I'm developing the open-source JavaScript plugin for Waze -- well-known free GPS navigator -- specifically for online editor. The idea of this userscript is to make it possible to quickly select large uniform colored map areas to convert them to landmarks.
So far I've successfully implemented the tool you would call "Magic Wand" in graphic editors like Photoshop: user clicks somewhere on the map (say, on the lake or forest) and script selects whole area covered by same color and creates a polygon for landmark.
Everything works great except that I am using convex hull algorithm to obtain the... well... convex hull :) That is: the polygon connecting the most outer points of the found points cloud.
But as everyone understand only few landmarks have a convex shape while most of real world objects have a polyline shape with concave areas. On the picture above you can see that the area has few sharp edges and a farmfield in the right bottom corner covered by convex hull -- that's wrong.
I was Googling for suitable algorithm and digging through math papers but still have no luck finding one. The most popular question about concave hulls here on Stackoverflow refers to Alpha-shapes along with Delaunay triangles. Though I don't understand how to use it in case: all points are connected to each other forming a continuous polyline thus it seems that I cannot find suitable alpha-radius as even circle with radius equal to 1 pixel with be alpha-exposed.
Any ideas how to archive the goal of building a concave hull will be much appreciated! May be I am moving in a wrong direction and need to look at bitmap vectorization algorithms?
Alpha shapes is defined by finding the delaunay triangulation of a set of points and then delete edges that exceed alpha. You need the delaunay triangulation but not the circles. It's also works with lines. To calculate the shape with JS you can use TopoJSON or try this answer:Calculate bounding polygon of alpha shape from the Delaunay triangulation. You can also try my php package http://concavehull.codeplex.com/.
You can read how to implement concave hull algorithm in this paper. The basic idea is to build the convex hull and flex (concave) edges inward.
There is JavaScript implementation of this algorithm: hull.js.
Related
Creating a map similar to the one found here:
https://www.plantmaps.com/interactive-california-2012-usda-plant-zone-hardiness-map.php
Have all the data needed.
Create polygons around each one without distance inbetween. No overlapping or similar.
Drawing it all by hand on geojson.io, seems impossible.
I want to create polygons around each [point] and make sure there is no distance between them.
What you're describing here is a tessellation. Depending on your data, you might opt for a regular tessellation (i.e. creating a grid of squares or hexagons, paying a modicum of attention to the units of your coordinate system) or the well-known-among-GIS-people Voronoi tessellation. Note that a Voronoi tessellation created over a regular grid of points will result in a regular grid of polygons.
There are plenty of tools for Voronoi tessellations. For javascript and GeoJSON, my tool of choice would be turf.js's voronoi module.
Here are some things to consider:
creating polygon from a point is simple enough. For example you use the point as the center of a regular polygon and devide 2PI by the number of sides and step through the points to create the polygon. But, what is the radius? That depends on the projection you are using. I happen to use OpenLayers and really like this map control. It's default projection it EPSG:3857. So, the coordinates are already in meters - so easy. But if your points are in long/lat then you have to do some math. it may be easier to transform to a different projection temporarily. An opensource library that is really nice for gis calculations if you need one is Turf.
You mentioned also about having non-overlapping polygons? Well, in this case you will have a lot of gaps if you use regular polygons. To have non-overlapping polygons with, as you put it no distance between them is an interesting constraint. Now you are dealing with different shaped polygons. And an algorithm for handling that is pretty intense. I know that MapInfo GIS has a feature for adjusting polygons to be non-overlapping. But, in a JavaScript environment with GeoJSON, you are probably talking about server side logic for this.
That map you are looking at looks like it is using Leaflet with svg overlays.
I am trying to develop a web application that uses 'Google Map' (JavaScript API).
The user should be able to draw a polygon on the map, and then the system calculates the length of all roads on that polygon.
I can draw the polygon on the map, but I don't know how to calculate the length of roads that are inside the polygons.
How can I do this?
I am using 'ASP.Net MVC' and I am able to send the polygons data to the server if it is easier to calculate it in C#.
If you are calculating the length of the sides of the polygon, that is much easier, as the sides are straight lines from one corner to another. You will need to declare a point of origin, (0,0), then find where each of the corners end, then calculate the length of that single side of the polygon using the distance formula, (that square root formula from middle school that we all loved so much): http://www.mathwarehouse.com/algebra/distance_formula/index.php
If instead, you are trying to calculate the length of the individual roads that fall within the polygon. This would be much more tricky, as there are not very many roads that are perfectly straight lines. You'll need to use the arch length formula: http://tutorial.math.lamar.edu/Classes/CalcII/ArcLength.aspx
Both formulas are easy to use, but the difficult part is setting up the equations for each of the lines. The curved lines will be much more difficult as you will need to somehow graph the roads using equations. Which depending on how Google Map's API works, you may have to get creative with you mathematical logic.
I would be interested in coding this with you. Do you have a GitHub repository?
I'm looking for an algorithm or tried & tested method for analyzing irregular polgygons and reducing them to primitives (squares, rectangles, trapeziums). A way of recurrsively looking over shapes to determine the best fit for regular polygons.
see image blow
The black shapes are the irregular polygons and the blue depicts the desired regualar, which fits inside. The left example should be straight forward but that's because it's a case of finding the a rectangle that can fit in the largest shape. The polygons will be of an undetermined size (but let's say they have less then 32 sides) What I'm hoping for is to be able to break up polys into several regualar ones - which is where I'm a little lost.
Sadly, I've no code at this point as I'm stuck to know the best way forward. The script will be done in pure JavasScript. This isn't homework :)
First of all, you need to check whether your polygon is convex or concave. If it is the latter, then you need to view it as several convex polygons "put together" and handle them separately. (It is easy to your mind to imagine a large pair of scissors which cuts the polygon into several smaller polygons). When this is done, you either have a single polygon, or several polygons.
For each polygon, calculate the gravity point of the polygon and (P(i), P((i + 1) mod n), G) will form a trivial form, a triangle. These triangles will solve your problem.
If you need shapes with four angles, then four consecutive points form a shape of four angles. But this approach might leave you with a smaller polygon with lesser number of angles in the middle of the main polygon, which will have to be handled.
I am writing code that will build an oriented bounding box (obb) tree for a (not necessarily convex) polygon in 2 dimensions.
So far, I'm able to find the area-minimal obb of a polygon by finding its convex hull and using rotating calipers on the hull.
The picture below is an example of this. The yellow-filled polygon with red lines and red points depicts the original polygon. The convex hull is shown in blue with black lines and the obb is shown as purple lines.
(Edit) As requested: Interactive Version - tested only in chrome
Now I want to extend my code to build an OBB tree, instead of just an OBB. This means I have to cut the polygon, and compute new OBBs for each half of the polygon.
The recommended way to do this seems to be to cut the polygon by cutting the OBB in half. But if I cut the obb through the middle in either of its axes it looks like I would have to create new vertices on the polygon (otherwise how do I find the convex hull of that partition?).
Is there a way to avoid adding vertices like this?
If not, what is the easiest way to do it (with respect to implementation difficulty)? What is the most runtime-efficient way?
Here's an example of a concave polygon that we want to create an OBB tree for:
In order to split it into a new set of concave polygons, we can simply cut our current polygon by cutting the bounding box down the middle and adding new 'intersection' vertices as appropriate:
:
This can be done in O(vertices) time because we can simply iterate through all of the edges, and add an intersection vertex if the edge crosses the red splitting line.
The polygon can then be divided in terms of these intersection vertices to get a new set of smaller (but still possibly concave) polygons. There will be at least two such polygons (one per side of the red line) but there may be more. In this next picture, the new polygons have been colored for emphasis:
Recursively computing the oriented bounding boxes for these smaller polygons gives the desired result. For example, here are the boxes from recursion depth 2:
Hopefully this is clear enough to help someone who's struggling the same way I was!
I'm not really sure this is what you need without further context, but here goes...
Subdividing a concave polygon into a set of convex polygons
In my comment above I suggested recursively subdividing the concave polygon in order to obtain a set of convex polygons instead. One (common) approach is the following:
If the polygon is convex, stop. (add the polygon to an array, I suppose)
Select an unmarked edge of the polygon. Mark the edge.
Split the polygon across the edge (actually: the infinite line coinciding with the edge).
Recursively repeat this algorithm for both result polygons (if non-empty).
Note: This is exactly how a BSP tree is built. Except in the algorithm above we're not building tree nodes and storing polygons in them. Maybe a BSP-only solution would be a solution to your problem as well (instead of using OBBs).
Testing a polygon for convexity (step 1)
For each edge, classify each vertex as on, in front or behind the edge. All vertices should be on or in front of the edge. If not (at least 1 vertex behind the edge), the polygon is concave. For details on the 'classifying' part, see my answer to a different question, which does this as well.
The rest
Once you have the list of convex sub-polygons, you could generate OBBs for them as you've done in your original post. You would not have an OBB tree though...
With the subdividing, you are adding vertices (a concern in your question). Depending on your application you may not need to use the subdivided polygons though: If you were to use a BSP tree and only needed simple collision you'd just traverse the tree and do some point/edge classifications and not deal with any polygon vertices.
Anyway, not really sure what to recommend further since I don't know what you want your application to do, but hopefully this is of some help.
Edit: I just realized that maybe this is what you want to do: Build a BSP tree and generate OBBs for each node, from root to leaf nodes. So the root node OBB would contain the entire concave polygon, and leaf nodes only convex sub-polygons. I remember the original Doom engine does something similar (except with axis-aligned BBs).
I have an exercise in problem solving for those who like that kind of thing. I'm working on a mapping application that uses Google Maps. A user first enters a series of coordinates and a "radius". The user then requests either a line or an area be plotted. The plots are taking place on Google Maps using polygons. In other words, given the blue line (or area) defined by the blue points and a distance, calculate the red points and draw the red polygon where the edges are of the given distance away from the user-provided edges:
I have managed to get this to work in "most" situations by calculate forward and reverse bearings, then finding the points with a bearing 90 degrees off these in the appropriate direction. For the arcs I just calculated the location points along that arc at 5 degree intervals. In the case of the inside of an acute angle, I determine where the two lines intersect and use that point, but this fails miserably sometimes when the cross-track distance at that point is greater than the radius that was provided.
I'm hoping someone knows of an easier way? Maybe one that works all the time regardless of the ratio of the cross-track to radius distances? Or maybe a library already exists to do this?
I hope what I'm trying to do makes sense... It's hard to put in words. Maybe if I had the words a search would have been helpful even.
Well, the answer turned out to be simpler than I thought. It took me back to a lesson I was taught during CompSci 101 almost 15 years ago:
"Use existing libraries whenever possible."
Once I found out (via googling), that what I'm looking for isn't called an "offset" or a "scale" but is actually called a "buffer" in GIS computing, it was simple. There are some great libraries like Clipper by Angus Johnson that can do it, but I wanted something JavaScript specific.
That brought me to arcGIS's GeometryService. They even have a Google Maps version but it's only API v2. Luckily, there's an official, unsupported version I found via the arcGIS forums that works with GMaps API v3.
So, my solution was to use that, called arcgislink, and it's buffer function works perfectly with Google Maps LatLng points, Google Maps Polygons/Polylines, and any of the standard arcGIS types. Anyone else needing to do this with Google Maps, I highly recommend looking at their libraries.
In the general setting, this problem is quite difficult because it is a global one (you cannot just solve locally, at each polygon vertex but just handling the two incoming edges). And also uneasy because it involves circular arcs.
There is a solution which is quite unefficient but safe: assume you have a general polygon union algorithm (like http://gvu.gatech.edu/~jarek/graphics/papers/04PolygonBooleansMargalit.pdf); you will add inflated versions of every edge one by one (every time a rectangle and two half-disks approximated by polygons), together with the original polygon for closed shapes.
For the sake of efficiency, you can design a "sweepline" algorithm that works by slicing the plane with horizontal lines at every "event point", i.e. segment/arc endpoints and arc apexes, so that the configuration in every slice is simpler. Do you see what I mean ?
BTW, what do you call the "cross-track distance" ?