Polyline drawMapRect optimized drawing - ios

I have lots of long polylines on a map.
I'd like to optimize their drawing, because at a few thousand points the polylines are drawn incredibly slow.
My drawMapRect looks like this :
- for each polyline segment
- verify if it's bounding box intersects the currently drawn MKMapRect
- if id does, draw it
Which does great if there aren't too many points. But when there are 8-16 maprects visible and 2-3000 points, they are incredibly slow running throught the for.
If they would be only locations, a solution would be to implement some kind of quadtree/r-tree structure and only filter for those locations in the currently drawn MKMapRect, but I'm not sure about if that would be appropiate for the polylines themselves.
If I filter only for the segment endpoints inside the current maprect, then some line segments might not be drawn. For example, the two red maprects between points 1-2 have no segment endpoints in them but still need to draw ...
Is there some kind of algorithm similar to quadtrees or some kind of approach for this problem ?

Unfortunately, I don’t know such a data structure that would allow to check line intersection with a rectangle.
However, one approach to solve the problem might be the following:
Draw all polylines in a map of very low resolution (a 2 dim array), and note for every pixel which polyline has drawn it. Then scan in this low-res map the relevant rectangles for drawn pixels, and store all relevant polylines. These can then be drawn in the full resolution map.
Maybe this approximate algorithm is faster than the precise algorithm that you use right now.
EDIT:
I assume you use for the polyline MKMapRect intersection check an effective algorithm such as shown in How to find the intersection point between a line and a rectangle?.

Related

Detect if polygon has intersecting lines (bowtie)

