I do have two ways of creating a filled circle via bresenham/midpoint algorithm.
But the second way looks far better than the first way.
I want to create a result like the second one, but with the way of the first
one. I want to do it with the first way because I need a correct formula for calculating distances which is this one at the moment:
function calcDistance (pos,pos2,range){
var x1 = pos.hasOwnProperty('x') ? pos.x : pos[0],
y1 = pos.hasOwnProperty('y') ? pos.y : pos[1],
x2 = pos2.hasOwnProperty('x') ? pos2.x : pos2[0],
y2 = pos2.hasOwnProperty('y') ? pos2.y : pos2[1];
return Math.pow((x1-x2),2) + Math.pow((y1-y2),2) - Math.pow(range, 2)
};
Here is the jsfiddle . The first approach was taken from wikipedia the second from here
Instead of drawing points when the distance is <= 0, draw points when the distance is <= radius*radius*zoom:
EDIT: applied a scaling factor of (8.0/radius)
function drawCircle(x0, y0, radius){
var range = radius*radius*zoom*(8.0/radius); // calculate the range once
for(var x = 0; x < imageWidth/zoom; x++){
for(var y = 0; y < imageHeight/zoom; y++){
if(calcDistance([x0,y0],[x*zoom,y*zoom],radius*zoom) <= range){
context.fillRect(x*zoom,y*zoom,zoom,zoom);
}
}
}
}
Related
I have a path in paper.js witch describes a letterform. I got Path by loading a font whith opentype.js's function path.toSVG(); than I load it to paper.js by .importSVG();
Now I do some manipulations with paper.js and then want it back as a downloadable font file. So my question is, is there an easy way to get it back from paper.js to opentype.js?
Edit:
Okay I am asuming there is no easy way. So i tried to convert the path manually with js:
for(var i=0; i<fragments.children.length; i++) {
var glyphName = fragments.children[i].name;
if (glyphName.indexOf('0x') > -1) {
var unicode = String.fromCharCode(parseInt(glyphName, 16));
glyphName = 'uni' + glyphName.charCodeAt(0);
} else {
var unicode = glyphName.charCodeAt(0);
}
var w = 0;
var glyphPath = new opentype.Path();
//Going through the array with the segments of the paper.js Path
for(var i2 = 0; i2 < fragments.children[i].segments.length; i2++) {
// handle In
var x1 = fragments.children[i].segments[i2].handleIn.x;
var y1 = fragments.children[i].segments[i2].handleIn.y;
// handle Out
var x2 = fragments.children[i].segments[i2].handleOut.x;
var y2 = fragments.children[i].segments[i2].handleOut.y;
// Point
var x = fragments.children[i].segments[i2].point.x;
var y = fragments.children[i].segments[i2].point.y;
if (i2 === 0) {
// if its the first segment use move to
glyphPath.moveTo(x, y);
} else if(x1==0 && y1==0 && x2 == 0 && y2 == 0) {
// if there is no curve use line to
glyphPath.lineTo(x, y);
} else {
// use curve if its a curve
glyphPath.curveTo(x1+x,y1+y, x2+x,y2+y, x,y,);
}
if(i2+1 == fragments.children[i].segments.length) {
glyphPath.close();
}
w = Math.max(w, x);
}
var glyph = new opentype.Glyph({
name: fragments.children[i].name,
unicode: unicode,
advanceWidth: (w + 1),
path: glyphPath
});
}
This gets me an opentype font file to download. However, if i open the font in a Font Viewer the whole Form is upside down and the handles are wrong. The positions of them seem right but somehow the wrong handles are in the position where another one should be...they seem to be switched. I can't figure out what I am missing..
This is how it should look
This is how it looks..
How the problem was solved:
As mentioned in the comment I saw that there were no straight lines even in fragments which should have straight lines. So i checked the coordinates and realised that there were straight lines (paths with handle x1/y2 and x2/y2 all on coordinate 0/0) if i just push them one ahead.
For example:
x y x1 y1 x2 y2
1: 148.29 92.125 0 0 -1.25 -3.5
2: 140 85 3.93 1.084 0 0
3: 139.99 74.16 0 0 12.95 2.02
4: 159.55 92.1 -1.238 -8.283 0 0
So i had to change the for loop to actually get the handles of the last point mixed with the ones from the actual point.
So in this example nr. 1 and nr. 3 would get x1: 0, y1: 0 // x2: 0, y2: 0
In my for loop i take x1/y1 from the last segment:
// handle In
var x1 = fragmentPathObj.segments[i2-1].handleOut.x * letterScale;
var y1 = fragmentPathObj.segments[i2-1].handleOut.y*-1 * letterScale;
// handle Out
var x2 = fragmentPathObj.segments[i2].handleIn.x * letterScale;
var y2 = fragmentPathObj.segments[i2].handleIn.y*-1 * letterScale;
If i do this i can check for straight lines with:
if(x1==0 && y1==0 && x2 == 0 && y2 == 0) {
glyphTempPath.lineTo(x, y);
}
and draw the curves when there are handles:
var lastX = fragmentPathObj.segments[i2-1].point.x * letterScale - letterPosCorrectionX;
var lastY = fragmentPathObj.segments[i2-1].point.y*-1 * letterScale - letterPosCorrectionY;
glyphTempPath.curveTo(x1+lastX, y1+lastY, x2+x, y2+y, x,y);
lastX/lastY: Since x1/y1 is coming from the last segment, i need to calculate the position for the handles also with the x/y of the last point.
letter Scale: is used for the scaling of the letter and is calculated by dividing the glyph's advanceWidth by the scaledAdvanceWith
y*-1 : is used to solve the upside down problem.
letterPosCorrectionX and letterPosCorrectionY; are corrections for the position (so they are moved to the correct position in the font.)
Maybe this can help someone save some time :)
OK. Based on the images, you've got at least 2 problems.
The first is that the Y co-ordinates have inverted.
importSVG probably handled that for you correctly going in, but you'll need to handle it coming back out.
That will mean iterating the glyphPath a second time and reversing the Y values. Looks like you are already tracking the max Y (or X?), and you'll need that. And you will probably also need an offset value.
The second problem (which is a guess) is that curves are being turned into lines.
I'm afraid I can't really advise on that, other than it probably means your curve detection is incorrect.
I would like to determine the proportion of a grid cell occupied by one (or more) circles. So, for example, the top left grid cell below would have a small value (~0.1) and the center grid cell (7,7) would have a value of 1, as it is entirely occupied by the circle.
At present I am doing this with canvas.context2d.getImageData, by sampling the cell's content to determine what is present. This works but is way too slow. This is this method:
var boxRadius = 6;
var boxSize = boxRadius * 2 + 1;
var cellWidth = gridWidth / boxSize;
var cellHeight = gridHeight / boxSize;
var scanInterval = 10;
var scanCount = 10;
for (var x = viewcenterpoint.x - (gridWidth / 2); x <= viewcenterpoint.x + (gridWidth / 2) -1; x += cellWidth) {
for (var y = viewcenterpoint.y - (gridHeight / 2) ; y <= viewcenterpoint.y + (gridHeight / 2) -1; y += cellHeight) {
var cellthreatlevel = 0.0;
for (var cellx = x; cellx < x + cellWidth; cellx += scanInterval){
for (var celly = y; celly < y + cellHeight; celly += scanInterval){
var pixeldata = context.getImageData(cellx, celly, 1, 1).data;
cellthreatlevel += ((pixeldata[0] + pixeldata[1] + pixeldata[2])/765 * -1) + 1;//255; //grey tone
scancount += 1;
}
}
cellthreatlevel = cellthreatlevel / scanCount; //mean
}
}
The getImageData call is the source of the problem - it is way too slow.
Given that I have an array of circles, each with their x, y and radius how can I calculate this? If possible I would like each value to be a decimal fraction (between 0 and 1).
The grid is static, but the circles may move within it. I would be happy to get a rough estimate for the value, it doesnt need to be 100% accurate.
You can use the Monte Carlo Method to get an approximate solution. It is a probability based method, in which you generate random samples in order to estimate some value. In this case, given the coordinates of the circle center, the circle radius and the boundaries of the grid cell, you can estimate the proportion of the grid cell occupied by the circle by generating K random samples (all contained inside the grid cell), and verify the proportion of the samples that are also inside the circle. The more samples you generate, the more accurate your result will be.
Remember: to verify if a given sample P is inside a circle with center C and radius R, all you have to do is check if the equation sqrt((Px-Cx)^2 + (Py-Cy)^2) <= R is true
You only need to call getImageData once, to obtain the entire canvas.
Once you have the image data you can access the bytes at offset 4 * (celly * width + cellx) to get the RGB(A) data.
This should be massively faster since it only makes one call to the graphics hardware instead of 10s of thousands.
Given an array of circles (x,y,r values), I want to place a new point, such that it has a fixed/known Y-coordinate (shown as the horizontal line), and is as close as possible to the center BUT not within any of the existing circles. In the example images, the point in red would be the result.
Circles have a known radius and Y-axis attribute, so easy to calculate the points where they intersect the horizontal line at the known Y value. Efficiency is important, I don't want to have to try a bunch of X coords and test them all against each item in the circles array. Is there a way to work out this optimal X coordinate mathematically? Any help greatly appreciated. By the way, I'm writing it in javascript using the Raphael.js library (because its the only one that supports IE8) - but this is more of a logic problem so the language doesn't really matter.
I'd approach your problem as follows:
Initialize a set of intervals S, sorted by the X coordinate of the interval, to the empty set
For each circle c, calculate the interval of intersection Ic of c with with the X axis. If c does not intersect, go on to the next circle. Otherwise, test whether Ic overlaps with any interval(s) in S (this is quick because S is sorted); if so, remove all intersecting intervals from S, collapse Ic and all removed intervals into a new interval I'c and add I'c to S. If there are no intersections, add Ic to S.
Check whether any interval in S includes the center (again, fast because S is sorted). If so, select the interval endpoint closest to the center; if not, select the center as the closest point.
Basically the equation of a circle is (x - cx)2 + (y - cy)2 = r2. Therefore you can easily find the intersection points between the circle and X axis by substituting y with 0. After that you just have a simple quadratic equation to solve: x2 - 2cxx + cx2 + cy2 - r2 = 0 . For it you have 3 possible outcomes:
No intersection - the determinant will be irrational number (NaN in JavaScript), ignore this result;
One intersection - both solutions match, use [value, value];
Two intersections - both solutions are different, use [value1, value2].
Sort the newly calculated intersection intervals, than try merge them where it is possible. However take in mind that in every program language there approximation, therefore you need to define delta value for your dot approximation and take it into consideration when merging the intervals.
When the intervals are merged you can generate your x coordinates by subtracting/adding the same delta value to the beginning/end of every interval. And lastly from all points, the one closest to zero is your answer.
Here is an example with O(n log n) complexity that is oriented rather towards readability. I've used 1*10-10 for delta :
var circles = [
{x:0, y:0, r:1},
{x:2.5, y:0, r:1},
{x:-1, y:0.5, r:1},
{x:2, y:-0.5, r:1},
{x:-2, y:0, r:1},
{x:10, y:10, r:1}
];
console.log(getClosestPoint(circles, 1e-10));
function getClosestPoint(circles, delta)
{
var intervals = [],
len = circles.length,
i, result;
for (i = 0; i < len; i++)
{
result = getXIntersection(circles[i])
if (result)
{
intervals.push(result);
}
}
intervals = intervals.sort(function(a, b){
return a.from - b.from;
});
if (intervals.length <= 0) return 0;
intervals = mergeIntervals(intervals, delta);
var points = getClosestPoints(intervals, delta);
points = points.sort(function(a, b){
return Math.abs(a) - Math.abs(b);
});
return points[0];
}
function getXIntersection(circle)
{
var d = Math.sqrt(circle.r * circle.r - circle.y * circle.y);
return isNaN(d) ? null : {from: circle.x - d, to: circle.x + d};
}
function mergeIntervals(intervals, delta)
{
var curr = intervals[0],
result = [],
len = intervals.length, i;
for (i = 1 ; i < len ; i++)
{
if (intervals[i].from <= curr.to + delta)
{
curr.to = Math.max(curr.to, intervals[i].to);
} else {
result.push(curr);
curr = intervals[i];
}
}
result.push(curr);
return result;
}
function getClosestPoints(intervals, delta)
{
var result = [],
len = intervals.length, i;
for (i = 0 ; i < len ; i++)
{
result.push( intervals[i].from - delta );
result.push( intervals[i].to + delta );
}
return result;
}
create the intersect_segments array (normalizing at x=0 y=0)
sort intersectsegments by upperlimit and remove those with upperlimit<0
initialize point1 = 0 and segment = 0
loop while point1 is inside intersectsegment[segment]
4.1. increment point1 by uppper limit of intersectsegment[segment]
4.2. increment segment
sort intersectsegments by lowerlimit and remove those with loerlimit>0
initialize point2 = 0 and segment = 0
loop while point2 is inside intersectsegments[segment]
7.1. decrement point2 by lower limit of segment
7.2. decrement segment
the point is minimum absolute value of p1 and p2
Derived from this: How to tackle diagonally stacked, rounded image background element hovers?
I made imagemap areas and transformed them for my case, but, now there is a problem with point in polygon hit detection.
It appears that only the bottom right quadrant is always correct, but, only if looking outside the ring - inside the detection might be still be incorrect. Other quadrants, outside the ring, occasionally report a positive hit where it should be false.
Fiddle: http://jsfiddle.net/psycketom/9J4dx/1/
The red lines are drawn from the polygon that's generated from data-map.
The blue line represents the polygon we're currently checking.
The point in polygon function comes from: https://github.com/substack/point-in-polygon
var pointInPolygon = function(point, vs)
{
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var x = point[0], y = point[1];
var inside = false;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i][0], yi = vs[i][1];
var xj = vs[j][0], yj = vs[j][1];
var intersect = ((yi > y) != (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}
return inside;
};
I cannot seem to understand what's the problem here.
Your mapToPolygon function doesn't convert the parsed points from string to number. Because of this, the pointInPolygon function ends up comparing the strings of the coordinates, not the actual coordinates. Using a parseInt on line 31 of the fiddle fixes the problem.
Create an off-screen canvas and use the context's .isPointInPath(x, y) function.
Loop through all of your polygons (in your example you would loop through them in reverse because you have smallest last. The smallest would be the highest level / greatest z-index).
On you get a hit (isPointInPath returns true) stop.
Something like...
var offcanvas = document.createElement("canvas");
...
var x = e.pageX - $ages.offset().left;
var y = e.pageY - $ages.offset().top;
revlayers.each(function() {
var $elm = $(this);
var poly = $elm.data("polygon");
var ctx = offcanvas.getContext("2d");
if(poly.length > 0) {
ctx.beginPath();
ctx.moveTo(poly[0][0], poly[0][1]);
for(var i=1; i<poly.length; i++) {
ctx.lineTo(poly[i][0], poly[i][1]);
}
if(ctx.isPointInPath(x, y)) {
hit.text($elm.attr("href"));
return false; // end the .each() loop
}
}
})
I am creating a new "whack-a-mole" style game where the children have to hit the correct numbers in accordance to the question. So far it is going really well, I have a timer, count the right and wrong answers and when the game is started I have a number of divs called "characters" that appear in the container randomly at set times.
The problem I am having is that because it is completely random, sometimes the "characters" appear overlapped with one another. Is there a way to organize them so that they appear in set places in the container and don't overlap when they appear.
Here I have the code that maps the divs to the container..
function randomFromTo(from, to) {
return Math.floor(Math.random() * (to - from + 1) + from);
}
function scramble() {
var children = $('#container').children();
var randomId = randomFromTo(1, children.length);
moveRandom('char' + randomId);
}
function moveRandom(id) {
var cPos = $('#container').offset();
var cHeight = $('#container').height();
var cWidth = $('#container').width();
var pad = parseInt($('#container').css('padding-top').replace('px', ''));
var bHeight = $('#' + id).height();
var bWidth = $('#' + id).width();
maxY = cPos.top + cHeight - bHeight - pad;
maxX = cPos.left + cWidth - bWidth - pad;
minY = cPos.top + pad;
minX = cPos.left + pad;
newY = randomFromTo(minY, maxY);
newX = randomFromTo(minX, maxX);
$('#' + id).css({
top: newY,
left: newX
}).fadeIn(100, function () {
setTimeout(function () {
$('#' + id).fadeOut(100);
window.cont++;
}, 1000);
});
I have a fiddle if it helps.. http://jsfiddle.net/pUwKb/8/
As #aug suggests, you should know where you cannot place things at draw-time, and only place them at valid positions. The easiest way to do this is to keep currently-occupied positions handy to check them against proposed locations.
I suggest something like
// locations of current divs; elements like {x: 10, y: 40}
var boxes = [];
// p point; b box top-left corner; w and h width and height
function inside(p, w, h, b) {
return (p.x >= b.x) && (p.y >= b.y) && (p.x < b.x + w) && (p.y < b.y + h);
}
// a and b box top-left corners; w and h width and height; m is margin
function overlaps(a, b, w, h, m) {
var corners = [a, {x:a.x+w, y:a.y}, {x:a.x, y:a.y+h}, {x:a.x+w, y:a.y+h}];
var bWithMargins = {x:b.x-m, y:b.y-m};
for (var i=0; i<corners.length; i++) {
if (inside(corners[i], bWithMargins, w+2*m, h+2*m) return true;
}
return false;
}
// when placing a new piece
var box;
while (box === undefined) {
box = createRandomPosition(); // returns something like {x: 15, y: 92}
for (var i=0; i<boxes.length; i++) {
if (overlaps(box, boxes[i], boxwidth, boxheight, margin)) {
box = undefined;
break;
}
}
}
boxes.push(box);
Warning: untested code, beware the typos.
The basic idea you will have to implement is that when a random coordinate is chosen, theoretically you SHOULD know the boundaries of what is not permissible and your program should know not to choose those places (whether you find an algorithm or way of simply disregarding those ranges or your program constantly checks to make sure that the number chosen isn't within the boundary is up to you. the latter is easier to implement but is a bad way of going about it simply because you are entirely relying on chance).
Let's say for example coordinate 50, 70 is selected. If the picture is 50x50 in size, the range of what is allowed would exclude not only the dimensions of the picture, but also 50px in all directions of the picture so that no overlap may occur.
Hope this helps. If I have time, I might try to code an example but I hope this answers the conceptual aspect of the question if that is what you were having trouble with.
Oh and btw forgot to say really great job on this program. It looks awesome :)
You can approach this problem in at least two ways (these two are popped up in my head).
How about to create a 2 dimensional grid segmentation based on the number of questions, the sizes of the question panel and an array holding the position of each question coordinates and then on each time frame to position randomly these panels on one of the allowed coordinates.
Note: read this article for further information: http://eloquentjavascript.net/chapter8.html
The second approach follow the same principle, but this time to check if the panel overlap the existing panel before you place it on the canvas.
var _grids;
var GRID_SIZE = 20 //a constant holding the panel size;
function createGrids() {
_grids = new Array();
for (var i = 0; i< stage.stageWidth / GRID_SIZE; i++) {
_grids[i] = new Array();
for (var j = 0; j< stage.stageHeight / GRID_SIZE; j++) {
_grids[i][j] = new Array();
}
}
}
Then on a separate function to create the collision check. I've created a gist for collision check in Actionscript, but you can use the same principle in Javascript too. I've created this gist for inspirational purposes.
Just use a random number which is based on the width of your board and then modulo with the height...
You get a cell which is where you can put the mole.
For the positions the x and y should never change as you have 9 spots lets say where the mole could pop up.
x x x
x x x
x x x
Each cell would be sized based on % rather then pixels and would allow re sizing the screen
1%3 = 1 (x)
3%3 = 0 (y)
Then no overlap is possible.
Once the mole is positioned it can be show or hidden or moved etc based on some extended logic if required.
If want to keep things your way and you just need a quick re-position algorithm... just set the NE to the SW if the X + width >= x of the character you want to check by setting the x = y+height of the item which overlaps. You could also enforce that logic in the drawing routine by caching the last x and ensuring the random number was not < last + width of the item.
newY = randomFromTo(minY, maxY);
newX = randomFromTo(minX, maxX); if(newX > lastX + characterWidth){ /*needful*/}
There could still however be overlap...
If you wanted to totally eliminate it you would need to keep track of state such as where each x was and then iterate that list to find a new position or position them first and then all them to move about randomly without intersecting which would would be able to control with just padding from that point.
Overall I think it would be easier to just keep X starting at 0 and then and then increment until you are at a X + character width > greater then the width of the board. Then just increase Y by character height and Set X = 0 or character width or some other offset.
newX = 0; newX += characterWidth; if(newX + chracterWidth > boardWidth) newX=0; newY+= characterHeight;
That results in no overlap and having nothing to iterate or keep track of additional to what you do now, the only downside is the pattern of the displayed characters being 'checker board style' or right next to each other (with possible random spacing in between horizontal and vertical placement e.g. you could adjust the padding randomly if you wanted too)
It's the whole random thing in the first place that adds the complexity.
AND I updated your fiddle to prove I eliminated the random and stopped the overlap :)
http://jsfiddle.net/pUwKb/51/