The path I'm using has no curves; just a series of connected points.
The method I'm currently using involves iterating through the NZBezierPathElement components of the path and getting each point, but this is clumsy - especially because I have to save the last point to get each new distance. If any of you know of a better method, that would be very much appreciated.
Your algorithm sounds exactly right - the length of the path is the sum of the lengths between each pair of points. It's hard to see why you think this is "clumsy", so here is the algorithm in pseudo code just in case:
startPoint <- point[1]
length <- 0
repeat with n <- 2 to number of points
nextPoint <- point[n]
length <- length + distanceBetween(startPoint, nextPoint)
startPoint <- nextPoint // hardly clumsy
end repeat
Maybe you're doing it differently?
The notion of current point is fundamental to NSBezierPath (and SVG, turtle graphics, etc.), with its relative commands (e.g. move relative, line relative) - there is no escaping it!
Related
I have a program written in vb.net that creates a graph and draws various lines on it parsed from an XML file. Each line defines if points on the graph must be above or below it.
Simply put, I am looking for a way to find the closest number ABOVE and BELOW a certain point.
So say we have a straight line {(0,0)(1,1)(2,2)(3,3)}
and a point we want to validate (1.5,4) Say this point needs to be ABOVE the line.
Also, i should mention that the line may not always be a straight line but have many segments representing a curve.
I suspect the easiest way to do this is to find the 2 points on the line surrounding our point on the x axis, get the slope between them and then interpolate.
So I tried this:
pointBelow = validationLine.points.Aggregate(Function(x, y) If(Math.Abs(x.X - paramPoint.XValue) < Math.Abs(y.X - paramPoint.YValues(0)), x, y))
pointAbove = validationLine.points.Aggregate(Function(x, y) If(Math.Abs(x.X - paramPoint.XValue) < Math.Abs(y.X - paramPoint.YValues(0)), x, y))
As you can see, these will obviously both return the same value, so I would like to know how I can search for the closest number in a list BELOW a given value, then do the same thing but search ABOVE that value.
P.S. it is also possible that the point we are validating may be at the exact same place on the x axis as one of the vertices on our line and I am looking for a solution that will solve this regardless.
Sorry but it's too long to comment.
It depends on the line that you are comparing it to... if your line is a function, it means it will never 'go backwards', and you just have to compare the Y-values of the point and your line at point X.
If it's not a function, then it's harder, and maybe you should ask that question on a math Q&A site, like https://mathematica.stackexchange.com/
Suppose I have a point to point line string in SQL Server for instance
geometry::STLineFromText('LINESTRING(0 0, 30 30)', 0)
Is there a function that will take this line and create a circle or half circle that uses the start and end point of the line as the diameter
Sorry for the late answer, I've only just found the question.
You have to use a combination of functions to achieve this, but it is fairly simple to create a circle. For example:
declare #geom geometry = geometry::STLineFromText('LINESTRING(0 0, 30 30)', 0);
declare #circle geometry = #geom.STEnvelope().STCentroid().STBuffer(#geom.STLength() / 2);
Essentially, we use STEnvelope() to build a polygon around the line, this lets us then use STCentroid() to obtain the centre point of the polygon (and therefore line) which we in turn finally expand with STBuffer() using STLength() / 2 as the buffer distance (which of course is half the length of the line - and therefore the radius of the required circle).
Creating a half (or semi) circle isn't going to be quite so easy. You'll need to consider creating your own function that uses a GeometryBuilder to define a Polygon, starting at your line start point and ending at your line end point, in between calculating the resting coordinate having travelled half the length of your line from the centre point along multiple angles, starting at the angle of your line minus 180 and going clockwise until you reach the angle of your line. The more points you have, the more circular like it will be.
Given a GEO-JSON polygon, such as the below:
[
[15.520376, 38.231155],
[15.160243, 37.444046],
[15.309898, 37.134219],
[15.099988, 36.619987],
[14.335229, 36.996631],
[13.826733, 37.104531],
[12.431004, 37.61295],
[12.570944, 38.126381],
[13.741156, 38.034966],
[14.761249, 38.143874],
[15.520376, 38.231155]
]
How can I check if a GPS location is within the polygon region?
For example, if the user is at Lat 37.387617, Long 14.458008, how would I go about searching the array?
I don't need someone to necessarily write the code for me, I just don't understand the logic of how I can check. If you have any example (any language) please point me.
This task is called point in polygon test.
Gerve has explained the algorithm that is widley used for this task. But this will not help you in implementing it. There are foot traps, like parallel lines.
One of that algorithms is called Crossings Multiply test, which is an optimized variant.
Source code: CrossingsMultiplyTest (last function in the file)
An Overview is given in "Point in Polygon Strategies"
Use longitude for the x coordinate, and latitude for the y coordinate.
I've found an article about the Ray-casting algorithm. It's explained pretty well here, the jist of it is (in pseudo code):
count ← 0
foreach side in polygon:
if ray_intersects_segment(P,side) then
count ← count + 1
if is_odd(count) then
return inside
else
return outside
I'm trying to build a MKPolygon using the outer boundary of a set of coordinates.
From what I can tell, there is no delivered functionality to achieve this in Xcode (the MKPolygon methods would use all points to build the polygon, including interior points).
After some research I've found that a convex-hull solves this problem.
After looking into various algorithms, the one I can best wrap my head around to implement is QuickHull.
This takes the outer lat coords and draws a line between the two. From there, you split your points based on that line into two subsets and process distance between the outer lats to start building triangles and eliminating points within until you are left with the outer boundary.
I can find the outer points just by looking at min/max lat and can draw a line between the two (MKPolyline) - but how would I determine whether a point falls on one side or the other of this MKPolyline?
A follow up question is whether there is a hit test to determine whether points fall within an MKPolygon.
Thanks!
I ended up using a variation of the gift wrap algorithm. Certainly not a trivial task.
Having trouble with formatting of the full code so I'll have to just put my steps (probably better because I have some clean up to do!)
I started with an array of MKPointAnnotations
1) I got the lowest point that is furthest left. To do this, I looped through all of the points and compared lat/lng to get lowest point. This point will definitely be in the convex hull, so add it to a NSMutableArray that will store our convex hull points (cvp)
2) Get all points to the left of the lowest point and loop through them, calculating the angle of the cvp to the remaining points on the left. Whichever has the greatest angle, will be the point you need to add to the array.
atan(cos(lat1)sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1), sin(lon2-lon1)*cos(lat2))
For each point found, create a triangle (by using lat from new point and long from previous point) and create a polygon. I used this code to do a hit test on my polygon:
BOOL mapCoordinateIsInPolygon = CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO);
If anything was found in the hit test, remove it from the comparison array (all those on the left of the original array minus the hull points)
Once you have at least 3 points in your cvp array, build another polygon with all of the cvp's in the array and remove anything within using the hit test.
3) Once you've worked through all of the left points, create a new comparison array of the remaining points that haven't been eliminated or added to the hull
4) Use the same calculations and polygon tests to remove points and add the cvp's found
At the end, you're left with a list of points in that make up your convex hull.
I have a projectile that I would like to pass through specific coordinates at the apex of its path. I have been using a superb equation that giogadi outlined here, by plugging in the velocity values it produces into chipmunk's cpBodyApplyImpulse function.
The equation has one drawback that I haven't been able to figure out. It only works when the coordinates that I want to hit have a y value higher than the cannon (where my projectile starts). This means that I can't shoot at a downward angle.
Can anybody help me find a suitable equation that works no matter where the target is in relation to the cannon?
As pointed out above, there isn't any way to make the apex be lower than the height of the cannon (without making gravity work backwards). However, it is possible to make the projectile pass through a point below the cannon; the equations are all here. The equation you need to solve is:
angle = arctan((v^2 [+-]sqrt(v^4 - g*(x^2+2*y*v^2)))/g*x)
where you choose a velocity and plug in the x and y positions of the target - assuming the cannon is at (0,0). The [+-] thing means that you can choose either root. If the argument to the square root function is negative (an imaginary root) you need a larger velocity. So, if you are "in range" you have two possible angles for any particular velocity (other than in the maximum range 45 degree case where the two roots should give the same answer).
I suspect one trajectory will tend to 'look' much more sensible than the other, but that's something to play around with once you have something working. You may want to stick with the apex grazing code for the cases where the target is above the cannon.