Generating random points in the map for a region? - javascript

I have to generate random point/marker in the map which should not outside of specific country.
For canvas, I found following example
http://jsfiddle.net/6cFfU/3/
var markerPositions = [[225,175], [75,275], [150,225], [400,125], [300,300]];
var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
for (var i=0; i<markerPositions.length; i++) {
// Create an SVG <use> element
var use = document.createElementNS(svgNS, "use");
// Point it at our pin marker (the circle)
use.setAttributeNS(xlinkNS, "href", "#pin");
// Set it's x and y
use.setAttribute("x", markerPositions[i][0]);
use.setAttribute("y", markerPositions[i][1]);
// Add it to the "markers" group
document.getElementById("markers").appendChild(use);
}
It adds marker but I have to generate random marker and check it should not be outside of the shape/region.
Is there any way to detect whether the random point is outside? As the above sample has simple shapes but map will have different corners/polygons?

First, you calculate the bounding box rectangle.
Then you generate random points within that rectangle.
x ==> rand(x_min,x_max)
y ==> rand (y_min, y_max)
Then you check if the point is in the polygon, and if yes add.
While not numMatchingPoints < numPointsMustHave ==> repeat
You can check if a point is in a non-overlapping n-Vertex-Polygon like this (C-Code):
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
This is called a ray-casting algorithm.
This algorithm ray-casts to the right.
In each iteration, it tests the test point against one of the polygon's edges.
The first if-statement succeeds if the point's y-coord is within the edge's scope.
The second condition checks whether the test point is to the left of the line
If both are true, then the line drawn rightwards from the test point crosses that edge.
By repeatedly inverting the value of c, the algorithm counts how many times the rightward line crosses the polygon. If it crosses an odd number of times, then the point is inside the polygon;
if it crosses an even number of times, the point is outside the polygon.
See also:
http://en.wikipedia.org/wiki/Point_in_polygon

Related

how to create a grapher below in processing

I want to create a graph with nodes and lines that connect node around the circumference only
I tried this; it didn't work
for (int i = 0; i < nodeX.length; i++) {
fill(0);
ellipse(nodeX[i], nodeY[i], 10, 10);
}
or a pass mark, there must be a display window of size (600, 360) containing a grid with the same number of columns and rows (10 in the video). Your program should work correctly with a different size and/or number of partitions.
You set a constant globally at the VERY TOP, as:
final int N_PARTITIONS = 10;
and use it (N_PARTITIONS) throughout the program. your program should work even if the marker changes the value of N_PARTITIONS to 5 or 8 or 15 or ... (obviously, when N_PARTITIONS changes to 15, there should be 15 rows and 15 columns)
When you click anywhere on the display window, circle of diameter 10 (henceforth called a node) should be displayed at that point. Nodes from previous clicks should stay on the screen and there should be lines that join each node with the next one (and the last is joined to the first node). There should be no other lines besides these lines (and the grid lines of course).
There should be nodes drawn at the three points and lines from (200, 400) to (300, 300); (300, 300) to (60, 100); and (60, 100) to (200, 400).
From how you desribed the expected output, it seems as if the grid lines and the nodes connected by lines are unrelated. Therefore, you have two tasks to accomplish:
Drawing a grid with N_PARTITIONS rows and column lines, and
Drawing and connecting circles of diameter 10 through a mouse-click.
The former is relatively easy. Given
final int N_PARTITIONS = 10;
we need 10 lines across the screen and 10 lines down the screen.
Within void setup(), use size(600, 360); to set the size of the canvas to 600x360 pixels.
Let's handle drawing lines across the screen first. We will use a for loop to accomplish this.
void draw() {
int distVertLine = width / N_PARTITIONS; // This variable defines the distance between each subsequent vertical line.
for(int i = distVertLine / 2; i < width; i += distVertLine) {
line(i, 0, i, height); // Draw a line at x=i starting at the top of the canvas (y=0) and going to the bottom (y=height)
}
}
Above, we initialize a distVertLine variable to define the horizontal distance between each vertical line. Its value is width / N_PARTITIONS because we are splitting up the width of the canvas into a given amount of partitions.
In the for loop, i is initialized as distVertLine / 2 so that the grid lines are in the center.
Similarly, we can do this with the horizontal lines:
int distHorizLine = height / N_PARTITIONS; // This variable defines the distance between each subsequent vertical line.
for(int i = distHorizLine / 2; i < width; i += distHorizLine) {
line(0, i, width, i); // Draw a line at y=i starting at the left of the canvas (x=0) and going to the right (x=width)
}
Now for the nodes and lines. A circle in Processing is given by circle(x, y, extent) (check out the docs here).
When the mouse is pressed, the method void mousePressed() is called. Upon each press, we wish to record the x and y values in an array:
ArrayList nodeX = new ArrayList(); // ArrayLists are nice to use because they're expandable, unlike a Processing array.
ArrayList nodeY = new ArrayList(); // ArrayLists are nice to use because they're expandable, unlike a Processing array.
void mouseClicked() {
nodeX.add(mouseX); // Adds the x-position of the mouse pointer to the nodeX list.
nodeY.add(mouseY); // Adds the y-position of the mouse pointer to the nodeY list.
}
In void draw(), set up a for loop that draws circles at the coordinates in both lists:
stroke(0); // Set the circle's outline as black.
for(int i = 0; i < nodeX.size(); i++) {
float xPos = (int)nodeX.get(i); // Grab the ith x-position from the list.
float yPos = (int)nodeY.get(i); // Grab the ith y-position from the list.
circle(xPos, yPos, 10); // Draw a circle of diameter 10 at (xPos, yPos).
}
(Note, within the first line of void draw() I added
background(255); // Set the background color to white
stroke(125); // Set the stroke color as gray.
to make it easier to see the circles).
Last, we need to connect each circle with a line.
stroke(0, 0, 255); // Make the connecting lines blue.
for(int i = 0; i < nodeX.size() - 1; i++) {
float xPosA = (int)nodeX.get(i); // Grab the ith x-position from the list.
float yPosA = (int)nodeY.get(i); // Grab the ith y-position from the list.
float xPosB = (int)nodeX.get(i+1); // Grab the next x-position from the list.
float yPosB = (int)nodeY.get(i+1); // Grab the next y-position from the list.
line(xPosA, yPosA, xPosB, yPosB);
}
// And draw the connecting line.
if(nodeX.size() > 0) { // The code in this block will crash unless this condition is added to handle an empty list.
int size = nodeX.size() - 1; // Get the index of the last item in nodeX/nodeY.
float xPosA = (int)nodeX.get(0); // Grab the first x-position from the list.
float yPosA = (int)nodeY.get(0); // Grab the first y-position from the list.
float xPosB = (int)nodeX.get(size); // Grab the last x-position from the list.
float yPosB = (int)nodeY.get(size); // Grab the last y-position from the list.
line(xPosA, yPosA, xPosB, yPosB);
}

