counter-clockwise cgpath/uibezierpath - objective-c

How can I tell if these points are connected counter-clockwise or clockwise?
I have this code in my GameScene.m:
CGFloat radius = (self.frame.size.width - 6) / 2;
CGFloat a = radius * sqrt((CGFloat)3.0) / 2;
CGFloat b = radius / 2;
UIBezierPath *pathFirstTrigon = [UIBezierPath bezierPath];
[pathFirstTrigon moveToPoint:CGPointMake(0, -radius)];
[pathFirstTrigon addLineToPoint:CGPointMake(a, b)];
[pathFirstTrigon addLineToPoint:CGPointMake(-a, b)];
[pathFirstTrigon closePath];

The orientation can be deduced from the signed area. You can calculate the signed area from the sum of cross products of consecutive points:
2 * area = (0, -radius) x (a, b) + (a, b) ⨯ (-a, b) + (-a, b) ⨯ (0, -radius)
With the definition of the 2D cross product:
(a, b) ⨯ (c, d) = a * d - b * c
This gets you:
area = a * radius + a * b
Use the sign of the area to determine if the path is clockwise or counter-clockwise (which one refers to what sign depends on your coordinate system).

What you have is something similar to :
Y
(-a,b) ^ (a,b)
+ | +
|
|
|
|
--------+---------> X
|
+ (0,r)
|
So it is counter-clockwise on standard coordinates system.

Related

Finding intersection points of line and circle

