How to detect polygon edge when implementing a plane sweep algorithm? - javascript

I am working in javascript and trying to implement an algorithm that triangulates a polygon (something convex or concave but assumed to be a simple polygon, not self crossing and without holes).
I have found a solution on the web but it is only in pseudocode and I am trying to implement it. ( source of the algorithm : https://sites.cs.ucsb.edu/~suri/cs235/Triangulation.pdf page 19).
The first step is to partition the polygon into trapezoids with a plane sweep algorithm, which is described as "At each vertex, extend vertical line until it hits a polygon edge. Each face of this decomposition is a trapezoid; which may degenerate into a triangle."
Considering that my polygon is set of coordinates, how do I know that my line is crossing the polygon ?
I was thinking that I could do something like
take the horinzontal x coordinate of my vertex as x1
take each pair of sucessive vertices (x2, y2, x3, y3)
test if they are on each side of the line (x2 < x1 and x1 < x3 or the opposite)
if yes calculate the equation for the line between them
use this equation to calculate y1
but it sounds like overkill since it has a O(n²) complexity and the pseudocode announces O(n*log(n)). And I can't stop when I have found a solution since my polygone might "double back" and there would be multiple points of crossing.
Is there another way to find the points where the line crosses the polygon?
(Or a simple way to triangulate the polygon in the first place)

There might be easier ways to solve it, but this might be one approach:
Make use of the Bentley Ottman algorithm for finding intersections in a set of line segments. Since your polygon is not self-intersecting, you can just add your sweep segments and find its intersections in O((n + k) log n) time, where k is the number of intersections. As long as the total number of intersections is O(n) (which will be the case if your polygon is not too crazy shaped), the resulting time complexity should be O(n log n).

Related

Resolve colliding rotated rectangles by moving along vector

I have a javascript program that places rectangles one at a time along walls in a room in counter-clockwise order. I use the coordinates of the rectangles corners for collision detection. It skips the placement of a rectangle if it intersects with another rectangle in the room.
(the room can be any shape so collisions can happen on any side of the rectangle)
However, I want to move the rectangle along the wall until it is no longer colliding instead of skipping it. My current idea is to move the rectangle 1 coordinate at a time in a loop until it no longer intersects, but it does not seem like a good solution for performance.
Is there a way to mathematically know how far in a given direction the rotated rectangle needs to be moved in order to no longer intersect another rotated rectangle?
Consider using of Separating Axis Theorem.
Two boxes (polygons in wide sense) don't intersect, if there exists some axis parallel to some box side, separating boxes, so the lie at distinct sides of this axis.
I've got arbitrary paper with good picture. At pages 16-17 we can see two boxes and some formulas to check for intersection.
You can express T - difference vector between box center as
T.x = pb.x - pa.x + t * dx
T.y = pb.y - pa.y + t * dy
where t is parameter (0 in the starting moment), and (dx, dy) is direction vector for B box moving (along the slanted wall at your picture).
Substituting T components into formula (note I changed > sign to =) we can get equation for parameter t corresponding to moment when Ax becomes separating axis.
| T • Ax | = WA + | ( WB*Bx ) • Ax | + |( HB*By ) • Ax |
If we make the same for other axes (Ay, Bx, By), we get 4 values of t, and the smallest positive one corresponds to minimal diplacement needed to separate the boxes.
Note that right part contains only constant values (for given setup), and we can easily calculate it using abs function, but left part contains variable, so we have to consider two cases (negative and positive dot product T • Ax) to find solution(s). Two possible solutions correspond to "left and right" box separation (anyway, you need smaller positive result)

Cubic bezier function for finding progress given time and two control points

I am trying to find a JS algorithm to find the ypos of a cubic bezier given the xpos. the first and last control points will be (0,0) and (1,1) and it should throw an error if any of the inputted control points' xpos is less than 0 or greater than 1, just like in CSS. the function will be called like
cubicBezier(p1x, p1y, p2x, p2y, time)
I spent like half an hjour searching it on google but nothing seemed to work.. I only fornd a buch of mathematical formulas when I was looking for an algorithm. Even when I turned my eyes to stackoverflow I couldn't find anything other than complex mathematical formulas and stuff in c++
the top left point is going to be p1 and the other point is p2.

Cheaply determine which of 2 Bezier Curves is longer

In my situation I need to compare the length of 2 bezier curves. I do not need to compute the actual length of either curve. I merely want to cheaply compare which of the 2 is longer. My assumptions for this method are as followed:
Both Bezier curves to compare are same dimension(number of control points)
The dimension of the curves could be any number greater than 2
I need to output which of the 2 curves is longer (either if equal)
My original thought, was to just add the lengths of control points ie:
distance(p0, p1) + distance(p1, p2) + distance(p2, p3)...
And It seems to work decently for lower order bezier curves. However I sure that this would not scale well in higher order curves.
I ended with a solution that adds the distance between each control point projected on the curve(basically take number of control points / index of point and using that value as T), and seems to work on some higher dimension curves.
I can't imagine I am the first person to want to do this, So to reiterate does anyone know of the right way to do this?

How to divide an ellipse to equal segments?

This calculates vertex coordinates on ellipse:
function calculateEllipse(a, b, angle)
{
var alpha = angle * (Math.PI / 180) ;
var sinalpha = Math.sin(alpha);
var cosalpha = Math.cos(alpha);
var X = a * cosalpha - b * sinalpha;
var Y = a * cosalpha + b * sinalpha;
}
But how can I calculate the "angle" to get equal or roughly equal circumference segments?
So from what Jozi's said in the OP's comments, what's needed isn't how to subdivide an ellipse into equal segments (which would require a whole bunch of horrible integrals), it's to construct an ellipse from line segments of roughly equal length.
There are a whole pile of ways to do that, but I think the best suited for the OP's purposes would be the concentric circle method, listed on the page as 'the draftman's method'. If you don't mind installing the Mathematica player, there's a neat lil' app here which illustrates it interactively.
The problem with those methods is that the segment lengths are only roughly equal at low eccentricities. If you're dealing in extreme eccentricities, things get a lot more complicated. The simplest solution I can think of is to linearly approximate the length of a line segment within each quadrant, and then solve for the positions of the endpoints in that quadrant exactly.
In detail: this is an ellipse quadrant with parameters a = 5, b = 1:
And this is a plot of the length of the arc subtended by an infinitesimal change in the angle, at each angle:
The x axis is the angle, in radians, and the y axis is the length of the arc that would be subtended by a change in angle of 1 radian. The formula, which can be derived using the equations in the Wikipedia article I just linked, is y = Sqrt(a^2 Sin^2(x) + b^2 Cos^2(x)). The important thing to note though is that the integral of this function - the area under this curve - is the length of the arc in the whole quadrant.
Now, we can approximate it by a straight line:
which has gradient m = (a-b) / (Pi/2) and y intercept c = b. Using simple geometry, we can deduce that the area under the red curve is A = (a+b)*Pi/4.
Using this knowledge, and the knowledge that the area under the curve is the total length of the curve, the problem of constructing an approximation to the ellipse reduces to finding say a midpoint-rule quadrature (other quadratures would work too, but this is the simplest) of the red line such that each rectangle has equal area.
Converting that sentence to an equation, and representing the position of a rectangle in a quadrature by it's left hand boundary x and its width w, we get that:
(v*m)*w^2 + (m*x+c)*w - A/k == 0
where k is the number of pieces we want to use to approximate the quadrant, and v is a weighting function I'll come to shortly. This can be used to construct the quadrature by first setting x0 = 0 and solving for w0, which is then used to set x1 = w0 and solve for w1. Then set x2 = w1, etc etc until you've got all k left-hand boundary points. The k+1th boundary point is obviously Pi/2.
The weighting function v effectively represents where the rectangle crosses the red line. A constant v = 0.5 is equivalent to it crossing in the middle, and gets you this with 10 points:
but you can play around with it to see what better balances the points. Ideally it should stay in the range [0, 1] and the sum of the values you use should be k/2.
If you want an even better approximation without messing around with weighting functions, you could try least-squares fitting a line rather than just fitting it to the endpoints, or you could try fitting a cubic polynomial to the blue curve instead of a linear polynomial. It'll entail solving quartics but if you've a maths package on hand that shouldn't be a problem.
Too long for a comment, so I suppose this has to be an answer ...
Here's a mathematically simple approach to forming a first order approximation. Pick one quadrant. You can generate the data for the other quadrants by reflection in the X and Y axis. Calculate (x,y) for the angle = 0 degrees, 1 degree, ... 90 degrees. Now you want the little lengths joining consecutive points. If (x_n, y_n) are the coordinates at angle = n, then Pythagoras tells us the distance D between points (x_n, y_n) and (x_n+1, y_n+1) is D = sqrt((x_n+1 - x_n)^2 + (y_n+1 - y_n)^2). Use this formula to produce a table of cumulative distances around the ellipse for angles from 0 degrees to 90 degrees. This is the inverse of the function you seek. Of course, you don't have to pick a stepsize of 1 degree; you could use any angle which exactly divides 90 degrees.
If you want to find the angle which corresponds to a perimeter step size of x, find the largest angle n in your table producing a partial perimeter less than or equal to x. The partial perimeter of angle n+1 will be larger than x. Use linear interpolation to find the fractional angle which corresponds to x.
All we are doing is approximating the ellipse with straight line segments and using them instead of the original curve; its a first order approximation. You could do somewhat better by using Simpson's rule or similar instead of linear interpolation.
Yes, you have to calculate the table in advance. But once you have the table, the calculations are easy. If you don't need too much accuracy, this is pretty simple both mathematically and coding-wise.

Accounting for vertical slope

I'm not a programmer primarily, so this might be a simple answer.
I'm working on a script in Illustrator where you select three points and then it does stuff. First it makes a triangle. Then, it recreates two of the line segments in the triangle and rotates them 90 degrees. Then, I find the intersect of those points so that I can make a circumcircle.
I'm actually moving along quite well, but the only problem I don't know how to solve at the moment is when two points that comprise the triangle have the same y-coordinates. When I make the perpendicular line, that line is vertical and therefore has no slope. It throws an error.
How do I account for a vertical slope with JavaScript? I was thinking about something along the lines of, "if the slope is NaN, then set the slope value to 9999999" or something like that, but this seemed a bit crude. Any better options?
You could normalise your gradient in the range -1 to 1. Anything larger than 1, or a NaN, is clamped at 1. The same goes for negative numbers, but with -1.

Categories

Resources