How to check if a mouse is in many (120) different regions in HTML5 canvas efficiently?

I have a polar graph (see image) with 120 different points. I want to make it so if the user clicks or hovers on one of the points, the coordinate of that point is displayed. I have an array called pointCoordinates that stores each canvas coordinate of each points like this:
[[x1, y1], [x2, y2] ... [x120, y120]]
This is how I am capturing mouse coordinates (which I might later change to click):
document.onmousemove = function(e) {
var x = e.clientX;
var y = e.clientY;
}
I was originally planning to use a formula to check if the mouse is in a certain region (using the distance formula) or simplifying it all into a circle. Either way, this will require me to have 120 different if statements to check for this. I feel like this is inefficient and probably slow. Are there other methods for doing this?
Edit:
To provide more information, these points will NOT be draggable. I am planning to display something like a tooltip near the point that was clicked where the polar coordinates of the point will be shown.
Edit 2:
After using the code posted below and drawing a rectangle in the "clickable" spot on the map, I get this image. I do not want the click detection to be perfect, but this is pretty far off after pi/3. Any ideas how to fix this? I used this code to generate the black spots:
for(var x = 0; x < WIDTH*2/3; x++){
for(var y = 0; y < HEIGHT; y++){
var mp = realToPolar(x, y);//converts canvas x and y into polar
if(checkRadialDistance(mp[0], mp[1])){ //returns true if in bounds
ctx.fillRect(x, y, 1, 1);
}
}
}
Playing around with the constants still generates the same pattern, just of different thicknesses. checkRadialDistance is just the renamed checkr function that inside calls checkrt.
JSBIN Keep in mind, width of screen has to be greater than height for this to work properly.
The image generated by mt-rt. I later made a minor edit, so that whole circle is covered when theta = 0.
EDIT: My (accepted) answer was bad. This corrects it:
This assumes r to be 1 to 5. Convert mouse cartesian mx,my to polar mr,mt. First check if mr is close to 1 of the 5 radii. Function checkr does that. If it is close, then check if mt is close to 1 of the 24 thetas. Function checkt does that. A complication is that the atan2 function is not continuous at pi radians which is where points are at, so make the discontinuity at -pi/24 radians where there are no points.
A "close" value is pi/24 since the arc distance between two adjacent points at r=1 will be pi/12.
var del = 1*Math.PI/24*.7; // for example
function xy2rt(xy) { // to polar cordinates
var rt = [];
rt.push(Math.sqrt(xy[0]*xy[0]+xy[1]*xy[1])); // r
var zatan = Math.atan2(xy[1], xy[0]);
// make the discontinuity at -pi/24
if (zatan < -Math.PI/24) zatan += 2*Math.PI;
rt.push(zatan); // theta
return rt;
}
function checkr() { // check radial distance
for (var pr=1; pr<=5; pr+=1) { // 5 radii
if (Math.abs(mr-pr) < del) { checkt(pr); break; }
}
}
function checkt(pr) { // check theta
var pt;
for (var ipt=0; ipt<24; ipt+=1) { // 24 thetas
pt = ipt / 24 * 2 * Math.PI;
if (Math.abs(mt-pt) < del/pr) {
// is close -- do whatever
break;
}
}
}
My problem was when checking the arc distance, I was using mr and pr whereas only pr should be used. The OP found my error by processing every pixel on the canvas and found there was a problem. I also processed every pixel and this image shows the routines to be correct now. The black is where the routines determine that the pixel is close to one of the 120 points.
EDIT: Faster processing
There are a lot of Math.* functions being executed. Although I haven't timed anything, I think this has to be much faster.
1) The x,y coordintates of the 120 points are stored in arrays.
2) Instead of getting polar mr, mt, pr, and pt, use vector processing.
Here is the derivation of arcd, the arc distance using vectors.
sint = sin(theta) = (M cross P)/mr/pr (cross product Mouse X Point)
cost = cos(theta) = (M dot P)/mr/pr (dot product Mouse . Point)
sint will be used to get arc distance, but sint goes to zero at theta=+-pi as well as theta=0, so:
mdotp will be used to determine if theta is near zero and not +-pi
arcd = pr*theta
arcd = pr*sin(theta) (good approximation for small theta)
arcd = pr*abs(M cross P)/mr/mp (from above)
if ardd < del, check if mdotp > 0.
Here are the load-xy-arrays and the new checkr and checkt routines.
apx=[], apy=[]; // the saved x,y of the 120 points
function loadapxapy() { // load arrays of px, py
var itheta, theta
for (var pr=1; pr<=5; pr+=1) { // 2-dimension arrays
apx[pr] = []; apy[pr] = []; // 5 arrays, 1 for each pr
for (itheta=0; itheta<24; itheta+=1) { // 24 x's and y's
theta = Math.PI*itheta/12;
apx[pr][itheta] = pr*Math.cos(theta);
apy[pr][itheta] = pr*Math.sin(theta);
}
}
}
function checkr() { // check radial distance
var mr = Math.sqrt(mx*mx+my*my); // mouse r
for (var pr=1; pr<=5; pr+=1) { // check 1 to 5
if (Math.abs(mr-pr) < del) { // mouser - pointr
checkt(mr, pr); // if close, check thetas
}
}
}
function checkt(mr, pr) { // check thetas
var px, py, sint, mdotp, arcd;
for (var itheta=0; itheta<24; itheta+=1) { // check 24
px = apx[pr][itheta]; // get saved x
py = apy[pr][itheta]; // and y
// This arcd is derived from vector processing
// At least this doesn't use the accursed "atan"!
sint = Math.abs(mx*py-my*px)/mr/pr; // sine
arcd = pr*sint; // arc distance
if (arcd<del) { // arc distance check
mdotp = (mx*px+my*py); // final check
if (mdotp > 0) { // to see if theta is near zero and not +-pi
setpixelxy([mx, my]); // or whatever..
}
}
}
}

