Calculate a specific curve with specific rotation, c# - c#

I am trying to code for a game I am working on a specific curve with a specific rotation. I am not a great mathematician... At all... Tried searching for solutions for a few hours, but I'm affraid I do not find any solution.
So, a small picture to illustrate first:
This is an eighth of a circle, radius of 9, beggining is (0,0)
The end is now at about 6.364, -2.636. But I need this same curve, with a 45° direction at the end, but ending at aexactly 6.0,-3.0.
Could any of you show me how to do this? I need to be able to calculate precisly any point on this curve & its exact length. I would suppose using some kind of eliptical math could be a solution? I admit my math class are reaaaly far now and have now good clue for now...
Thank for any possible help

I think I found a quadratic curve which sastisfies your requirement:
f(x) = -1/12 x^2 + 9
Copy the following into https://www.desmos.com/calculator to see it:
-\frac{1}{12}x^2+9
f'(x) would be -1/6x, so when x=6, the derivative would be -1, which corresponds to a -45° inclination. There are probably infinite curves that satisfy your requirement but if my calculus isn't too rusty this is one of them.
I tried to fit an ellipse with foci starting at y=6 here and starting at y=9 here to your points but the slope doesn't look like 45°.
Also starting at any height k, here doesn't seem to work.

I don't think you've fully understood the question I asked in the comments about the "inclination" angle. So I will give a general case solution, where you have an explicit tangent vector for the end of the curve. (You can calculate this using the inclination angle; if we clarify what you mean by it then I will be happy to edit with a formula to calculate the tangent vector if necessary)
Let's draw a diagram of how the setup can look:
(Not 100% accurate)
A and B are your fixed points. T is the unit tangent vector. r and C are the radius and center of the arc we need to calculate.
The angle θ is given by the angle between BA and T minus π/2 radians (90 degrees). We can calculate it using the dot product:
The (signed) distance from the center of AB to C is given by:
Note that this is negative for the case on the right, and positive for the left. The radius is given by:
(You can simplify by substituting and using a cosine addition rule, but I prefer to keep things in terms of variables in the diagram). To obtain the point C, we need the perpendicular vector to AB (call it n):
Now that we have the radius and center of the circular arc, we still need to determine which direction we are moving in, i.e. whether we are moving clockwise or anti-clockwise when going from A to B. This is a simple test, using the cross-product:
If this is negative, then T is as in the diagram, and we need to move clockwise, and vice versa. The length of the arc l, and the angular displacement γ when we move by a distance x along the arc:
Nearly there! Just one more step - we need to work out how to rotate the point A by angle γ around point C, to get the point we want (call it D):
(Adapted from this Wikipedia page)
Now for some code, in case the above was confusing (it probably was!):
public Vector2 getPointOnArc(Vector2 A, Vector2 B, Vector2 T, double x)
{
// calculate preliminaries
Vector2 BA = B - A;
double d = BA.Length();
double theta = Math.Acos(Vector2.DotProduct(BA, T) / d) - Math.PI * 0.5;
// calculate radius
double r = d / (2.0 * Math.Cos(theta));
// calculate center
Vector2 n = new Vector2(BA.y, -BA.x);
Vector2 C = 0.5 * (A + B + n * Math.Tan(theta));
// calculate displacement angle from point A
double l = (Math.PI - 2.0 * theta) * r;
double gamma = (2.0 * Math.PI * x) / l;
// sign change as discussed
double cross = T.x * BA.y - T.y * BA.x;
if (cross < 0.0) gamma = -gamma;
// finally return the point we want
Vector2 disp = A - C;
double c_g = Math.Cos(gamma), s_g = Math.Sin(gamma);
return new Vector2(disp.X * c_g + disp.Y * s_g + C.X,
disp.Y * c_g - disp.X * s_g + C.Y);
}

Related

ATan2 for pitch on Right-handed coordinate system

