I need to triangulate a polygon that could be convex or concave, but it doesn't have holes
in it, is there a code or a library for objective-c that does the job?
The best way to triangulate a concave polygon in Objective-C is the ear clipping method. It requires the following steps:
1. Go through each vertex in the polygon and store the convex points in an array
- This is harder than it sounds.
You will need to find the left-most point (take the bottom-most point if there are equal x-coords).
Determine if you want to go clockwise or anti-clockwise. If anti-clockwise, find the angle between AB and BC using double angle = atan2(c.y - b.y, c.x - b.x) - atan2(a.y - b.y, a.x - b.x) where B is the vertex point.
Convert the angle from radians to degrees using angle *= 180 / M_PI. If the angle is negative, add the angle by 360 degrees.
Finally, if the angle is < 180 degrees, store the vertex in an array.
2. Find the ear of each point in your convex point array
A point is considered an "ear" if there are no vertices inside the triangle formed by the point and adjacent vertices. You will need to iterate through all points and determine if a point in the polygon lies in the triangle formed by points ABC. You can do this by finding the barycentric coordinate of the fourth point. See determine whether point lies inside triangle. Store the ears in an array.
3. Triangulate the shape
Remove each ear and draw a diagonal between the adjacent points. Discover any new convex points and determine if there are more ears. Add any new ears into the end of the array and continue this step until left with just 3 points (1 triangle). See http://www.geometrictools.com/Documentation/TriangulationByEarClipping.pdf for more details
Related
I detected lane lines in opencv and calculated their angles (which are shown by read lines in the image), although they look almost the same angle, the angle calculated by the program shows quiet a difference with left line always greater than right.
I am using arctan(slope) to find angles.
Is is due to the fact that y-axis in MAT matrix is inverted?
I am trying to detect the difference in the lane line angles to detect turns and straight road. How can I do achieve my goal? which I can not right now because lines do not have same(but opposite) angle on the straight road.
Below is the image.
Image
The difference of the two angles is not close to zero, because the lines are not parallel in 2D, simple as that. You are comparing angles of 2D lines in the image plane!
What you want to do is to check how close is the sum of the angles to zero, i.e. fabs(angle1 + angle2). You probably also want to check if fabs(angle1) and fabs(angle2) are within a specific range.
Furthermore, you shouldn't use slopes, as the slope of a vertical line is infinity. You probably have 2D direction vectors for each line at some point. Either use atan2(dy, dx) to compute the angle for each line, or you could stick with the direction vectors, in the latter case adding the normalized direction vectors and comparing their angle to the vector (0, 1), which is the vertical line.
Be aware that all this assumes that the camera points into the direction of the (straight) lane.
what I'm trying to do is getting a tangential quadrilateral from 4 points using OpenCv.
I'm tried an approach where I just take the center of the four points and adding a circle. But this is not always true. Further its very hard to determine the radius of the circle.
Shortly: A tangential quadrilateral is a circle which lies completely within a square. e.g.:
Source: https://commons.wikimedia.org/wiki/File:Tangentenviereck.svg CC BY-SA 4.0
Is there a way in OpenCv for this?
If you have 4 points A,B, C, D you definitely already have quadrilateral (four-side polygon).
It is not guaranteed that this tangential is tangential - it is true only if sums of opposite side lengths are equal.
If you really have vertices of tangential tangential - find length of sides a,b,c,d and diagonals p,q and get incircle radius as
r = Sqrt(4*p^2*q^2-(a^2-b^2+c^2-d^2)^2)) / (2*(a+b+c+d))
There is a lot of formulas for incircle center at wiki page, but I'd use trigonometric approach - get bisector vector of A angle as sum of normalized AB and AD vectors, normalize it, multiply by length |AM|=r/tg(A/2) and add resulting vector to A.
Note that OpenCV is library for image processing, not for geometric calculations.
In undistortPoints function from OpenCV, the documentations says that
http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html#undistortpoints
where undistort() is an approximate iterative algorithm that estimates the normalized original point coordinates out of the normalized distorted point coordinates (“normalized” means that the coordinates do not depend on the camera matrix).
It seems that the normalized point coordinates is obtained by adding 1 to the third coordinate. What does normalized point coordinates means? How can it be used for?
In the above, there are two lines
x" = (u - cx)/fx
y" = (v - cy)/fy
Is there one term for the coordinates(x'', y'')?
I'm not entirely sure what you mean by "Is there one term for the coordinates (x", y")", but if you mean what do they physically represent, then they are the coordinates of the image point (u, v) on the image plane expressed in the camera coordinate system (origin at the centre of projection, x-axis to the right, y-axis down, z-axis pointing out towards the scene and perpendicular to the image plane), whereas (u,v) are the coordinates of the image point relative to the origin at the top left corner of the image plane (x-axis to the right, y-axis down). All quantities are expressed in pixels.
The output of the undistortPoints function are normalised coordinates, which means that the points returned in the dst parameter have their (x", y") coordinates between 0 and 1 (not shown in the equations you presented, but is the output of the internally called undistort function within undistortPoints).
2D coordinates (whether normalised or not) that have a 1 inserted as the third coordinate are known as homogenous coordinates. The same can be done for 3D coordinates by inserting a 1 into the 4th element. Homogenous coordinates are useful because they allow certain operations to be represented as a simple linear equation whereas their non-homogenous equivalent may not be as straightforward.
I want to let the user control an object moving over the surface of a static sphere. Using two buttons to rotate the direction of the object clockwise and anti-clockwise as it constantly moves forward similar to asteroids.
In scene kit there are three different orientation properties for an SCNNode and I really don't know where to start. I understand how to execute everything except the rotation around the sphere.
You're looking for a parameterization of the surface of the sphere. You can find this online (but it can be tricky if you don't know the magic words to enter for your searches). Check out the entry on MathWorld.
The surface of the sphere is parameterized by two angle variables, call them s and t. Note that one variable will run from zero to 2 pi, and the other will run only from zero to pi. This is a gotcha that can be easy to miss. To convert these angles to rectangular (x, y, z) coordinates, you use the formula:
x = r cos(s) sin(t)
y = r sin(s) sin(t) // Yes it's sin(t) twice, that's not a typo.
z = r cos(t)
I find the following visualization helpful. A curve in a plane (the xy-plane, for example) sweeps out an angle from zero to pi, half a rotation and corresponds to the parameter s. If you set t equal to pi/2, so sin(t) = 1, then you can see how x and y turn into standard rectangular coordinates for a circular section. After the s parameter sweeps out half a circle, you can rotate that half circle all the way around from zero to 2 pi, to form a full sphere, and that full sweep corresponds to the parameter t.
If you represent your object's position by coordinates (s, t) then you can, for the most part, safely convert to rectangular coordinates using the formula above without worrying about the domain of either parameter; however if s or t grow without bound (say, because your object orbits continuously for a long time) it might be worth the small extra effort to normalize the parameters. I'm not sure how sin or cos behave for very large inputs.
I'm trying to move multiple sprites (images) in an elliptical path such that distance (arc distance) remains uniform.
I have tried
Move each sprite angle by angle, however the problem with this is that distance moved while moving unit angle around major axis is different than that while moving unit angle around minor axis - hence different distance moved.
Move sprites with just changing x-axis uniformly, however it again moves more around major axis.
So any ideas how to move sprites uniformly without them catching-up/overlapping each other?
Other info:
it will be called in onMouseMove/onTouchMoved so i guess it shouldn't
be much CPU intensive.
Although its a general algorithm question but
if it helps I'm using cocos2d-x
So this is what i ended up doing (which solved it for me):
I moved it in equation of circle and increased angle by 1 degree. Calculated x and y using sin/cos(angle) * radius. And to make it into an ellipse I multiplied it by a factor.
Factor was yIntercept/xIntercept.
so it looked like this in end
FACTOR = Y_INTERCEPT / X_INTERCEPT;
//calculate previous angle
angle = atan((prev_y/FACTOR)/prev_x);
//increase angle by 1 degree (make sure its not radians in your case)
angle++;
//new x and y
x = cos(newangle) * X_INTERCEPT;
y = sin(newangle) * X_INTERCEPT * FACTOR;
I have written a function named getPointOnEllipse that allows you to move your sprites pixel-by-pixel in an elliptical path. The function determines the coordinates of a particular point in the elliptical path, given the coordinates of the center of the ellipse, the lengths of the semi-major axis and the semi-minor axis, and finally the offset of the point into the elliptical path, all in pixels.
Note: To be honest, unfortunately, the getPointOnEllipse function skips (does not detect) a few of the points in the elliptical path. As a result, the arc distance is not exactly uniform. Sometimes it is one pixel, and sometimes two pixels, but not three or more! In spite of the fault, changes in speed will be really "faint", and IMO, your sprites will move pretty smoothly.
Below is the getPointOnEllipse function, along with another function named getEllipsePerimeter, which is used to determine an ellipse's perimeter through Euler's formula. The code is written in JScript.
function getEllipsePerimeter(rx, ry)
{
with (Math)
{
// You'll need to floor the return value to obtain the ellipse perimeter in pixels.
return PI * sqrt(2 * (rx * rx + ry * ry));
}
}
function getPointOnEllipse(cx, cy, rx, ry, d)
{
with (Math)
{
// Note: theta expresses an angle in radians!
var theta = d * sqrt(2 / (rx * rx + ry * ry));
//var theta = 2 * PI * d / getEllipsePerimeter(rx, ry);
return {x:floor(cx + cos(theta) * rx),
y:floor(cy - sin(theta) * ry)};
}
}
The following figure illustrates the parameters of this function:
cx - the x-coordinate of the center of the ellipse
cy - the y-coordinate of the center of the ellipse
rx - the length of semi-major axis
ry - the length of semi-minor axis
d - the offset of the point into the elliptical path (i.e. the arc length from the vertex to the point)
The unit of all parameters is pixel.
The function returns an object containing the x- and y-coordinate of the point of interest, which is represented by a purple ball in the figure.
d is the most important parameter of the getPointOnEllipse function. You should call this function multiple times. In the first call, set d to 0, and then place the sprite at the point returned, which causes the sprite to be positioned on the vertex. Then wait a short period (e.g. 50 milliseconds), and call the function again, setting d parameter to 1. This time, by placing the sprite at the point returned, it moves 1 pixel forward in the ellipse path. Then repeat doing so (wait a short period, call the function with increased d value, and position the sprite) until the value of d reaches the perimeter of the ellipse. You can also increase d value by more than one, so that the sprite moves more pixels forward in each step, resulting in faster movement.
Moreover, you can modify the getEllipsePerimeter function in the code to use a more precise formula (like Ramanujan's formula) for getting ellipse perimeter. But in that case, be sure to modify the getPointOnEllipse function as well to use the second version of theta variable (which is commented in the code). Note that the first version of theta is just a simplified form of the second version for the sake of optimization.