Wave animation for a character converted to svg

I have problems animating part of the character 'W' that is converted to svg. This character is styled out a bit, it has like small flag at the left side (the part that I want to animate).
Right now when the animation is going, that flag is stretched vertically at the top of page. It should stay at the same position where it was, also the top and bottom line of the flag should be in parallel( like in image sample below).
Code sample:
var pathData = "M253.477,175...";
var path = new paper.Path(pathData);
var flags = {
collection:[]
}
var Flag = function(){
var model = {
startIndex:0, // start point in path.segments array
middleIndex:0,// middle point in path.segments array
endIndex:0, // end point in path.segments array
height:20, // the wave animation height
segments:[] // only flag segments
}
return model;
};
var initializeFlag = function(){
var segments = path.segments;
//...
for(var i = flag.startIndex; i <= flag.endIndex; i++ ){
flag.segments.push(segments[i]);
}
flags.collection.push(flag); //adds to flags collection
};
var doWaveAnimation = function(segment, counter, height, top, e){
var sinus = Math.sin(e.time * 3 + counter);
segment.point.y = sinus * height + top;
};
var animateFlags = function(e){
var collection = flags.collection;
for(var i = 0; i < collection.length; i++){
var flag = collection[i];
for(var s = flag.startIndex, n = flag.endIndex -1;
s < flag.middleIndex && n > flag.middleIndex -2;
s++, n--){
//top line
doWaveAnimation(flag.segments[n], n, flag.height, 180, e);
//bottom line
doWaveAnimation(flag.segments[s], s, flag.height, 200, e);
}
}
};
//...
Full code sample -> flag animation
To get greater understanding what kind of "wave" animation I want, here is also one example(at the bottom of page) -> http://paperjs.org/
EDIT
Looks like the main reason why this animation is not working properly is that both lines are not positioned horizontally but diagonally..
There's a few things you can do to make this easier:
Make the 'flag' segments linear instead curved
Create your flags so that they are N segments long and are at the end of a path. Then you can refer to them by segment index instead of matching coordinates
Store each moving segment's initial coordinates in a property
Move each segment by a ratio of it's distance from the letter form over the entire length of the flag.
Here's an example sketch
Try moving the X-coordinate of each segment with a different phase to create a more complex motion.
Well obviously a sine wave is centred on zero. So you are going to have to keep a record of all your flag Y coordinates when you loop through finding your start and end indices. Then add those Ys back in when you are doing your animation.