public double GetPitchToFace(double Z2, double Z1, double X2, double X1)
{
double Arc;
Arc = Math.Atan2(Z2 - Z1, X2 - X1);
Arc = (Arc >= 0) ? Arc+Math.PI : (2 * Math.PI + Arc);
return Arc;
}
I am attempting to calculate the correct pitch of a player in-game in order to face and travel to a waypoint.
It might be worth noting that the games coordinate system is Right-Handed.
I've confirmed that ATan2 is receiving the correct values yet the return value is incorrect.
It seems to be returning a downward pitch despite the waypoint being above the player. Yet other times it returns the seemingly correct pitch - I suspect this might have something to do when the point / player shift quadrants ?
(Minor side note - the reason I am 2 * Math.PI if Arc is >= 0 is simply the way the game stores and manages player pitch more info can be found here :
Pitch-Ingame
)
Here is an example of the above manually calculated :
Atan2(Z2 - Z1, X2 - X1)
Arc = Atan2(179.7 - 157.9, -3457.1-(-3432.1))
Arc = Atan2(21.7,-25.3)
Arc = 2.4 Radians
Arc = Arc + PI (without adding PI we return 137.51 degrees this is the opposite angle I need so I add PI to flip it to the correct side or add 180 degrees)
Arc = 5.5 Radians
Arc = 315,127 Degrees (this is a downwards trend from the point meaning we still miss the end point)
Here is the really bad plot of the above points
Please keep in mind that the points are plotted such as X,Z not X,Y

Drawing a parabolic arc between two points based on a known projectile angle

