If I have a line, with the points x,y,endx and endy how can I detect if another point is on the line? A simple equation, or example functions in JavaScript or pseudocode will be most helpful.
EDIT:
This is for a game I'm working on, I'm trying to detect if a laser is colliding with an object, Here is the sample http://jefnull.com/references/lasers/ The file that will be most descriptive is http://jefnull.com/references/lasers/lasers.js
Since my previous answer said how to determine if a point was on the line, and the real question appears to be "how can I tell if the point is near the line segment", I'm adding a new answer.
Here's the trick: first find the distance from your obstacle to each of the two endpoints of your line segment. These two distances don't uniquely determine the location of the obstacle, but they do uniquely determine a triangle with three specific side lengths, and then we can immediately use a bunch of geometry.
I fiddled with the colors a little. Anyway, I mentioned in a comment above that you should use the point-line distance formula to find the distance between the obstacle and the line. But that won't actually work. The reason is that is is the point-line distance. So, for both examples below, the formula will calculate the bold distance H in the picture.
That isn't right!!
So instead, here is the pseudocode for finding the distance from your obstacle to the line segment formed by the laser:
Find the distance from my point to the line segment!
if the angle at (x,y) is obtuse
return A
else if the angle at (endx,endy) is obtuse
return B
else
return H
Here is the math you can use to implement the above pseudocode:
To see if the angle at (x,y) is obtuse, find whether B^2 > A^2 + C^2. If so, the angle is obtuse.
To see if the angle at (endx, endy) is obtuse, find whether A^2 > B^2 + C^2. If so, the angle is obtuse.
To calculate H, use two different methods for finding the area of the triangle -- the usual base*height/2 and Heron's Formula.
This means you should:
set s = (A+B+C)/2
The area of the triangle is C*H/2
The area of the triangle is also sqrt(s*(s-A)*(s-B)*(s-C))
So H = 2/C * sqrt(s*(s-A)*(s-B)*(s-C)).
The end result is something like:
if B^2 > A^2 + C^2
return A
else if A^2 > B^2 + C^2
return B
else
s = (A+B+C)/2
return 2/C * sqrt(s*(s-A)*(s-B)*(s-C))
I think that should give you enough to accomplish what you are actually setting out to do. Good luck, and don't give up!
First of all, the answer provided by Razack was the most mathematically sound answer, though highly theoretical. If you are upvoting this answer, please consider upvoting his answer too.
I have implemented his methods in the following useful javascript functions. Have a look in particular at function calcIsInsideThickLineSegment(...). Use as you please.
//Returns {.x, .y}, a projected point perpendicular on the (infinite) line.
function calcNearestPointOnLine(line1, line2, pnt) {
var L2 = ( ((line2.x - line1.x) * (line2.x - line1.x)) + ((line2.y - line1.y) * (line2.y - line1.y)) );
if(L2 == 0) return false;
var r = ( ((pnt.x - line1.x) * (line2.x - line1.x)) + ((pnt.y - line1.y) * (line2.y - line1.y)) ) / L2;
return {
x: line1.x + (r * (line2.x - line1.x)),
y: line1.y + (r * (line2.y - line1.y))
};
}
//Returns float, the shortest distance to the (infinite) line.
function calcDistancePointToLine(line1, line2, pnt) {
var L2 = ( ((line2.x - line1.x) * (line2.x - line1.x)) + ((line2.y - line1.y) * (line2.y - line1.y)) );
if(L2 == 0) return false;
var s = (((line1.y - pnt.y) * (line2.x - line1.x)) - ((line1.x - pnt.x) * (line2.y - line1.y))) / L2;
return Math.abs(s) * Math.sqrt(L2);
}
//Returns bool, whether the projected point is actually inside the (finite) line segment.
function calcIsInsideLineSegment(line1, line2, pnt) {
var L2 = ( ((line2.x - line1.x) * (line2.x - line1.x)) + ((line2.y - line1.y) * (line2.y - line1.y)) );
if(L2 == 0) return false;
var r = ( ((pnt.x - line1.x) * (line2.x - line1.x)) + ((pnt.y - line1.y) * (line2.y - line1.y)) ) / L2;
return (0 <= r) && (r <= 1);
}
//The most useful function. Returns bool true, if the mouse point is actually inside the (finite) line, given a line thickness from the theoretical line away. It also assumes that the line end points are circular, not square.
function calcIsInsideThickLineSegment(line1, line2, pnt, lineThickness) {
var L2 = ( ((line2.x - line1.x) * (line2.x - line1.x)) + ((line2.y - line1.y) * (line2.y - line1.y)) );
if(L2 == 0) return false;
var r = ( ((pnt.x - line1.x) * (line2.x - line1.x)) + ((pnt.y - line1.y) * (line2.y - line1.y)) ) / L2;
//Assume line thickness is circular
if(r < 0) {
//Outside line1
return (Math.sqrt(( (line1.x - pnt.x) * (line1.x - pnt.x) ) + ( (line1.y - pnt.y) * (line1.y - pnt.y) )) <= lineThickness);
} else if((0 <= r) && (r <= 1)) {
//On the line segment
var s = (((line1.y - pnt.y) * (line2.x - line1.x)) - ((line1.x - pnt.x) * (line2.y - line1.y))) / L2;
return (Math.abs(s) * Math.sqrt(L2) <= lineThickness);
} else {
//Outside line2
return (Math.sqrt(( (line2.x - pnt.x) * (line2.x - pnt.x) ) + ( (line2.y - pnt.y) * (line2.y - pnt.y) )) <= lineThickness);
}
}
To see some of this code in action using a nice SVG, see this fiddle which I used to debug:
https://jsfiddle.net/c06zdxtL/2/
You want to check whether the slopes are the same between the pairs of points. But you should be careful not to ever divide by zero, so check by checking the cross-multiplied version of the equations.
More explicitly, if your points are A = (Ax, Ay), B = (Bx, By), C = (Cx, Cy), then you would like to check that
(Cy - Ay) / (Cx - Ax) = (By - Ay) / (Bx - Ax)
But instead you should check that
(Cy - Ay) * (Bx - Ax) = (By - Ay) * (Cx - Ax).
function isOnLine(x, y, endx, endy, px, py) {
var f = function(somex) { return (endy - y) / (endx - x) * (somex - x) + y; };
return Math.abs(f(px) - py) < 1e-6 // tolerance, rounding errors
&& px >= x && px <= endx; // are they also on this segment?
}
x, y, endx and endy are the points that define the line, using which you can build the equation of that line. Then, fill in px and see if f(px) = py (in fact checking for small enough due to rounding errors). Lastly, check whether the line segment is defined on the interval x ... endx.
Let the point be C (Cx,Cy) and the line be AB (Ax,Ay) to (Bx,By).
Let P be the point of perpendicular projection of C on AB. The parameter
r, which indicates P's position along AB, is computed by the dot product
of AC and AB divided by the square of the length of AB:
(1) AC dot AB
r = ---------
||AB||^2
r has the following meaning:
r=0 P = A
r=1 P = B
r<0 P is on the backward extension of AB
r>1 P is on the forward extension of AB
0<r<1 P is interior to AB
The length of a line segment in d dimensions, AB is computed by:
L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 + ... + (Bd-Ad)^2)
so in 2D:
L = sqrt( (Bx-Ax)^2 + (By-Ay)^2 )
and the dot product of two vectors in d dimensions, U dot V is computed:
D = (Ux * Vx) + (Uy * Vy) + ... + (Ud * Vd)
so in 2D:
D = (Ux * Vx) + (Uy * Vy)
So (1) expands to:
(Cx-Ax)(Bx-Ax) + (Cy-Ay)(By-Ay)
r = -------------------------------
L^2
The point P can then be found:
Px = Ax + r(Bx-Ax)
Py = Ay + r(By-Ay)
And the distance from A to P = r*L.
Use another parameter s to indicate the location along PC, with the
following meaning:
s<0 C is left of AB
s>0 C is right of AB
s=0 C is on AB
Compute s as follows:
(Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay)
s = -----------------------------
L^2
Then the distance from C to P = |s|*L.
function is_point_on_segment (startPoint, checkPoint, endPoint) {
return ((endPoint.y - startPoint.y) * (checkPoint.x - startPoint.x)).toFixed(0) === ((checkPoint.y - startPoint.y) * (endPoint.x - startPoint.x)).toFixed(0) &&
((startPoint.x > checkPoint.x && checkPoint.x > endPoint.x) || (startPoint.x < checkPoint.x && checkPoint.x < endPoint.x)) &&
((startPoint.y >= checkPoint.y && checkPoint.y >= endPoint.y) || (startPoint.y <= checkPoint.y && checkPoint.y <= endPoint.y));
}
Test:
var startPoint = {x:30,y:30};
var checkPoint = {x:40,y:40};
var endPoint = {x:50,y:50};
console.log(is_point_on_segment(startPoint ,checkPoint ,endPoint ));
According to the straight line equation y = mx + b where m is slope, x is value of point at x axis and b is y intercept (the point where line intercept y axis).
m(slope) = endy - y/endx - x;
e.g. if a line starts at (0, 0) and ends (4,2) then m = 4-0/2-0 = 2;
b (y intercept) = 0 ;
now for example you are provided with a point(1,2) to see if it lies on line. okay calculate your y coordinate with the help of x coordinate. i.e.
y = mx+b
y= 2(1) + 0; // here x is the x coordinate of the given point
y = 2; which is exactly the same as the y- coordinate of your given point so we can conclude this lies on the line. If the point had value (2,2) according to equation it will evaluate to y= 4 which is not equal to the y-coordinate of the point you were given so it doesn't lie on the line.
function isOnLine(initial_x, initial_y, endx, endy, pointx, pointy, tolerate) {
var slope = (endy-initial_y)/(endx-initial_x);
var y = slope * pointx + initial_y;
if((y <= pointy+tolerate && y >= pointy-tolerate) && (pointx >= initial_x && pointx <= endx)) {
return true;
}
return false;
}
Here is my implementation of isOnLine
function isOnLine(a, b, p, tolerance) {
var dy = a.y - b.y;
var dx = a.x - b.x;
if(dy == 0) { //horizontal line
if(p.y == a.y) {
if(a.x > b.x) {
if(p.x <= a.x && p.x >= b.x)
return true;
}
else {
if(p.x >= a.x && p.x <= b.x)
return true;
}
}
}
else if(dx == 0) { //vertical line
if(p.x == a.x) {
if(a.y > b.y) {
if(p.y <= a.y && p.y >= b.y)
return true;
}
else {
if(p.y >= a.y && p.y <= b.y)
return true;
}
}
}
else { //slope line
var s = dy/dx;
var py = s * p.x;
if(py <= p.y + tolerance && py >= p.y - tolerance) {
if(a.x > b.x) {
if(p.x <= a.x && p.x >= b.x)
return true;
}
else {
if(p.x >= a.x && p.x <= b.x)
return true;
}
}
}
return false;
}
Related
I'm trying to create an algorithm that detects discontinuities (like vertical asymptotes) within functions between an interval for the purpose of plotting graphs without these discontinuous connecting lines. Also, I only want to evaluate within the interval so bracketing methods like bisection seems good for that.
EDIT
https://en.wikipedia.org/wiki/Classification_of_discontinuities
I realize now there are a few different kinds of discontinuities. I'm mostly interested in jump discontinuities for graphical purposes.
I'm using a bisection method as I've noticed that discontinuities occur where the slope tends to infinity or becomes vertical, so why not narrow in on those sections where the slope keeps increasing and getting steeper and steeper. The point where the slope is a vertical line, that's where the discontinuity exists.
Approach
Currently, my approach is as follows. If you subdivide the interval using a midpoint into 2 sections and compare which section has the steepest slope, then that section with the steepest slope becomes the new subinterval for the next evaluation.
Termination
This repeats until it converges by either slope becoming undefined (reaching infinity) or the left side or the right side of the interval equaling the middle (I think this is because the floating-point decimal runs out of precision and cannot divide any further)
(1.5707963267948966 + 1.5707963267948968) * .5 = 1.5707963267948966
Example
function - floor(x)
(blue = start leftX and rightX, purple = midpoint, green = 2nd iteration midpoints points, red = slope lines per iteration)
As you can see from the image, each bisection narrows into the discontinuity and the slope keeps getting steeper until it becomes a vertical line at the discontinuity point at x=1.
To my surprise this approach seems to work for step functions like floor(x) and tan(x), but it's not that great for 1/x as it takes too many iterations (I'm thinking of creating a hybrid method where I use either illinois or ridders method on the inverse of 1/x as it those tend to find the root in just one iteration).
Javascript Code
/* Math function to test on */
function fn(x) {
//return (Math.pow(Math.tan(x), 3));
return 1/x;
//return Math.floor(x);
//return x*((x-1-0.001)/(x-1));
}
function slope(x1, y1, x2, y2) {
return (y2 - y1) / (x2 - x1);
}
function findDiscontinuity(leftX, rightX, fn) {
while (true) {
let leftY = fn(leftX);
let rightY = fn(rightX);
let middleX = (leftX + rightX) / 2;
let middleY = fn(middleX);
let leftSlope = Math.abs(slope(leftX, leftY, middleX, middleY));
let rightSlope = Math.abs(slope(middleX, middleY, rightX, rightY));
if (!isFinite(leftSlope) || !isFinite(rightSlope)) return middleX;
if (middleX === leftX || middleX === rightX) return middleX;
if (leftSlope > rightSlope) {
rightX = middleX;
rightY = middleY;
} else {
leftX = middleX;
leftY = middleY;
}
}
}
Problem 1 - Improving detection
For the function x*((x-1-0.001)/(x-1)), the current algorithm has a hard time detecting the discontinuity at x=1 unless I make the interval really small. As an alternative, I could also add most subdivisions but I think the real problem is using slopes as they trick the algorithm into choosing the incorrect subinterval (as demonstrated in the image below), so this approach is not robust enough. Maybe there are some statistical methods that can help determine a more probable interval to select. Maybe something like least squares for measuring the differences and maybe applying weights or biases!
But I don't want the calculations to get too heavy and 5 points of evaluation are the max I would go with per iteration.
EDIT
After looking at problem 1 again, where it selects the wrong (left-hand side) subinterval. I noticed that the only difference between the subintervals was the green midpoint distance from their slope line. So taking inspiration from linear regression, I get the squared distance from the slope line to the midpoints [a, fa] and [b, fb] corresponding to their (left/right) subintervals. And which subinterval has the greatest change/deviation is the one chosen for further subdivision, that is, the greater of the two residuals.
This further improvement resolves problem 1. Although, it now takes around 593 iterations to find the discontinuity for 1/x. So I've created a hybrid function that uses ridders method to find the roots quicker for some functions and then fallback to this new approach. I have given up on slopes as they don't provide enough accurate information.
Problem 2 - Jump Threshold
I'm not sure how to incorporate a jump threshold and what to use for that calculation, don't think slopes would help.
Also, if the line thickness for the graph is 2px and 2 lines of a step function were on top of each other then you wouldn't be able to see the gap of 2px between those lines. So the minimum jump gap would be calculated as such
jumpThreshold = height / (ymax-ymin) = cartesian distance per pixel
minJumpGap = jumpThreshold * 2
But I don't know where to go from here! And once again, maybe there are statistical methods that can help to determine the change in function so that the algorithm can terminate quickly if there's no indication of a discontinuity.
Overall, any help or advice in improving what I got already would be much appreciated!
EDIT
As the above images explains, the more divergent the midpoints are the greater the need for more subdivisions for further inspection for that subinterval. While, if the points mostly follow a straight line trend where the midpoints barely deviate then should exit early. So now it makes sense to use the jumpThreshold in this context.
Maybe there's further analysis that could be done like measuring the curvature of the points in the interval to see whether to terminate early and further optimize this method. Zig zag points or sudden dips would be the most promising. And maybe after a certain number of intervals, keep widening the jumpThreshold as for a discontinuity you expect the residual distance to rapidly increase towards infinity!
Updated code
let ymax = 5, ymin = -5; /* just for example */
let height = 500; /* 500px screen height */
let jumpThreshold = Math.pow(.5 * (ymax - ymin) / height, 2); /* fraction(half) of a pixel! */
/* Math function to test on */
function fn(x) {
//return (Math.pow(Math.tan(x), 3));
return 1 / x;
//return Math.floor(x);
//return x * ((x - 1 - 0.001) / (x - 1));
//return x*x;
}
function findDiscontinuity(leftX, rightX, jumpThreshold, fn) {
/* try 5 interations of ridders method */
/* usually this approach can find the exact reciprocal root of a discountinuity
* in 1 iteration for functions like 1/x compared to the bisection method below */
let iterations = 5;
let root = inverseRidderMethod(leftX, rightX, iterations, fn);
let limit = fn(root);
if (Math.abs(limit) > 1e+16) {
if (root >= leftX && root <= rightX) return root;
return NaN;
}
root = discontinuityBisection(leftX, rightX, jumpThreshold, fn);
return root;
}
function discontinuityBisection(leftX, rightX, jumpThreshold, fn) {
while (true) {
let leftY = fn(leftX);
let rightY = fn(rightX);
let middleX = (leftX + rightX) * .5;
let middleY = fn(middleX);
let a = (leftX + middleX) * .5;
let fa = fn(a);
let b = (middleX + rightX) * .5;
let fb = fn(b);
let leftResidual = Math.pow(fa - (leftY + middleY) * .5, 2);
let rightResidual = Math.pow(fb - (middleY + rightY) * .5, 2);
/* if both subinterval midpoints (fa,fb) barely deviate from their slope lines
* i.e. they're under the jumpThreshold, then return NaN,
* indicating no discountinuity with the current threshold,
* both subintervals are mostly straight */
if (leftResidual < jumpThreshold && rightResidual < jumpThreshold) return NaN;
if (!isFinite(fa) || a === leftX || a === middleX) return a;
if (!isFinite(fb) || b === middleX || b === rightX) return b;
if (leftResidual > rightResidual) {
/* left hand-side subinterval */
rightX = middleX;
middleX = a;
} else {
/* right hand-side subinterval */
leftX = middleX;
middleX = b;
}
}
}
function inverseRidderMethod(min, max, iterations, fn) {
/* Modified version of RiddersSolver from Apache Commons Math
* http://commons.apache.org/
* https://www.apache.org/licenses/LICENSE-2.0.txt
*/
let x1 = min;
let y1 = 1 / fn(x1);
let x2 = max;
let y2 = 1 / fn(x2);
// check for zeros before verifying bracketing
if (y1 == 0) {
return min;
}
if (y2 == 0) {
return max;
}
let functionValueAccuracy = 1e-55;
let relativeAccuracy = 1e-16;
let oldx = Number.POSITIVE_INFINITY;
let i = 0;
while (i < iterations) {
// calculate the new root approximation
let x3 = 0.5 * (x1 + x2);
let y3 = 1 / fn(x3);
if (!isFinite(y3)) return NaN;
if (Math.abs(y3) <= functionValueAccuracy) {
return x3;
}
let delta = 1 - (y1 * y2) / (y3 * y3); // delta > 1 due to bracketing
let correction = (signum(y2) * signum(y3)) * (x3 - x1) / Math.sqrt(delta);
let x = x3 - correction; // correction != 0
if (!isFinite(x)) return NaN;
let y = 1 / fn(x);
// check for convergence
let tolerance = Math.max(relativeAccuracy * Math.abs(x), 1e-16);
if (Math.abs(x - oldx) <= tolerance) {
return x;
}
if (Math.abs(y) <= functionValueAccuracy) {
return x;
}
// prepare the new interval for the next iteration
// Ridders' method guarantees x1 < x < x2
if (correction > 0.0) { // x1 < x < x3
if (signum(y1) + signum(y) == 0.0) {
x2 = x;
y2 = y;
} else {
x1 = x;
x2 = x3;
y1 = y;
y2 = y3;
}
} else { // x3 < x < x2
if (signum(y2) + signum(y) == 0.0) {
x1 = x;
y1 = y;
} else {
x1 = x3;
x2 = x;
y1 = y3;
y2 = y;
}
}
oldx = x;
}
}
function signum(a) {
return (a < 0.0) ? -1.0 : ((a > 0.0) ? 1.0 : a);
}
/* TEST */
console.log(findDiscontinuity(.5, .6, jumpThreshold, fn));
Python Code
I don't mind if the solution is provided in Javascript or Python
import math
def fn(x):
try:
# return (math.pow(math.tan(x), 3))
# return 1 / x
# return math.floor(x)
return x * ((x - 1 - 0.001) / (x - 1))
except ZeroDivisionError:
return float('Inf')
def slope(x1, y1, x2, y2):
try:
return (y2 - y1) / (x2 - x1)
except ZeroDivisionError:
return float('Inf')
def find_discontinuity(leftX, rightX, fn):
while True:
leftY = fn(leftX)
rightY = fn(rightX)
middleX = (leftX + rightX) / 2
middleY = fn(middleX)
leftSlope = abs(slope(leftX, leftY, middleX, middleY))
rightSlope = abs(slope(middleX, middleY, rightX, rightY))
if not math.isfinite(leftSlope) or not math.isfinite(rightSlope):
return middleX
if middleX == leftX or middleX == rightX:
return middleX
if leftSlope > rightSlope:
rightX = middleX
rightY = middleY
else:
leftX = middleX
leftY = middleY
I am drawing on shape on canvas(using HTML5) and need to determine(in javascript, jquery) if drawn Line Points (x,y cordinates) connect or intersect each other and form some shape(like triangle, square etc.). The purpose of this is to fill these shapes with colors, just like painting tools.
Have read few articles like http://www.geeksforgeeks.org/articulation-points-or-cut-vertices-in-a-graph/ but did not clearly understand if this can be used as solution for this problem.
Please suggest and algorithm to determine, if line points are connected to each other and form shapes.
Thanks,
Here are some links which has some required guidance for what I was looking out. Sharing the details here can be helpful for others looking for similar info.
https://gist.github.com/lengstrom/8499382
extract from jsfiddle
http://jsfiddle.net/justin_c_rounds/Gd2S2/light/
function checkLineIntersection(line1StartX, line1StartY, line1EndX, line1EndY, line2StartX, line2StartY, line2EndX, line2EndY) {
// if the lines intersect, the result contains the x and y of the intersection (treating the lines as infinite) and booleans for whether line segment 1 or line segment 2 contain the point
var denominator, a, b, numerator1, numerator2, result = {
x: null,
y: null,
onLine1: false,
onLine2: false
};
denominator = ((line2EndY - line2StartY) * (line1EndX - line1StartX)) - ((line2EndX - line2StartX) * (line1EndY - line1StartY));
if (denominator == 0) {
return result;
}
a = line1StartY - line2StartY;
b = line1StartX - line2StartX;
numerator1 = ((line2EndX - line2StartX) * a) - ((line2EndY - line2StartY) * b);
numerator2 = ((line1EndX - line1StartX) * a) - ((line1EndY - line1StartY) * b);
a = numerator1 / denominator;
b = numerator2 / denominator;
// if we cast these lines infinitely in both directions, they intersect here:
result.x = line1StartX + (a * (line1EndX - line1StartX));
result.y = line1StartY + (a * (line1EndY - line1StartY));
/*
// it is worth noting that this should be the same as:
x = line2StartX + (b * (line2EndX - line2StartX));
y = line2StartX + (b * (line2EndY - line2StartY));
*/
// if line1 is a segment and line2 is infinite, they intersect if:
if (a > 0 && a < 1) {
result.onLine1 = true;
}
// if line2 is a segment and line1 is infinite, they intersect if:
if (b > 0 && b < 1) {
result.onLine2 = true;
}
// if line1 and line2 are segments, they intersect if both of the above are true
return result;
};
Test if two lines intersect - JavaScript function
I have an matrix like this, so I hope you can get the circle outline:
EDIT 1: What about the outline? The outline doesn't includes spaces (so every y-value gets minimum 2 x-values)
EDIT 2: What is a circle? Searching for an more ore less "exact circles" like the example below! (nearly same radius at every point)
00000000000000000000000000000000
00000000000001111111100000000000
00000000000100000000010000000000
00000000010000000000000100000000
00000000100000000000000010000000
00000000100000000000000010000000
00000001000000000000000001000000
00000010000000000000000000100000
00000010000000000000000000100000
00000010000000000000000000100000
00000100000000000000000000100000
00000100000000000000000000100000
00000100000000000000000000100000
00000100000000000000000000100000
00000100000000000000000000100000
00000010000000000000000000100000
00000010000000000000000000100000
00000010000000000000000001000000
00000001000000000000000010000000
00000000100000000000000010000000
00000000100000000000000100000000
00000000010000000000001000000000
00000000000111111111100000000000
00000000000000000000000000000000
00000000000000000000000000000000
and I also have an array like this including all positions of the outline:
var coordinates = [
[13,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],
[11,2],[21,2],
[9,3],[23,3],
[8,4],[24,4],
[8,5],[24,5],
[7,6],[25,6],
[6,7],[26,7],
[6,8],[26,8],
[6,9],[26,9],
[5,10],[26,10],
[5,11],[26,11],
[5,12],[26,12],
[5,13],[26,13],
[5,14],[26,14],
[6,15],[26,15],
[6,16],[26,16],
[6,17],[25,17],
[7,18],[24,18],
[8,19],[24,19],
[8,20],[23,20],
[9,21],[22,21],
[11,22],[12,22],[13,22],[14,22],[15,22],[16,22],[17,22],[18,22],[19,22],[20,22]]
What is a good way to check if the coordinates are matching to be a circle?
My first idea was using some code like this but tbh I'm sure there is a way more efficient & working way:
var circle = [[13,1],[14,1],[15,1],[16,1],[17,1],[18,1],[19,1],[20,1],[11,2],[21,2],[9,3],[23,3],[8,4],[24,4],[8,5],[24,5],[7,6],[25,6],[6,7],[26,7],[6,8],[26,8],[6,9],[26,9],[5,10],[26,10],[5,11],[26,11],[5,12],[26,12],[5,13],[26,13],[5,14],[26,14],[6,15],[26,15],[6,16],[26,16],[6,17],[25,17],[7,18],[24,18],[8,19],[24,19],[8,20],[23,20],[9,21],[22,21],[11,22],[12,22],[13,22],[14,22],[15,22],[16,22],[17,22],[18,22],[19,22],[20,22]]
var no_circle= [[13,1],[14,1],[25,4]]
Array.prototype.is_circle = function() {
var min = {
'x': Infinity,
'y': Infinity
};
var max = {
'x': 0,
'y': 0
};
var center = {
'x': 0,
'y': 0
};
var radius;
this.forEach(function(a) {
a[0] = a[0]
a[1] = a[1]
if (a[0] > max.x) max.x = a[0];
if (a[0] < min.x) min.x = a[0];
if (a[1] > max.y) max.y = a[1];
if (a[1] < min.y) min.y = a[1];
});
center.x = (max.x + min.x) / 2;
center.y = (max.y + min.y) / 2;
radius = []
radius[0] = max.x - center.x
radius[1] = center.x - min.x
radius[2] = center.y - min.y
radius[3] = max.y - center.y
r = (radius[0] + radius[1] + radius[2] + radius[3]) / 4;
if ((radius[0] > r-1 && radius[0] < r+1) && (radius[1] > r-1 && radius[1] < r+1) && (radius[2] > r-1 && radius[2] < r+1) && (radius[3] > r-1 && radius[3] < r+1)) return true;
return false
}
var result1 = circle.is_circle();
console.log(result1)
var result2 = no_circle.is_circle();
console.log(result2)
Your algorithm seems to check only four most distant points on X and Y axis. I guess that if you provide points that represent square shape it will also pass is_circle test.
I propose that you do two-stage test with some extra roundness margin called e. Walk over whole set of points and remember x_min, y_min, x_max and y_max. Then make check if difference between delta of X and delta of Y is in the error margin i.e. abs((x_max-x_min) - (y_max-y_min)) <= e. That checks squarness of shape so that it can be circle, not oval. If that test passes then calculate center point c at (x_c, y_c) = (x_min+(x_max-x_min)/2, y_min+(y_max-y_min)/2) and for each point calculate if radius (distance from any point to center c) is within error margin e. To save on expensive calculations check if squared radius of each point is within error margin i.e. if abs((x-x_c)^2 + (y-y_c)^2 - r^2) <= e, where r^2 is computed for center c and first point on the list.
i am just a beginner in Threejs so please excuse if its a noobie question. but i haven't worked with particles.
How do i put points(particles) inside a custom geometry of a text geometry?
What i want to achieve is instance points inside a geometry or text then explode it to the world position. if someone direct me to the path, would be much helpful.
i know there's an example https://threejs.org/examples/#webgl_points_dynamic
but i cant understand whats happening in the render loop.
This is not the ultimate solution, but just a starting point.
You can set points from any type of geometry (usual geometry or buffer geometry).
Let's imagine that you have a THREE.TextGeometry(), then you can set points from it as:
textGeo = new THREE.TextGeometry("ABC", {
font: font,
size: 2,
height: 0.25,
curveSegments: 1,
bevelEnabled: false
});
textGeo.computeBoundingBox();
textGeo.computeVertexNormals();
textGeo.center();
fillWithPoints(textGeo, 1000); // fill our text geometry with 1000 random points
textGeo.vertices.forEach(function(vertex){
vertex.startPoint = vertex.clone(); // remember the starting position of a vertex
vertex.direction = vertex.clone().normalize(); // set direction
})
textPoints = new THREE.Points(textGeo, new THREE.PointsMaterial({color: 0x00ff00, size: 0.1})); // all you need is to have a geometry and THREE.PointsMaterial()
scene.add(textPoints);
To determine if a random point is inside our geometry, we can do the trick with projection of all the faces of our text geometry into 2D (x,y) and check if the point (with its x,y coordinates) is inside of one of projected triangles (faces):
function isPointInside(point, geometry) {
var retVal = false;
for (var i = 0; i < geometry.faces.length; i++) { //loop through faces
face = geometry.faces[i];
a = geometry.vertices[face.a];
b = geometry.vertices[face.b];
c = geometry.vertices[face.c];
if (ptInTriangle(point, a, b, c)) {
var retVal = true;
break; // exit the loop if the point is in a projected triangle
}
}
return retVal;
}
where
function ptInTriangle(p, p0, p1, p2) {
// credits: http://jsfiddle.net/PerroAZUL/zdaY8/1/
var A = 1/2 * (-p1.y * p2.x + p0.y * (-p1.x + p2.x) + p0.x * (p1.y - p2.y) + p1.x * p2.y);
var sign = A < 0 ? -1 : 1;
var s = (p0.y * p2.x - p0.x * p2.y + (p2.y - p0.y) * p.x + (p0.x - p2.x) * p.y) * sign;
var t = (p0.x * p1.y - p0.y * p1.x + (p0.y - p1.y) * p.x + (p1.x - p0.x) * p.y) * sign;
return s > 0 && t > 0 && (s + t) < 2 * A * sign;
}
and then in the animation loop we'll use the stuff of a vertex (startPoint and direction):
textGeo.vertices.forEach(function(vertex){
vertex.copy(vertex.startPoint).addScaledVector(vertex.direction, 5 + Math.sin(Date.now() * 0.001) * 5);
});
textGeo.verticesNeedUpdate = true; // this is the most important thing, you have to set it to true after each rendering
jsfiddle example
Given a point on a line and that line's slope how would one determine if the line, extending in each direction infinitely, intersects with a line segment (x1,y1), (x2,y2) and, if so, the point at which the intersection occurs?
I found this, but I'm unsure if it's helpful here.
If someone wants to help me understand "rays", that's alright with me.
http://www.realtimerendering.com/intersections.html
I'm sorry that I'm an idiot.
Arbitrary point on the first line has parametric equation
dx = Cos(slope)
dy = Sin(Slope)
x = x0 + t * dx (1)
y = y0 + t * dy
Line containing the second segment
dxx = x2 - x1
dyy = y2 - y1
x = x1 + u * dxx (2)
y = y1 + u * dyy
Intersection exists if linear system
x0 + t * dx = x1 + u * dxx (3)
y0 + t * dy = y1 + u * dyy
has solution for unknowns t and u
and u lies in range [0..1]
Intersection point could be calculated with substitution of u found in the equation pair (2)
Please don't ask me to explain how exactly this is working, I've just extrapolated/rewritten it from some ancient code I've had laying around. (Actionscript 1)
some functions to build the objects for this example:
function point(x, y){
return {x, y}
}
function line(x0, y0, x1, y1){
return {
start: point(x0, y0),
end: point(x1, y1)
}
}
function ray(x, y, vx, vy){
return {
start: point(x, y),
vector: point(vx, vy)
}
}
function ray2(x, y, angle){
var rad = angle * Math.PI / 180;
return ray(x, y, Math.cos(rad), Math.sin(rad));
}
the intersection-code:
//returns the difference vector between two points (pointB - pointA)
function delta(a, b){ return point( b.x - a.x, b.y - a.y ) }
//kind of a 2D-version of the cross-product
function cp(a, b){ return a.y * b.x - a.x * b.y }
function intersection(a, b){
var d21 = a.vector || delta(a.start, a.end),
d43 = b.vector || delta(b.start, b.end),
d13 = delta(b.start, a.start),
d = cp(d43, d21);
//rays are paralell, no intersection possible
if(!d) return null;
//if(!d) return { a, b, position: null, hitsA: false, hitsB: false };
var u = cp(d13, d21) / d,
v = cp(d13, d43) / d;
return {
a, b,
//position of the intersection
position: point(
a.start.x + d21.x * v,
a.start.y + d21.y * v
),
//is position on lineA?
hitsA: v >= 0 && v <= 1,
//is position on lineB?
hitsB: u >= 0 && u <= 1,
timeTillIntersection: v,
};
}
and an example:
var a = line(0, 0, 50, 50);
var b = line(0, 50, 50, 0); //lines are crossing
console.log(intersection(a, b));
var c = line(100, 50, 150, 0); //lines are not crossing
console.log(intersection(a, c));
var d = line(100, -1000, 100, 1000); //intersection is only on d, not on a
console.log(intersection(a, d));
var e = ray(100, 50, -1, -1); //paralell to a
console.log(intersection(a, e));
returns information about the intersection point, and wether it is on the passed lines/rays. Doesn't care wether you pass lines or rays.
about timeTillIntersection: if the first argument/ray represents a ball/bullet/whatever with current position and motion-vector, and the second argument represents a wall or so, then v, aka timeTillIntersection determines how much time it takes till this ball intersects/hits the wall (at the current conditions) in the same unit as used for the velocity of the ball. So you basically get some information for free.
What you search is the dot product. A line can be represented as a vector.
When you have 2 lines they will intersect at some point. Except in the case when they are parallel.
Parallel vectors a,b (both normalized) have a dot product of 1 (dot(a,b) = 1).
If you have the starting and end point of line i, then you can also construct the vector i easily.