Calculate minimum value not between set of ranges

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

Finding point n% away from the centre of a semicircle in Javascript?

I'm sorry to say that Math really isn't my strong suit. Normally I can get by, but this has got me totally stumped.
I'm trying to code up a quiz results screen in HTML/CSS/Javascript.
On my interface, I have a semicircle (the right hemisphere of a target).
I have a range of 'scores' (integers out of 100 - so 50, 80, 90 etc.).
I need to plot these points on the semicircle to be n% away from the centre, where n is the value of each score - the higher the score, the closer to the centre of the target the point will appear.
I know how wide my semicircle is, and have already handled the conversion of the % values so that the higher ones appear closer to the centre while the lower ones appear further out.
What I can't wrap my head around is plotting these points on a line that travels out from the centre point (x = 0, y = target height/2) of the target at a random angle (so the points don't overlap).
Any suggestions are gratefully received!
Do you have an example of what you want this to look like? It sounds like you want to divide up the circle into N slices where N is the number of points you need to display, then plot the points along each of those radii. So you might have something like:
Edit: code was rotating about the origin, not the circle specified
var scores = [];
//...
//assume scores is an array of distances from the center of the circle
var points = [];
var interval = 2 * Math.PI / N;
var angle;
for (var i = 0; i < N; i++) {
angle = interval * i;
//assume (cx, cy) are the coordinates of the center of your circle
points.push({
x: scores[i] * Math.cos(angle) + cx,
y: scores[i] * Math.sin(angle) + cy
});
}
Then you can plot points however you see fit.
After much headscratching, I managed to arrive at this solution (with the help of a colleague who's much, much better at this kind of thing than me):
(arr_result is an array containing IDs and scores - scores are percentages of 100)
for (var i = 0; i < arr_result.length; i++){
var angle = angleArray[i]; // this is an array of angles (randomised) - points around the edge of the semicircle
var radius = 150; // width of the semicircle
var deadZone = 25 // to make matters complicated, the circle has a 'dead zone' in the centre which we want to discount
var maxScore = 100
var score = parseInt(arr_result[i]['score'], 10)
var alpha = angle * Math.PI
var distance = (maxScore-score)/maxScore*(radius-deadZone) + deadZone
var x = distance * Math.sin(alpha)
var y = radius + distance * Math.cos(alpha)
$('#marker_' + arr_result[i]['id'], templateCode).css({ // target a specific marker and move it using jQuery
'left' : pointX,
'top': pointY
});
}
I've omitted the code for generating the array of angles and randomising that array - that's only needed for presentational purposes so the markers don't overlap.
I also do some weird things with the co-ordinates before I move the markers (again, this has been omitted) as I want the point to be at the bottom-centre of the marker rather than the top-left.

Categories