I have an Archimedean spiral determined by the parametric equations x = r t * cos(t) and y = r t * sin(t).
I need to place n points equidistantly along the spiral. The exact definition of equidistant doesn't matter too much - it only has to be approximate.
Using just r, t and n as parameters, how can I calculate the coordinates of each equidistant point?
You want to place points equidistantly corresponding to arc length. Arc length for Archimedean spiral (formula 4) is rather complex
s(t) = a/2 * (t * Sqrt(1 + t*t) + ln(t + Sqrt(1+t*t)))
and for exact positions one could use numerical methods, calculating t values for equidistant s1, s2, s3... arithmetical progression. It is possible though.
First approximation possible - calculate s(t) values for some sequence of t, then get intervals for needed s values and apply linear interpolation.
Second way - use Clackson scroll formula approximation, this approach looks very simple (perhaps inexact for small t values)
t = 2 * Pi * Sqrt(2 * s / a)
Checked: quite reliable result
Related
I am trying to figure out how to generate the transform necessary to take a set of coordinates for a rectangle-like polygon, given source and destination.
I am doing it in node using and I'm comfortable using the image manipulation libraries, I just can't find out the maths behind generating a transform with the information that I have.
You have source coordinates and destination coordinates after applying of perspective transformation matrix. That matrix contains 8 independent coefficients. Source and destination points form 8 pairs of corresponding coordinates (x1(src)=>x1'(dst) and so on).
This article of Paul Heckbert shows theory - how to build system of eight linear equations to calculate coefficients of perspective transformation matrix.
Antigrain library contains C++ implementation of this problem solution (in the file agg_trans_perspective.h). I'm sure that appropriate JS implementation does exist in the world.
After solving of eq. system you have coefficients A..H and can find transformation of any needed point (x,y)=>(x',y'):
x' = (A * x + B * y + C) / (G * x + H * y + 1.0)
y' = (D * x + E * y + F) / (G * x + H * y + 1.0)
I'm using this equation to calculate a series of points along a quadratic curve:
// Returns a point on a quadratic bezier curve with Robert Penner's optimization of the standard equation
result.x = sx + t * (2 * (1 - t) * (cx - sx) + t * (ex - sx));
result.y = sy + t * (2 * (1 - t) * (cy - sy) + t * (ey - sy));
Sadly the points are unevenly distributed, as you can see in the dashed-line rendering below. The points are denser in the middle of the curve, and are further spaced apart near the edges. How can I calculate a evenly distributed set of points along a quadratic bezier curve?
Please note that I'm using this for rendering a dashed line, so a slow solution in MATLAB or something will not do. I need a fast solution that will fit inside a renderer. This is not for research or a one-off calculation!
Edit: I'm not asking how to accomplish the above. The above is MY RENDERING! I already know how to estimate the length of a bezier, calculate the number of points, etc, etc. What I need is a better bezier point interpolation algorithm since the one I have calculates points unevenly distributed along the curve!
You want to generate equidistant (by arc length) subdivision of quadratic Bezier curves.
So you need subdivision procedure and function for calculation of curve length.
Find length of the whole curve (L), estimate desired number of segments (N), then generate subdivision points, adjusting t parameters to get Bezier segments with length about L/N
Example: you find L=100 and want N=4 segments. Get t=1/2, subdivide curve by two parts and get length of the first part. If length > 50, diminish t and subdivide curve again. Repeat (use binary search) until length value becomes near 50. Remember t value and do the same procedure to get segments with length=25 for the first and for the second halves of the curve.
This approach uses the THREE.js library, which is not in the OP's question, but may be useful if only to look at how they approach it:
var curve = new THREE.QuadraticBezierCurve(
new THREE.Vector2( -10, 0 ),
new THREE.Vector2( 20, 15 ),
new THREE.Vector2( 10, 0 )
);
var points = curve.getSpacedPoints(numPoints);
I want to get all the vertices from an ARC. I have all the data (for ex : start point, end point, start angle, end angle, radius) which will used to draw an arc but my need is I have to generate all the vertices from the arc data.
I have already tried with one or two algorithm but I failed to get the exact vertices from an arc data.
I used Bresenham's algorithm but I failed.
Right now I am using below code but its not working ..
double theta = 2 * 3.1415926 / 100;
double c = Math.cos(theta);
double s = Math.sin(theta);
double t;
double x = ((ArcTo) element).getRadius();//we start at angle = 0
double y = 0;
for(int ii = 0; ii < 100; ii++) {
coordinates.add(new Coordinate(x + element.getCenterPoint().getX(), y + element.getCenterPoint().getY()));//output vertex
//apply the rotation matrix
t = x;
x = c * x - s * y;
y = s * t + c * y;
}
Please help me. Thank you.
First some clarifications
I assume that by vertices you mean the pixels and ARC is standard 2D circular arc (not elliptic arc !!!) and your input data are:
int (x0,y0),(x1,y1) // star/end points on curve !!!
float a0,a1 // start end angles [rad]
int (xc,yc) // center of circle
int r // radius
Do not use Bresenham
because you would need to start from zero angle and compute all pixels until start point is hit. Then flip draw flag so you start filling the pixel from that point and stop on end point hit. Also you would need to handle the winding to match ARC direction.
You can use circle parametric equation
// just some arc data to test with
float r=25.0;
float a0= 45.0*M_PI/180.0;
float a1=270.0*M_PI/180.0;
int xc=100,x0=xc+floor(r*cos(a0)),x1=xc+floor(r*cos(a1));
int yc=100,y0=yc+floor(r*sin(a0)),y1=yc+floor(r*sin(a1));
// arc rasterize code
int x,y;
float a,da;
// here draw pixels x0,y0 and x1,y1 to avoid rounding holes ...
if (r) da=0.75/float(r); else da=0.1; // step slightly less then pixel to avoid holes
for (a=a0;;a+=da)
{
x=xc+int(floor(r*cos(a)));
y=yc+int(floor(r*sin(a)));
// here draw pixel x,y
if ((x==x1)&&(y==y1)) // stop if endpoint reach
if (fabs(a-a1)<da) // but ignore stop if not at end angle (full or empty circle arc)
break;
}
may be round instead of floor will have less pixel position error. If your endpoint does not match then this will loop infinitely. If you tweak a bit the end conditions you can avoid even that or recompute x1,y1 from a1 as I have ...
You can use equation (x-xc)^2+(y-yc)^2=r^2
you need to divide ARC to quadrants and handle each as separate arc looping through x or y and computing the other coordinate. Loop through coordinate that is changing more
so in blue areas loop y and in the red loop x. For example red area code can look like this:
int x,y;
for (x=_x0;;x++)
{
y=sqrt((r*r)-((x-xc)*(x-xc)));
// here draw pixel x,y
if (x==_x1) // stop if endpoint reach
break;
}
you need to compute (_x0,_y0),(_x1,_y1) start end points of cut part of ARC inside the quadrant and make _x0<=_x1.
The value for _x looped start/end point coordinate will be xc +/- sqrt(r) or x0 or x1
the value for _y looped start/end point coordinate will be yc +/- sqrt(r) or y0 or y1
The blue parts are done in analogically manner (just swap/replace x and y). This approach is a bit more complicated due to cutting but can be done solely on integers. sqrt can be speed up by LUT (limiting the max radius) and the ^2 can be also further optimized.
[Notes]
so if I recapitulate the parametric equation is the simplest to implement but slowest. Then is the sqrt approach which can be done as fast as Bresenham (and may be even faster with LUT) but need the code for cutting ARC to quadrants which need few ifs prior to rendering.
All codes are in C++ and can be further improved like avoiding some int/float conversions, pre-compute some values before loop, etc ...
The last goes the Bresenham but you need to change a few things inside and when you do not know what you are doing you can easily get lost. It also need to cut to octant's so the complexity of change is far bigger then sqrt approach
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.
I'm trying to come up with a flexible decaying score system for a game using quadratic curves. I could probably brute force my way through it but was wondering if anyone can help me come up with something flexible or maybe there are some ready made solutions out there already!
But basically I need the ability to generate the values of a,b & c in:
y = ax^2 + bx + c
from 3 points (which i know fall on a valid quadratic curve, but are dynamic based on configurable settings and maximum times to react to an event) for example: (-1100, 0), (200, 1), (1500, 0).
So I can then plugin in values for x to generate values of Y which will determine the score I give the user.
If I could get away with a fixed quadratic equation I would but the scoring is based on how much time a user has to react to a particular event (X Axis) the y axis points will always be between 0 and 1 with 0 being minimum score and 1 being maximum score!
Let me know if you need more info!
You can use Lagrange polynomial interpolation, the curve is given by
y(x) = y_1 * (x-x_2)*(x-x_3)/((x_1-x_2)*(x_1-x_3))
+ y_2 * (x-x_1)*(x-x_3)/((x_2-x_1)*(x_2-x_3))
+ y_3 * (x-x_1)*(x-x_2)/((x_3-x_1)*(x_3-x_2))
If you collect the coefficients, you obtain
a = y_1/((x_1-x_2)*(x_1-x_3)) + y_2/((x_2-x_1)*(x_2-x_3)) + y_3/((x_3-x_1)*(x_3-x_2))
b = -y_1*(x_2+x_3)/((x_1-x_2)*(x_1-x_3))
-y_2*(x_1+x_3)/((x_2-x_1)*(x_2-x_3))
-y_3*(x_1+x_2)/((x_3-x_1)*(x_3-x_2))
c = y_1*x_2*x_3/((x_1-x_2)*(x_1-x_3))
+ y_2*x_1*x_3/((x_2-x_1)*(x_2-x_3))
+ y_3*x_1*x_2/((x_3-x_1)*(x_3-x_2))
you can formulate it in a matrix form: aX=b
1 x1 x1^2
a= 1 x2 x2^2
1 x3 x3^2
y1
b= y2
y3
then solve by inverting the matrix a (can be done via gauss method pretty straight forward)
http://en.wikipedia.org/wiki/Gaussian_elimination
X = a^-1*b
and X in this case are the [c b a] coefficients your are looking for.