Im trying to understand what this function does. It was given by my teacher and I just cant understands, whats logic behind the formulas finding x, and y coordinates. From my math class I know I my formulas for finding interception but its confusing translated in code. So I have some problems how they defined the formulas for a,b,c and for finding the coordinates x and y.
void Intersection::getIntersectionPoints(const Arc& arc, const Line& line) {
double a, b, c, mu, det;
std::pair<double, double> xPoints;
std::pair<double, double> yPoints;
std::pair<double, double> zPoints;
//(m2+1)x2+2(mc−mq−p)x+(q2−r2+p2−2cq+c2)=0.
//a= m2;
//b= 2 * (mc - mq - p);
//c= q2−r2+p2−2cq+c2
a = pow((line.end().x - line.start().x), 2) + pow((line.end().y - line.start().y), 2) + pow((line.end().z - line.start().z), 2);
b = 2 * ((line.end().x - line.start().x)*(line.start().x - arc.center().x)
+ (line.end().y - line.start().y)*(line.start().y - arc.center().y)
+ (line.end().z - line.start().z)*(line.start().z - arc.center().z));
c = pow((arc.center().x), 2) + pow((arc.center().y), 2) +
pow((arc.center().z), 2) + pow((line.start().x), 2) +
pow((line.start().y), 2) + pow((line.start().z), 2) -
2 * (arc.center().x * line.start().x + arc.center().y * line.start().y +
arc.center().z * line.start().z) - pow((arc.radius()), 2);
det = pow(b, 2) - 4 * a * c;
/* Tangenta na kružnicu */
if (Math<double>::isEqual(det, 0.0, 0.00001)) {
if (!Math<double>::isEqual(a, 0.0, 0.00001))
mu = -b / (2 * a);
else
mu = 0.0;
// x = h + t * ( p − h )
xPoints.second = xPoints.first = line.start().x + mu * (line.end().x - line.start().x);
yPoints.second = yPoints.first = line.start().y + mu * (line.end().y - line.start().y);
zPoints.second = zPoints.first = line.start().z + mu * (line.end().z - line.start().z);
}
if (Math<double>::isGreater(det, 0.0, 0.00001)) {
// first intersection
mu = (-b - sqrt(pow(b, 2) - 4 * a * c)) / (2 * a);
xPoints.first = line.start().x + mu * (line.end().x - line.start().x);
yPoints.first = line.start().y + mu * (line.end().y - line.start().y);
zPoints.first = line.start().z + mu * (line.end().z - line.start().z);
// second intersection
mu = (-b + sqrt(pow(b, 2) - 4 * a * c)) / (2 * a);
xPoints.second = line.start().x + mu * (line.end().x - line.start().x);
yPoints.second = line.start().y + mu * (line.end().y - line.start().y);
zPoints.second = line.start().z + mu * (line.end().z - line.start().z);
}
Denoting the line's start point as A, end point as B, circle's center as C, circle's radius as r and the intersection point as P, then we can write P as
P=(1-t)*A + t*B = A+t*(B-A) (1)
Point P will also locate on the circle, therefore
|P-C|^2 = r^2 (2)
Plugging equation (1) into equation (2), you will get
|B-A|^2*t^2 + 2(B-A)\dot(A-C)*t +(|A-C|^2 - r^2) = 0 (3)
This is how you get the formula for a, b and c in the program you posted. After solving for t, you shall obtain the intersection point(s) from equation (1). Since equation (3) is quadratic, you might get 0, 1 or 2 values for t, which correspond to the geometric configurations where the line might not intersect the circle, be exactly tangent to the circle or pass thru the circle at two locations.

Drawing triangles on a slope

I am writing an objective-c method that draws a series of triangles on a slope. In order to complete this, I need to calculate the vertex point of each triangle (C,D). The position starting and ending points are variable.
This seems like it should be an easy math problem. But so far I haven't been able to work it out on paper. Can anyone point me in the right direction?
No trigonometry involved.
Let D= Sqrt(X12^2+Y12^2) the Euclidean distance between P1 and P2 (X12 = X2-X1 and Y12 = Y2-Y1), and let p= P/D, a= A/D.
If P1P2 was the line segment (0, 0)-(1, 0), the vertices would be at (0, 0), (a, p/2), (0, p), (a, 3p/2), (0, 2p)...
The transform below scales and rotates (0, 0)-(1, 0) to P1P2:
X = X1 + X12.x - Y12.y
Y = Y1 + Y12.x + X12.y
Set triangle at origin horizontally:
(0, 0), (p, 0), (p/2, a)
Rotate to get needed slope alpha:
(0, 0), (p*cos(alpha), p*sin(alpha)), (p/2 * cos(alpha) - a * sin(alpha), p/2 * sin(alpha) + a*sin(alpha))
Shift by adding (x1, y1) to all of the coordinates.
The third coordinate is your vertex:
(Cx, Cy) = (p/2 * cos(alpha) - a * sin(alpha) + x1, p/2 * sin(alpha) + a*sin(alpha) + y1)
To find other vertices use the fact that they are shifted by p from each other, under the angle alpha:
(Cx_i, Cy_i) = (Cx, Cy) + i*(p * cos(alpha), p * sin(alpha))

Minimum distance between a point and a line in latitude, longitude

I have a line with two points in latitude and longitude
A: 3.222895, 101.719751
B: 3.227511, 101.724318
and 1 point
C: 3.224972, 101.722932
How can I calculate minimum distance between point C and a line consists of point A and B?
It will be convenient if you can provide the calculation and objective-c code too. The distance is around 89 meters (using ruler in Google Earth).
Thanks to mimi and this great article http://www.movable-type.co.uk/scripts/latlong.html but they don't give the whole picture. Here is a detail one. All this points are collected using Google Earth using Placemark to mark the locations. Make sure lat/long are set to decimal degrees in Preferences.
lat A = 3.222895
lon A = 101.719751
lat B = 3.222895
lon B = 101.719751
lat C = 3.224972
lon C = 101.722932
Earth radius, R = 6371
1. First you have to find the bearing from A to C and A to B.
Bearing formula
bearingAC = atan2( sin(Δλ)*cos(φ₂), cos(φ₁)*sin(φ₂) − sin(φ₁)*cos(φ₂)*cos(Δλ) )
bearingAB = atan2( sin(Δλ)*cos(φ₂), cos(φ₁)*sin(φ₂) − sin(φ₁)*cos(φ₂)*cos(Δλ) )
φ is latitude, λ is longitude, R is earth radius
2. Find A to C distance using spherical law of cosines
distanceAC = acos( sin(φ₁)*sin(φ₂) + cos(φ₁)*cos(φ₂)*cos(Δλ) )*R
3. Find cross-track distance
distance = asin(sin(distanceAC/ R) * sin(bearingAC − bearing AB)) * R
Objective-C code
double lat1 = 3.227511;
double lon1 = 101.724318;
double lat2 = 3.222895;
double lon2 = 101.719751;
double lat3 = 3.224972;
double lon3 = 101.722932;
double y = sin(lon3 - lon1) * cos(lat3);
double x = cos(lat1) * sin(lat3) - sin(lat1) * cos(lat3) * cos(lat3 - lat1);
double bearing1 = radiansToDegrees(atan2(y, x));
bearing1 = 360 - ((bearing1 + 360) % 360);
double y2 = sin(lon2 - lon1) * cos(lat2);
double x2 = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lat2 - lat1);
double bearing2 = radiansToDegrees(atan2(y2, x2));
bearing2 = 360 - ((bearing2 + 360) % 360);
double lat1Rads = degreesToRadians(lat1);
double lat3Rads = degreesToRadians(lat3);
double dLon = degreesToRadians(lon3 - lon1);
double distanceAC = acos(sin(lat1Rads) * sin(lat3Rads)+cos(lat1Rads)*cos(lat3Rads)*cos(dLon)) * 6371;
double min_distance = fabs(asin(sin(distanceAC/6371)*sin(degreesToRadians(bearing1)-degreesToRadians(bearing2))) * 6371);
NSLog(#"bearing 1: %g", bearing1);
NSLog(#"bearing 2: %g", bearing2);
NSLog(#"distance AC: %g", distanceAC);
NSLog(#"min distance: %g", min_distance);
Actually there's a library for this. You can find it here https://github.com/100grams/CoreLocationUtils
Calculate bearing for each: C to A , and C to B:
var y = Math.sin(dLon) * Math.cos(lat2);
var x = Math.cos(lat1)*Math.sin(lat2) -
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
var brng = Math.atan2(y, x).toDeg();
dLon= lon2-lon1;
Calculate cross-track distance:
var dXt = Math.asin(Math.sin(distance_CB/R)*Math.sin(bearing_CA-bearing_CB)) * R;
R is the radius of earth, dXt is the minimum distance you wanted to calculate.
Code to carry out this calculation is posted at here.
This implements an accurate solution in terms of ellipsoidal geodesics.
For the basic geodesic calculations, you can use
GeographicLib or the port of these algorithms to C which are included in version 4.9.0 of PROJ.4. This C interface is documented here.
Here's the result of compiling and running intercept.cpp:
$ echo 3.222895 101.719751 3.227511 101.724318 3.224972 101.722932 | ./intercept
Initial guess 3.225203 101.7220345
Increment 0.0003349040566247297 0.0003313413822354505
Increment -4.440892098500626e-16 0
Increment 0 0
...
Final result 3.225537904056624 101.7223658413822
Azimuth to A1 -135.1593040635131
Azimuth to A2 44.84069593652217
Azimuth to B1 134.8406959363608
Distance to line is 88.743m:
$ echo 3.224972 101.722932 3.225537904056624 101.7223658413822 | GeodSolve -i
-45.15927221 -45.15930407 88.743
See post here:
https://stackoverflow.com/a/33343505/4083623
For distance up to a few thousands meters I would simplify the issue from sphere to plane.
Then, the issue is pretty simply as a easy triangle calculation can be used:
We have points A and B and look for a distance X to line AB. Then:
Location a;
Location b;
Location x;
double ax = a.distanceTo(x);
double alfa = (Math.abs(a.bearingTo(b) - a.bearingTo(x))) / 180
* Math.PI;
double distance = Math.sin(alfa) * ax;
If you know how to calculate the distance of two points, get the distances between each two points, you get AB, AC, and BC. You want to know the closest distance between point C and line AB.
First get the value of P
P=(AB+BC+AC)/2
Using P, you need to get S
S=SQRT((P(P-AC)(P-AB)(P-AC))
SQRT means square root. Then you get what you want by
2*S/AB

Calculating point and dimensions of maximum rotated rectangle inside rectangle

I have a rectangle that has to be rotated always the same amount of degrees. Lets call this angle alpha (𝜶).
The width (w) and height (h) of this rectangle can vary. The rectangle has always to fit rotated inside the big rectangle. It must be scaled up or down to fit inside the gray rectangle.
NOTE: Alpha is the angle between w and the horizontal line.
So, there are 3 kinds of rectangles where
w > h
w < h or
w = h
See the picture below.
What I know:
The big rectangle has width of R and height of K and I know both values;
w and h are unknown;
the rectangle is always rotated 𝜶 degrees;
I know the value of w/h. I call this "ratioWH";
red rectangle is always centered horizontally and vertically on the gray rectangle
what I need to know:
the maximum values of w and h that will fit the gray rectangle for each case of w and h.
the coordinates of point P, assuming that 0,0 is at the upper left of the gray rectangle.
This is what I did so far, but this is not giving the correct values:
CGPoint P = CGPointZero;
if (ratioWH > 0) { // means w > h
maxH = R / (ratioWH * fabsf(cosf(theta)) + fabsf(sinf(theta)));
maxW = maxH * ratioWH;
// P.x = 0.0f; // P.x is already zero
CGFloat marginY = (K - maxW * fabsf(sinf(theta)) - maxH * fabsf(cosf(theta))) / 2.0f;
P.y = marginY + maxW * fabsf(sinf(theta));
} else { // w <= h
maxW = K / (fabsf(cosf(theta) / ratioImagemXY) + fabsf(sinf(theta)));
maxH = maxW / ratioWH;
P.x = (R - maxW * fabsf(cosf(theta)) - maxH * fabsf(sinf(theta))) / 2.0f;
P.y = maxW * fabsf(sinf(theta));
}
any clues? Thanks.
The way I see it is like this... You work out the total width and total height of the rectangle. For that, you simply walk along two edges. Like this:
dx = w * cos(theta) + h * sin(theta)
dy = h * cos(theta) + w * sin(theta)
These could be negative, so special handling would apply if the rectangle is rotated into other quadrants. This will happen later.
You now just need the ratio between the width and height. This is where you decide whether to scale by the vertical amount or the horizontal amount. It's nothing to do with w and h -- it's actually about where the rectangle ends up as a result of rotation. That's what dx and dy are for.
rectratio = abs( dx / dy )
viewratio = R / K
If rectratio comes out larger than viewratio that means the rotated rectangle's horizontal footprint needs to be scaled. Otherwise you scale by the vertical footprint.
if rectratio > viewratio
scale = R / abs(dx)
else
scale = K / abs(dy)
end
And the scale itself is applied to the original width and height
sw = scale * w
sh = scale * h
So now you can compute the corners of your rectangle. It doesn't matter where you start.
x[0] = 0
x[1] = x[0] + sw * cos(theta)
x[2] = x[1] + sh * sin(theta)
x[3] = x[2] - sw * cos(theta)
y[0] = 0
y[1] = y[0] - sw * sin(theta)
y[2] = y[1] + sh * cos(theta)
y[3] = y[2] + sw * sin(theta)
I've assumed image co-ordinates given that (0,0) is top-left, so increasing y moves down. So, if I haven't made a mistake in my math, the above gives you the rectangle vertices (in clockwise order).
The last thing to do is normalise them... This means finding the min value of px and py. Call them pxmin and pymin. I don't need to show code for that. The idea is to calculate an offset for your rectangle such that the view area is defined by the rectangle (0,0) to (R,K).
First we need to find the left and right value of the subview that completely contains our rotated rectangle... Remember the ratio before:
if( rectratio > viewratio )
// view is too tall, so centre vertically:
left = 0
top = (K - scale * abs(dy)) / 2.0
else
// view is too wide, so centre horizontally:
left = (R - scale * abs(dx)) / 2.0
top = 0
end
left and top are now the 'minimum' co-ordinate of our subview that exactly contains the rectangle (floating point rounding errors exempted). So:
left += pxmin
top += pymin
Now they are the offset required to shift the rectangle to where it's wanted. All you do is add left and top to all your rectangle co-ordinates, and you are done. The position of P is px[0] and py[0]. If you rotated by 90 degrees or more, it won't be the top-left vertex.

How to find z by arbitrary x,y coordinates within triangle if you have triangle vertices

Given vertices V1 (x1,y1,z1), V2 (x2,y2,z2), V3 (x3,y3,z3) of a triangle T, I have to find z coordinate of a point by it's x,y coordinate if I know that (x,y) lies within projection of triangle Tp (x1,y1), (x2,y2), (x3,y3).
Actually, triangle plane in 3D is defined by equation: Ax+By+Cz+D=0, and I can find z = (D-Ax-By)/C
The problem is that A, B, C, D are too expensive to calculate in run-time:
A = y1(z2-z3) + y2(z3-z1) + y3(z1-z2)
B = z1(x2-x3) + z2(x3-x1) + z3(x1-x2)
C = x1(y2-y3) + x2(y3-y1) + x3(y1-y2)
D = -x1(y2*z3 – y3*z2) – x2(y3*z1 – y1*z3) – x3 (y1*z2 – y2*z1)
Is it possible to calculate A, B, C, D using, say, opengl shaders? Are there optimized algorithms to find plane coefficients?
The technique is called Barycentric coordinates but the wiki page is pretty hard to follow -
See http://www.alecjacobson.com/weblog/?p=1596
float calcY(vec3 p1, vec3 p2, vec3 p3, float x, float z) {
float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z);
float l1 = ((p2.z - p3.z) * (x - p3.x) + (p3.x - p2.x) * (z - p3.z)) / det;
float l2 = ((p3.z - p1.z) * (x - p3.x) + (p1.x - p3.x) * (z - p3.z)) / det;
float l3 = 1.0f - l1 - l2;
return l1 * p1.y + l2 * p2.y + l3 * p3.y;
}
Code from http://www.gamedev.net/topic/597393-getting-the-height-of-a-point-on-a-triangle/ - carefull about computer graphics vs maths use of Y Z
ps. I Don't know of any faster version using shaders. One quick dirty+solution is to render the triangle using colors based on the height of the vertices and pick the pixel color at your X,Y - in practice this never ends up being much faster on a desktop machine, don't know about opengl-es