I'm looking for a way to detect if a set of points/coordinates have any intersecting lines.
A little setup, I'm drawing a polygon using UIBezierPath on an overlay to a map. This all works. I'm able to reduce the map points down using a point reducing algorithm, and I'm left with a simple looking polygon that renders on my map just fine. FWIW, I'm using Google Maps SDK.
My problem is that it is possible for the user to draw a polygon with self intersecting lines (which is a problem for what I am doing). I need to be able to do one of 3 things.
Remove the intersecting points in the array. (Clip off the bow tie pieces)
Detect if my points have this bow tie (I'll just tell them to redraw a new polygon)
If possible (which I don't think it is), prevent the path from drawing the bow tie in the first place.
I mostly see the bow tie when the polygon self closes and the end point is slightly underlapping the start point. So when the polygon closes and renders into map coordinates on the map, I get a tiny bow tie that messes with an internal API.
Is there anything out there that will work using map coordinates? I've seen some fixes for regular CGPoints, but nothing that will take map coordinates. I would prefer to do this check on my polygon after it has gone through my reducer as it leaves many less points to check. Performance is an issue, and would prefer not to iterate over hundreds of points directly coming off the UIBezierPath. Any help would be appreciated.
I don't know about the Google Maps SDK or the UIBezierPath. I assume that you are given a polygon in the 2D plane and you would like to automatically detect where the polygon intersects itself (if it does).
Perhaps the easiest way to do this is checking all pairs of edges whether they intersect or not. You can check this in O(n2) time where n is the number of edges, as there are n*(n-1)/2 pairs of edges. For a given pair of edges, here are the details how to do it:
How to check if two given line segments intersect?
Nothing extraordinary but the details do require attention.
A more sophisticated algorithm is the plane sweep algorithm:
Line segment intersection, starting at slide 25
Line Segment Intersection Using a Sweep Line Algorithm

MKOverlay Vector Data Drawn Multiple Times or Clipped with drawMapRect:zoomScale:inContext

I'm using the method - (void)drawMapRect:(MKMapRect)mapRect zoomScale:(MKZoomScale)zoom inContext:(CGContextRef)context to render a vector-based map for an MKOverlay on iOS.
I can't find a good way to avoid rending all of the vector shapes multiple times without clipping them to the mapRects (tiles) sent to the above drawMapRect... method. Let me explain...
drawMapRect... gets called on the MKOverlayRenderer/View multiple times when the overlay needs to be drawn. It gets called for various small mapRect tiles concurrently. There are two kinds of vector shapes that don't work well with this way of doing things, and therefore two problems that I've yet to overcome:
A small shape that technically fits entirely within one of the mapRect tiles but for which the actual drawn rendering should extend beyond that tile's boundary. Eg, a dot is drawn larger than the actual (zero) size of the point that it represents and often has a textual label associated with it that extends well beyond the mapRect tile. In such cases, they will be clipped by the tile boundaries. Currently, I get around this by drawing the entire set of vector data for every tile (ie, every time the drawMapRect... method is called). This looks nice, but is a massive waste of resources and slows things down a lot.
A large shape that intersects many tiles will get drawn multiple times - once for each mapRect tile for which the drawMapRect... method is called. I can (partially) get around this by drawing only the shapes that intersect the passed-in mapRect tile, but then I have the problem (1) above. It is a massive waste of resources to draw a large complicated vector shape many times when it only needs to appear on the screen once.
In the end, I want to draw everything only once, and not to have things clipped to mapRect tiles. Drawing everything multiple times can really slow things down for a large and complex set of vector data.
I don't want to have to repeatedly pre-render screenfuls of the vector data every time the map is panned or zoomed. There's got to be a 'correct' way to do this, but I can't figure it out.
How should I go about this?
In particular, is there a way to avoid having the drawing into the CGContext clipped to the mapRect tile that is sent to the drawMapRect... method?

area calculation using lat/long in UIMapview

I am trying to find area of MKPolygonView object added to MapView. Apple documentation has method distanceFromLocation: to find distance between edges of MKPolygonView object. But I could not find anything to calculate area of the overlay.
Does Apple have any documented method for finding area?
Concerning the comments on the question post, the Earth is not a perfect sphere either. In fact, it's not a perfect anything, so "correct" answers aren't possible. What matters is how accurate of an approximation you need. Also, are you interested in a mean sea level type measurement, or do you want the actual contours of the ground (for example if your polygon is put over a mountain, then the same exact size polygon is put over some plains, should the result you calculate be the same or different)?
Depending on how big your polygon is, and which measurement you're looking for, a 2D approximation can be pretty accurate (the smaller the polygon, the closer you'll get). Something to keep in mind, if you want your area in something like square feet, the distance between two longitudinal lines is not constant (63 deg west and 62 deg west are closer (in feet) somewhere in Alaska than they are at the equator). You might have to do a unit conversion to handle this depending on how big your polygon is (or if your polygon could be placed anywhere). If you can't do the 2D approximation, I'm not even sure how you'd do that.
When I did this, I did the 2D approx, and I had to do the unit conversion. If that's the way you go, I can try to dig up some of my old notes and the links I used to get you started.

Best way to search a point across several polygons

I need to match a given point (lat, lon) against several polygons to decide if there is a match.
The easiest way would be to iterate over each polygon and apply the point-in-polygon check algorithm, but that is prohibitively expensive.
The next optimization that I did was to define a bounding rectangle for each polygon (upper bound, lower bound) and iteratively check the point against each bounding box (fewer comparisons as against checking all the points in the polygon).
Is there any other optimizations possible? Would a spatial index on the bound rectangle points or a geohash help?
Further optimizations:
The bounding box idea is good. Checking if a point is in a bounding box is extremely fast.
If you still need more speed, you can do more pre-calculation like this:
For each polgon create a bounding box.
Define equally sized "tiles" that cover your map.
For each tile, create a list of polygons that overlap. You can do that by first checking if the bounding box overlaps with the tile. If they do, you check if the polygon overlaps with the tile.
When searching, do this:
Determine the tile that you're in. That's a fast operation.
Now you have the list of potential polygons.
For each polygon, check if the point is in the bounding box.
if it is, check if the point is in the polygon using the more expensive algorithm that you've mentioned.
I've used this algorithm several times and it's very fast. By changing the tile size you can choose the right balance between memory footprint and performance:
Think of the extreme cases:
One huge tile that covers the entire map:
You'll get one list of all elements in your map, you'll have to check all of the bounding boxes.
Very tiny tiles (1x1 m for a map that only has a polygon per country):
You'll get a huge amount of tiles. All polygons will be split over many tiles, and each tile will only have one polygon. But, once you've figured out in which tile the point is (fast), it's almost 100% sure that there's just one polygon that needs to be checked.
You need to be somewhere in between. If you only need this once and a while, you might want to choose a low memory footprint over performance. The optimal tilesize can also depends on the homogeneity of the polygon sizes. So, there is no automatic way to calculate an optimal tile-size, and you'll just have to tweak a bit until you get it right.

how to connect points after identifying them in cvgoodfeaturesTotrack

I want to identify an object and draw a shape around it ...
I used previously the color identification but wasn't a good option since color change dramatically from place to place .. so I though why not identifying objects by features such as edges .. and I did that using this function in openCV
cvgoodfeaturesTotrack
it returns the (x,y)-coordinates of the points .. now I want to connect those points.. well not all of them but the one who are close to each other to draw a shape around the different objects. Any ideas ?
I don't think there is a free lunch in this case. You are trying to reconstruct a polygon if you only know the corner points of the polygon. There is no unique solution to this problem: you can draw all sorts of polygons through the corners. If you are certain the shape you are after is convex, then you can construct the convex span of the corner points, but the result will be horrible if you include any corners that were not part of the original object.
It seems to me that detecting corners is not the way to segment an object that is more or less delimited by lines. You probably want to try an edge detector instead, or a proper segmentation technique such as watershed.

Resources