4

I have to allow a user to input multiple zip codes, retrieve the latitude and longitude from a database and then build a huge polygon that encompasses them.

I'm coding in Java and using Google Maps API V3. I have no problem doing a single zip code build. But upon adding more zip codes the polylines that are generated go hay-wire and distort the polygon, as pictured below. fussy google map polygon

What do I need to change in my code to make all these smaller polygons into one larger one? I've scoured Google for answers and all I've managed to come across is building each zip code's polygon individually but that still won't give me a end result of a larger, single polygon.

Currently, after the zip codes are inputted the program collects the lat and long points from the database and feeds them into a giant array of arrays (a String[][] to be exact), which is then passed the the html and javascript to generate the resulting polygon.

My javascript is highly similar to the GoogleMaps API V3 simple polygon example:

function clearHello(coords1){
coords = coords1
var triangleCoords = new Array();
var l = coords.length;
for (var x = 0; x < l; x++){
triangleCoords[x] = new google.maps.LatLng( coords[x][0], coords[x][1]);
}
// Construct the polygon.
bermudaTriangle = new google.maps.Polygon({
paths: triangleCoords,
strokeColor: '#FF0000',
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: '#FF0000',
fillOpacity: 0.35
});
bermudaTriangle.setMap(document.map);

Suggestions? Is there a code technique out there that will take my giant array and then remove the interior points that appear to be the cause of this distortion?

EDIT: Wondering about a different approach, does anyone know of a way to remove the interior lines that creating the bizarre trapezoid thing so that the zipcode polygon can fill in properly? I know I can make them transparent, but that doesn't stop the distortion of the polygon. Also simply managing it as a few polygons that I populate won't work as this program needs to be able to handle up to 200 zip codes worth of coordinates at a time.

senex_subconscious
  • 221
  • 2
  • 6
  • 14
  • I finally got it figured out and overhauled my answer to demonstrate how you can use two different third party JS libraries to perform a Dissolve in a Google Maps context. I think doing a big analytical operation like this is a bit nasty in a browser application, and I'd still recommend involving PostGREsql/PostGIS if you anticipate doing alot of geographic queries and manipulations, but this should certainly accomplish your goal using the preferred technologies. – elrobis Jun 06 '14 at 19:20

3 Answers3

8

It sounds like you're wanting to remove shared boundaries and create a kind of macro object. In the land of Geographic Information Systems (GIS), this sort of operation is called known as "Dissolve". You can combine two 3rd-party libraries to do what you want exclusively in JavaScript code.

How to do a GIS Dissolve in JavaScript

You can combine both the Wicket and the JavaScript Topology Suite (JSTS) libraries to perform a Union/Dissolve operation and derive a single polygon geometry with a united outer boundary.

In simple terms, Wicket will handle going to and from your Google Maps Polygon objects to Well Known Text (WKT) geometry expressions, and the JSTS can then do a union/dissolve operation using the WKT.

Preliminary steps: Download the two libraries and reference them in your project.

1) First download the JSTS library, unzip it, browse into the lib folder, and include the two lib files (javascript.util.js, and jsts.js) in your project. I copied mine into a separate jsts folder and referenced them in my project like this..

<script type="text/javascript" src="jsts/javascript.util.js"></script>
<script type="text/javascript" src="jsts/jsts.js"></script>

2) Next download the Wicket library, unzip it, and include wicket.js and wicket-gmap3.js in your project. Similarly, I copied mine into a separate wicket folder and referenced them like this..

<script type="text/javascript" src="wicket/wicket.js"></script>
<script type="text/javascript" src="wicket/wicket-gmap3.js"></script>

Use Wicket to get the Polygon WKT geometries, then use JSTS to perform a Dissolve operation.

3) Unite these two libraries to get Well Known Text geometries from Wicket, and perform a Dissolve operation with JSTS.

My demo assumes two Google polygon objects were already instantiated and were passed into the method—polygon1 and polygon2. Obviously this is intended to be a simple example, so you'll need to modify it for more elaborate operations.