I am trying to draw an arc between two points that represents a projectile's path. The angle that the projectile leaves point A at is known, and the X/Y coordinates of both points are known.
I'm trying to figure out the math behind this, and how to draw it up in c#.
Here is my failed attempt, based on some path examples I found
var g = new StreamGeometry();
var xDistance = Math.Abs(pointA.X - pointB.X);
var yDistance = Math.Abs(pointA.Y - pointB.Y);
var angle = 60;
var radiusX = xDistance / angle;
var radiusY = yDistance / angle;
using (var gc = g.Open())
{
gc.BeginFigure(
startPoint: pointA,
isFilled: false,
isClosed: false);
gc.ArcTo(
point: pointB,
size: new Size(radiusX, radiusY),
rotationAngle: 0d,
isLargeArc: false,
sweepDirection: SweepDirection.Clockwise,
isStroked: true,
isSmoothJoin: false);
}
Any help would be greatly appreciated!
Edit #2 (added clarity): For this problem assume that physics play no role (no gravity, velocity, or any outside forces). The projectile is guaranteed to land at point B and move along a parabolic path. The vertex will be halfway between point A and point B on the horizontal axis. The angle that it launches at is the angle up from the ground (horizontal).
So Point A (Ax, Ay) is known.
Point B (Bx, By) is known.
The angle of departure is known.
The X half of the vertex is known (Vx = Abs(Ax - Bx)).
Does this really boil down to needing to figure out the Y coordinate of the vertex?
Following on from the comments, we need a quadratic Bezier curve. This is defined by 3 points, the start, end, and a control point:
It is defined by the following equation:
We therefore need to find P1 using the given conditions (note that the gravity strength is determined implicitly). For a 2D coordinate we need two constraints / boundary conditions. They are given by:
The tangent vector at P0:
We need to match the angle to the horizontal:
The apex of the curve must be directly below the control point P1:
Therefore the vertical coordinate is given by:
[Please let me know if you would like some example code for the above]
Now for how to add a quadratic Bezier; thankfully, once you have done the above, it is not too difficult
The following method creates the parabolic geometry for the simple symmetric case. The angle is measured in degrees counterclockwise from the horizontal.
public Geometry CreateParabola(double x1, double x2, double y, double angle)
{
var startPoint = new Point(x1, y);
var endPoint = new Point(x2, y);
var controlPoint = new Point(
0.5 * (x1 + x2),
y - 0.5 * (x2 - x1) * Math.Tan(angle * Math.PI / 180));
var geometry = new StreamGeometry();
using (var context = geometry.Open())
{
context.BeginFigure(startPoint, false, false);
context.QuadraticBezierTo(controlPoint, endPoint, true, false);
}
return geometry;
}
A body movement subject only to the force of gravity (air resistance is ignored) can be evaluated with the following equations:
DistanceX(t) = dx0 + Vx0·t
DistanceY(t) = dy0 + Vy0·t - g/2·t^2
Where
g : gravity acceleration (9.8 m/s^2)
dx0 : initial position in the X axis
dy0 : initial position in the Y axis
Vy0 : initial X velocity component (muzzle speed)
Vy0 : initial Y velocity component (muzzle speed)
Well that doesn't seem very helpful, but lets investigate further. Your cannon has a muzzle speed V we can consider constant, so Vx0 and Vy0 can be written as:
Vx0 = V·cos(X)
Vy0 = V·sin(X)
Where X is the angle at which you are shooting. Ok, that seems interesting, we finally have an input that is useful to whoever is shooting the cannon: X. Lets go back to our equations and rewrite them:
DistanceX(t) = dx0 + V·cos(X)·t
DistanceY(t) = dy0 + V·sin(X)·t - g/2·t^2
And now, lets think through what we are trying to do. We want to figure out a way to hit a specific point P. Lets give it coordinates: (A, B). And in order to do that, the projectile has to reach that point in both projections at the same time. We'll call that time T. Ok, lets rewrite our equations again:
A = dx0 + V·cos(X)·T
B = dy0 + V·sin(X)·T - g/2·T^2
Lets get ourselves rid of some unnecessary constants here; if our cannon is located at (0, 0) our equations are now:
A = V·cos(X)·T [1]
B = V·sin(X)·T - g/2·T^2 [2]
From [1] we know that: T = A/(V·cos(X)), so we use that in [2]:
B = V·sin(X)·A/(V·cos(X)) - g/2·A^2/(V^2·cos^2(X))
Or
B = A·tan(X) - g/2·A^2/(V^2*cos^2(X))
And now some trigonometry will tell you that 1/cos^2 = 1 + tan^2 so:
B = A·tan(X) - g/2·A^2/V^2·(1+tan^2(X)) [3]
And now you have quadratic equation in tan(X) you can solve.
DISCLAIMER: typing math is kind of hard, I might have an error in there somewhere, but you should get the idea.
UPDATE The previous approach would allow you to solve the angle X that hits a target P given a muzzle speed V. Based on your comments, the angle X is given, so what you need to figure out is the muzzle speed that will make the projectile hit the target with the specified cannon angle. If it makes you more comfortable, don't think of V as muzzle speed, think of it as a form factor of the parabola you are trying to find.
Solve Vin [3]:
B = A·tan(X) - g/2·A^2/V^2·(1+tan^2(X))
This is a trivial quadratic equation, simply isolate V and take the square root. Obviously the negative root has no physical meaning but it will also do, you can take any of the two solutions. If there is no real number solution for V, it would mean that there is simply no possible shot (or parabola) that reaches P(angle X is too big; imagine you shoot straight up, you'll hit yourself, nothing else).
Now simply eliminate t in the parametrized equations:
x = V·cos(X)·t [4]
y = V·sin(X)·t - g/2·t^2 [5]
From [4] you have t = x/(V·cos(X)). Substitute in [5]:
y = tan(X)·x - g·x^2 /(2·V^2*cos^2(X))
And there is your parabola equation. Draw it and see your shot hit the mark.
I've given it a physical interpretation because I find it easier to follow, but you could change all the names I've written here to purely mathematical terms, it doesn't really matter, at the end of the day its all maths and the parabola is the same, any which way you want to think about it.

Approximating an ellipse with a polygon

I am working with geographic information, and recently I needed to draw an ellipse. For compatibility with the OGC convention, I cannot use the ellipse as it is; instead, I use an approximation of the ellipse using a polygon, by taking a polygon which is contained by the ellipse and using arbitrarily many points.
The process I used to generate the ellipse for a given number of point N is the following (using C# and a fictional Polygon class):
Polygon CreateEllipsePolygon(Coordinate center, double radiusX, double radiusY, int numberOfPoints)
{
Polygon result = new Polygon();
for (int i=0;i<numberOfPoints;i++)
{
double percentDone = ((double)i)/((double)numberOfPoints);
double currentEllipseAngle = percentDone * 2 * Math.PI;
Point newPoint = CalculatePointOnEllipseForAngle(currentEllipseAngle, center, radiusX, radiusY);
result.Add(newPoint);
}
return result;
}
This has served me quite while so far, but I've noticed a problem with it: if my ellipse is 'stocky', that is, radiusX is much larger than radiusY, the number of points on the top part of the ellipse is the same as the number of points on the left part of the ellipse.
That is a wasteful use of points! Adding a point on the upper part of the ellipse would hardly affect the precision of my polygon approximation, but adding a point to the left part of the ellipse can have a major effect.
What I'd really like, is a better algorithm to approximate the ellipse with a polygon. What I need from this algorithm:
It must accept the number of points as a parameter; it's OK to accept the number of points in every quadrant (I could iteratively add points in the 'problematic' places, but I need good control on how many points I'm using)
It must be bounded by the ellipse
It must contain the points straight above, straight below, straight to the left and straight to the right of the ellipse's center
Its area should be as close as possible to the area of the ellipse, with preference to optimal for the given number of points of course (See Jaan's answer - appearantly this solution is already optimal)
The minimal internal angle in the polygon is maximal
What I've had in mind is finding a polygon in which the angle between every two lines is always the same - but not only I couldn't find out how to produce such a polygon, I'm not even sure one exists, even if I remove the restrictions!
Does anybody have an idea about how I can find such a polygon?
finding a polygon in which the angle between every two lines is
always the same
Yes, it is possible. We want to find such points of (the first) ellipse quadrant, that angles of tangents in these points form equidistant (the same angle difference) sequence. It is not hard to find that tangent in point
x=a*Cos(fi)
y=b*Sin(Fi)
derivatives
dx=-a*Sin(Fi), dy=b*Cos(Fi)
y'=dy/dx=-b/a*Cos(Fi)/Sin(Fi)=-b/a*Ctg(Fi)
Derivative y' describes tangent, this tangent has angular coefficient
k=b/a*Cotangent(Fi)=Tg(Theta)
Fi = ArcCotangent(a/b*Tg(Theta)) = Pi/2-ArcTan(a/b*Tg(Theta))
due to relation for complementary angles
where Fi varies from 0 to Pi/2, and Theta - from Pi/2 to 0.
So code for finding N + 1 points (including extremal ones) per quadrant may look like (this is Delphi code producing attached picture)
for i := 0 to N - 1 do begin
Theta := Pi/2 * i / N;
Fi := Pi/2 - ArcTan(Tan(Theta) * a/b);
x := CenterX + Round(a * Cos(Fi));
y := CenterY + Round(b * Sin(Fi));
end;
// I've removed Nth point calculation, that involves indefinite Tan(Pi/2)
// It would better to assign known value 0 to Fi in this point
Sketch for perfect-angle polygon:
One way to achieve adaptive discretisations for closed contours (like ellipses) is to run the Ramer–Douglas–Peucker algorithm in reverse:
1. Start with a coarse description of the contour C, in this case 4
points located at the left, right, top and bottom of the ellipse.
2. Push the initial 4 edges onto a queue Q.
while (N < Nmax && Q not empty)
3. Pop an edge [pi,pj] <- Q, where pi,pj are the endpoints.
4. Project a midpoint pk onto the contour C. (I expect that
simply bisecting the theta endpoint values will suffice
for an ellipse).
5. Calculate distance D between point pk and edge [pi,pj].
if (D > TOL)
6. Replace edge [pi,pj] with sub-edges [pi,pk], [pk,pj].
7. Push new edges onto Q.
8. N = N+1
endif
endwhile
This algorithm iteratively refines an initial discretisation of the contour C, clustering points in areas of high curvature. It terminates when, either (i) a user defined error tolerance TOL is satisfied, or (ii) the maximum allowable number of points Nmax is used.
I'm sure that it's possible to find an alternative that's optimised specifically for the case of an ellipse, but the generality of this method is, I think, pretty handy.
I assume that in the OP's question, CalculatePointOnEllipseForAngle returns a point whose coordinates are as follows.
newPoint.x = radiusX*cos(currentEllipseAngle) + center.x
newPoint.y = radiusY*sin(currentEllipseAngle) + center.y
Then, if the goal is to minimize the difference of the areas of the ellipse and the inscribed polygon (i.e., to find an inscribed polygon with maximal area), the OP's original solution is already an optimal one. See Ivan Niven, "Maxima and Minima Without Calculus", Theorem 7.3b. (There are infinitely many optimal solutions: one can get another polygon with the same area by adding an arbitrary constant to currentEllipseAngle in the formulae above; these are the only optimal solutions. The proof idea is quite simple: first one proves that these are the optimal solutions in case of a circle, i.e. if radiusX=radiusY; secondly one observes that under a linear transformation that transforms a circle into our ellipse, e.g. a transformation of multiplying the x-coordinate by some constant, all areas are multiplied by a constant and therefore a maximal-area inscribed polygon of the circle is transformed into a maximal-area inscribed polygon of the ellipse.)
One may also regard other goals, as suggested in the other posts: e.g. maximizing the minimal angle of the polygon or minimizing the Hausdorff distance between the boundaries of the polygon and ellipse. (E.g. the Ramer-Douglas-Peucker algorithm is a heuristic to approximately solve the latter problem. Instead of approximating a polygonal curve, as in the usual Ramer-Douglas-Peucker implementation, we approximate an ellipse, but it is possible to devise a formula for finding on an ellipse arc the farthest point from a line segment.) With respect to these goals, the OP's solution would usually not be optimal and I don't know if finding an exact solution formula is feasible at all. But the OP's solution is not as bad as the OP's picture shows: it seems that the OP's picture has not been produced using this algorithm, as it has less points in the more sharply curved parts of the ellipse than this algorithm produces.
I suggest you switch to polar coordinates:
Ellipse in polar coord is:
x(t) = XRadius * cos(t)
y(t) = YRadius * sin(t)
for 0 <= t <= 2*pi
The problems arise when Xradius >> YRadius (or Yradius >> Yradius)
Instead of using numberOfPoints you can use an array of angles obviously not all identical.
I.e. with 36 points and dividing equally you get angle = 2*pi*n / 36 radiants for each sector.
When you get around n = 0 (or 36) or n = 18 in a "neighborhood" of these 2 values the approx method doesn't works well cause the ellipse sector is significantly different from the triangle used to approximate it. You can decrease the sector size around this points thus increasing precision. Instead of just increasing the number of points that would also increase segments in other unneeded areas. The sequence of angles should become something like (in degrees ):
angles_array = [5,10,10,10,10.....,5,5,....10,10,...5]
The first 5 deg. sequence is for t = 0 the second for t = pi, and again the last is around 2*pi.
Here is an iterative algorithm I've used.
I didn't look for theoretically-optimal solution, but it works quit well for me.
Notice that this algorithm gets as an input the maximal error of the prime of the polygon agains the ellipse, and not the number of points as you wish.
public static class EllipsePolygonCreator
{
#region Public static methods
public static IEnumerable<Coordinate> CreateEllipsePoints(
double maxAngleErrorRadians,
double width,
double height)
{
IEnumerable<double> thetas = CreateEllipseThetas(maxAngleErrorRadians, width, height);
return thetas.Select(theta => GetPointOnEllipse(theta, width, height));
}
#endregion
#region Private methods
private static IEnumerable<double> CreateEllipseThetas(
double maxAngleErrorRadians,
double width,
double height)
{
double firstQuarterStart = 0;
double firstQuarterEnd = Math.PI / 2;
double startPrimeAngle = Math.PI / 2;
double endPrimeAngle = 0;
double[] thetasFirstQuarter = RecursiveCreateEllipsePoints(
firstQuarterStart,
firstQuarterEnd,
maxAngleErrorRadians,
width / height,
startPrimeAngle,
endPrimeAngle).ToArray();
double[] thetasSecondQuarter = new double[thetasFirstQuarter.Length];
for (int i = 0; i < thetasFirstQuarter.Length; ++i)
{
thetasSecondQuarter[i] = Math.PI - thetasFirstQuarter[thetasFirstQuarter.Length - i - 1];
}
IEnumerable<double> thetasFirstHalf = thetasFirstQuarter.Concat(thetasSecondQuarter);
IEnumerable<double> thetasSecondHalf = thetasFirstHalf.Select(theta => theta + Math.PI);
IEnumerable<double> thetas = thetasFirstHalf.Concat(thetasSecondHalf);
return thetas;
}
private static IEnumerable<double> RecursiveCreateEllipsePoints(
double startTheta,
double endTheta,
double maxAngleError,
double widthHeightRatio,
double startPrimeAngle,
double endPrimeAngle)
{
double yDelta = Math.Sin(endTheta) - Math.Sin(startTheta);
double xDelta = Math.Cos(startTheta) - Math.Cos(endTheta);
double averageAngle = Math.Atan2(yDelta, xDelta * widthHeightRatio);
if (Math.Abs(averageAngle - startPrimeAngle) < maxAngleError &&
Math.Abs(averageAngle - endPrimeAngle) < maxAngleError)
{
return new double[] { endTheta };
}
double middleTheta = (startTheta + endTheta) / 2;
double middlePrimeAngle = GetPrimeAngle(middleTheta, widthHeightRatio);
IEnumerable<double> firstPoints = RecursiveCreateEllipsePoints(
startTheta,
middleTheta,
maxAngleError,
widthHeightRatio,
startPrimeAngle,
middlePrimeAngle);
IEnumerable<double> lastPoints = RecursiveCreateEllipsePoints(
middleTheta,
endTheta,
maxAngleError,
widthHeightRatio,
middlePrimeAngle,
endPrimeAngle);
return firstPoints.Concat(lastPoints);
}
private static double GetPrimeAngle(double theta, double widthHeightRatio)
{
return Math.Atan(1 / (Math.Tan(theta) * widthHeightRatio)); // Prime of an ellipse
}
private static Coordinate GetPointOnEllipse(double theta, double width, double height)
{
double x = width * Math.Cos(theta);
double y = height * Math.Sin(theta);
return new Coordinate(x, y);
}
#endregion
}

Logarithmic Spiral - Is Point on Spiral (cartesian coordinates

Lets Say I have a 3d Cartesian grid. Lets also assume that there are one or more log spirals emanating from the origin on the horizontal plane.
If I then have a point in the grid I want to test if that point is in one of the spirals. I acutally want to test if it within a certain range of the spirals but determining if it is on the point is a good start.
So I guess the question has a couple parts.
How to generate the arms from parameters (direction, tightness)
How to tell if a point in the grid is in one of the spiral arms
Any ideas? I have been googling all day and don't feel I am any closer to a solution than when I started.
Here is a bit more information that might help:
I don't actually need to render the spirals. I want to set the pitch and rotation and then pass a point to a method that can tell me if the point I passed is within the spiral (within a given range of any point on the spiral). Based on the value returned (true or false) my program will make a decision on whether or not something exists at the point in space.
How to parametrically define the log spirals (pitch and rotation and ??)
Test if a point (x, y, z) is withing a given range of any point on the spiral.
Note: Both of the above would be just on the horizontal plane
These are two functions defining an anti-clockwise spiral:
PolarPlot[{
Exp[(t + 10)/100],
Exp[t/100]},
{t, 0, 100 Pi}]
Output:
These are two functions defining a clockwise spiral:
PolarPlot[{
- Exp[(t + 10)/100],
- Exp[t/100]},
{t, 0, 100 Pi}]
Output:
Cartesian coordinates
The conversion Cartesian <-> Polar is
(1) Ro = Sqrt[x^2+y^2]
t = ArcTan[y/x]
(2) x = Ro Cos[t]
y = Ro Sin[t]
So, If you have a point in Cartesian Coords (x,y) you transform it to your equivalent polar coordinates using (1). Then you use the forula for the spiral function (any of the four mentinoned above the plots, or similar ones) putting in there the value for t, and obtaining Ro. The last step is to compare this Ro with the one we got from the coordinates converion. If they are equal, the point is on the spiral.
Edit Answering your comment
For a Log spiral is almost the same, but with multiple spirals you need to take care of the logs not going to negative values. That's why I used exponentials ...
Example:
PolarPlot[{
Log[t],
If[t > 3, Log[ t - 2], 0],
If[t > 5, Log[ t - 4], 0]
}, {t, 1, 10}]
Output:
Not sure this is what you want, but you can reverse the log function (or "any" other for that matter).
Say you have ln A = B, to get A from B you do e^B = A.
So you get your point and pass it as B, you'll get A. Then you just need to check if that A (with a certain +- range) is in the values you first passed on to ln to generate the spiral.
I think this might work...
Unfortunately, you will need to know some mathematics notation anyway - this is a good read about the logarithmic sprial.
http://en.wikipedia.org/wiki/Logarithmic_spiral
we will only need the top 4 equations.
For your question 1
- to control the tightness, you tune the parameter 'a' as in the wiki page.
- to control the direction, you offset theta by a certain amount.
For your question 2
In floating point arithmetic, you will never get absolute precision, which mean there will be no point falling exactly on the sprial. On the screen, however, you will know which pixel get rendered, and you can test whether you are hitting a point that is rendered.
To render a curve, you usually render it as a sequence of line segments, short enough so that overall it looks like a curve. If you want to know whether a point lies within certain distance from the spiral, you can render the curve (on a off-screen buffer if you wish) by having thicker lines.
here a C++ code drawing any spiral passing where the mouse here
(sorry for my English)
int cx = pWin->vue.right / 2;
int cy = pWin->vue.bottom / 2;
double theta_mouse = atan2((double)(pWin->y_mouse - cy),(double)(pWin->x_mouse - cx));
double square_d_mouse = (double)(pWin->y_mouse - cy)*(double)(pWin->y_mouse - cy)+
(double)(pWin->x_mouse - cx)*(double)(pWin->x_mouse - cx);
double d_mouse = sqrt(square_d_mouse);
double theta_t = log( d_mouse / 3.0 ) / log( 1.19 );
int x = cx + (3 * cos(theta_mouse));
int y = cy + (3 * sin(theta_mouse));
MoveToEx(hdc,x,y,NULL);
for(double theta=0.0;theta < PI2*5.0;theta+=0.1)
{
double d = pow( 1.19 , theta ) * 3.0;
x = cx + (d * cos(theta-theta_t+theta_mouse));
y = cy + (d * sin(theta-theta_t+theta_mouse));
LineTo(hdc,x,y);
}
Ok now the parameter of spiral is 1.19 (slope) and 3.0 (radius at center)
Just compare the points where theta is a mutiple of 2 PI = PI2 = 6,283185307179586476925286766559
if any points is near of a non rotated spiral like
x = cx + (d * cos(theta));
y = cy + (d * sin(theta));
then your mouse is ON the spiral... I searched this tonight and i googled your past question

Shorten this code that determines distance between two lat/longs in C#?

public static double Distance(LatLong from, LatLong to)
{
double lat1 = from.Latitude * (Math.PI / 180.0);
double lat2 = to.Latitude * (Math.PI / 180.0);
return
Math.Acos((Math.Sin(lat1) * Math.Sin(lat2)) +
(Math.Cos(lat1) * Math.Cos(lat2) *
Math.Cos((Math.PI / 180.0) * (to.Longitude - from.Longitude)))) * 3958.760;
}
Can you shorten this code any stretch? I'm just wondering ...
That's the standard spherical law of cosines formula. You won't get it any simpler than that. At best, you could clean up the code a little:
public static double Distance(LatLong from, LatLong to)
{
double deg = Math.PI / 180.0; // One degree in radians
double lat1 = from.Latitude * deg;
double lat2 = to.Latitude * deg;
double dLng = (to.Longitude - from.Longitude) * deg;
double R = 3958.760;
return Math.Acos(Math.Sin(lat1) * Math.Sin(lat2) +
Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(dLng)) * R;
}
No, but I can offer a shorter, faster way, but far less accurate way to obtain relative distances:
public static double RelativeDistance(LatLong from, LatLong to)
{
return (from.Latitude - to.Latitude) * (from.Latitude - to.Latitude) + (from.Longitude - to.Longitude) * (from.Longitude - to.Longitude);
}
This returns a value relative to the square of the distance in terms of the projection of coordinates unto a square 2D grid (as if the world were a 2:1 rectangle). It's so useless for real distances that I wouldn't even bother to take a square root to bring it back to being proportional to the projection (since the projection is silly), but what it can serve for is rapidly sorting by relative distances within such a small area (and far enough from the poles) that the gross inaccuracy doesn't matter much.
Hence, it won't help you calculate your fuel costs, but it will help you work out which pub is (probably) nearest. If you wanted to sort by relative distance to a given point, it could serve well and its speed be a boon. Outside of that use, it's pointless.
The formula looks like it is computing the distance along the surface of a sphere, and would thus be reasonably accurate even for points that were practically on opposite sides of the world. If the distances will be very close together, you could approximate it by projecting the points onto the surface of a cylinder (coaxial with the Earth) passing through one of the points; scale the cylinder so north/south and east/west distances on the cylinder match those on the Earth. This will simply require taking the cosine of one of the latitudes. Note that if the points are far enough apart that it matters which point's latitude you use, they are too far apart for this to be a good approximation, but for small distances this approach is quick and easy.
Note, btw, that something like a conical projection will be accurate over wider distances, but will also require more calculation; if one is going to that much trouble, one may as well use the 'right' calculations.

Categories

Resources