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))
Related
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.
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.
Lets say I have 2 points (x1,y1) and (x2,y2). And I can draw vector from point (x1,y1) to point (x2,y2). How can I get all possible points between them at for example every 10 pixels?
Simple visualization:
The vector between point A and a point B is B-A (x2-x1, y2-y1)
If you normalize that vector, and multiply it by the factor you want (it seems you want a distance of 10px, so your factor is 10), you can get all the points by adding it to the a current point (which initially is the origin A) until you reach the end point B.
You can take a smaller stepVector and add him step by step.
PseudoCode:
stepVector = yourVector / 10
Point1 = basePoint + stepVector
Point2 = Point1 + stepVector
...
or something line
stepVector = yourVector / 10
Point1 = basePoint + stepVector
Point2 = basePoint + (stepVector * 2)
Point3 = basePoint + (stepVector * 3)
...
I've got two points between which im drawing a line (x1,y1 and x2,y2) but i need to know the coordinates of x3,y3 which is gapSize away from point x2,y2. Any ideas on how to solve this problem (the program is written in objective-c if that is helpful at all)?
You can simply calculate the angle in radians as
double rads = atan2(y2 - y1, x2 - x1);
Then you get the coordinates as follows:
double x3 = x2 + gapSize * cos(rads);
double y3 = y2 + gapSize * sin(rads);
Is this what you meant?
Compute the distance between P1 and P2: d=sqrt( (y2-y1)^2 + (x2-x1)^2)
Then x2 = (d*x1 + gapSize*x3) / (d+gapSize)
So x3 = (x2 * (d+gapSize) - d*x1) / gapSize
Similarly, y3 = (y2 * (d+gapSize) - d*y1) / gapSize
Sorry for the math. I didn't try to code it but it sounds right. I hope this helps.
There are many ways to do this. Simplest (to me) is the following. I'll write it in terms of mathematics since I can't even spell C.
Thus, we wish to find the point C = {x3,y3}, given points A = {x1,y1} and B = {x2,y2}.
The distance between the points is
d = ||B-A|| = sqrt((x2-x1)^2 + (y2-y1)^2)
A unit vector that points along the line is given by
V = (B - A)/d = {(x2 - x1)/d, (y2-y1)/d}
A new point that lies a distance of gapSize away from B, in the direction of that unit vector is
C = B + V*gapSize = {x2 + gapSize*(x2 - x1)/d, y2 + gapSize*(y2 - y1)/d}
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