function DissolveTwoGeometriesWithJSTS(polygon1, polygon2)
{
    // Instantiate Wicket
    var wicket = new Wkt.Wkt();

    wicket.fromObject(polygon1);  // import a Google Polygon
    var wkt1 = wicket.write();    // read the polygon into a WKT object

    wicket.fromObject(polygon2);  // repeat, creating a second WKT ojbect
    var wkt2 = wicket.write();

    // Instantiate JSTS WKTReader and get two JSTS geometry objects
    var wktReader = new jsts.io.WKTReader();
    var geom1 = wktReader.read(wkt1);
    var geom2 = wktReader.read(wkt2);

    // In JSTS, "union" is synonymous with "dissolve"
    var dissolvedGeometry = geom1.union(geom2);

    // Instantiate JSTS WKTWriter and get new geometry's WKT
    var wktWriter = new jsts.io.WKTWriter();
    var wkt = wktWriter.write(dissolvedGeometry);

    // Reuse your Wicket object to ingest the new geometry's WKT
    wicket.read(wkt);

    // Assemble your new polygon's options, I used object notation
    var polyOptions = {
        strokeColor: '#1E90FF',
        strokeOpacity: 0.8,
        strokeWeight: 2,
        fillColor: '#1E90FF',
        fillOpacity: 0.35    
    };

    // Let wicket create a Google Polygon with the options you defined above
    var newPoly = wicket.toObject(polyOptions);        

    // Now I'll hide the two original polygons and add the new one.
    polygon1.setMap(null);
    polygon2.setMap(null);

    newPoly.setMap(map);
}

Here's what basically happened. Before executing the code..

enter image description here

and after..

enter image description here

Community
  • 1
  • 1
elrobis
  • 1,512
  • 2
  • 16
  • 22
  • I just found the PostGREsql library, but I'm not sure about how I'd go about implementing it, if I even can, I'm currently utilizing Java's built in database with Derby. I'll look at both your recommendations and see which one I can wrangle into working and get back to you. – senex_subconscious Jun 05 '14 at 15:49
  • @senex_subconscious, getting started with PostGREsql/PostGIS is non-trivial, especially if your webhost won't allow PostGIS extensions. I use [WebFaction](https://www.webfaction.com/), and they do. Once everything is installed, you'll need to know basics about GIS data, getting it in and out of PostGIS, etc. Start by looking into that [JavaScript Topology Suite](https://github.com/bjornharrtell/jsts) from the first GIS.SE link. Also, get familiar with Well Known Text for Polygon geometries. [..this might be useful](http://gis.stackexchange.com/questions/63697/google-maps-polygon-to-wkt). – elrobis Jun 05 '14 at 16:02
  • It seems no matter which option I go with I'm still going to have to break the massive array down into the individual polygon arrays. Or somehow get the PostGREsql/PostGIS working. – senex_subconscious Jun 05 '14 at 18:33
  • Yes, most likely you'll need to iterate over the vertices of each Google Maps polygon and translate them to Well Known Text geometries. As I expected--based on [this buffer example](https://github.com/bjornharrtell/jsts/blob/master/examples/buffer.html) from the JSTS library mentioned above--the library appears to operate on Well Known Text geometry expressions. – elrobis Jun 06 '14 at 13:39
  • @senex_subconscious, seeing an opportunity here, I added a blog post describing how to convert from Google Polygon objects to their equivalent Well Known Text (WKT) geometry expressions. If I can figure out how to do a dissolve using JSTS, I'll return and update my answer. But WKT is going to be important even for PostGREsql/PostGIS, so you might want to give this a look. Hopefully it saves you some time. http://cartometric.com/blog/2014/06/06/convert-google-maps-polygon-api-v3-to-well-known-text-wkt-geometry-expression/ – elrobis Jun 06 '14 at 15:51
  • Wow! Great for expanding on WKT too, as I happen to be using that as well in part of my program! Great and in-depth, thanks so much for your time and help! – senex_subconscious Jun 06 '14 at 20:41
  • @senex_subconscious, no problem. I'm glad it'll help. Please note I made one last revision to this code. I forgot to reuse Wicket in the last step to go from WKT to a Google Polygon, so I jumped back in to fix it. Originally I didn't use Wicket, but a home-rolled solution. However I think it's better to use Wicket throughout since it handles more geometry cases and has been released as a polished API. Plus, the code looks alot cleaner this way. :) – elrobis Jun 06 '14 at 21:04
0

You can try topojason javascript. A good start is also a concave hull. I have wrote a concave hull php class @ phpclasses.org. It takes a set of points and find the concave hull with the concave hull algorithm. Basically it's a delaunay triangualation and you delete the longest edges. You can also read my answer here:Calculate bounding polygon of alpha shape from the Delaunay triangulation.

Community
  • 1
  • 1
Micromega
  • 12,486
  • 7
  • 35
  • 72
0

The solution is to use GeoJson to represent what you want and there is a API for that, so you don't have to worry about the backend or any distortion in the polygon(s), as pictured below.:

here: www.boundaries-io.com

example query:

/rest/v1/public/boundary?zipcode=30044,30043,30045'

you can also query for multiple counties,cities,etc in one line of code.

simple in java script: https://developers.google.com/maps/documentation/javascript/datalayer#sample_geojson

... map.data.loadGeoJson('.../rest/v1/public/boundary?zipcode=30044,30042,30045''); ...

results gives this, with additional queryable information per zipcode: enter image description here

*****I do work for the company*

Jeryl Cook
  • 989
  • 17
  • 40