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.
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.
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..
and after..
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.
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:
*****I do work for the company*
Related
I am using Esri web with javascript to create a heat map of tracts.
There are groups of tracts that represent one area so I want to merge and remove the bounders between them.
How can I do this?
This is How I draw the tracts:
var featureLayer = new FeatureLayer({
url: "https://services.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/USA_Census_Tract_Areas_analysis_trim/FeatureServer/0",
outFields: ["*"],
renderer: renderer,
definitionExpression: "FIPS IN (" + fips + ")"
});
Well, It seems clear that your want to create one large polygon out of too many small polygons(group of tracts).
Follow below steps to achieve this-
don't add feature layer on the map
Create an empty map with basemap and add a graphics layer on it.
query the group of tracts from the layer using esri query task and store the geometry in an array.
use esri gemetryEngine union method and pass the array to it.
union will return a big ploygon without the inner boundaries of 'group of tracts'.
create an esri graphics with new polygon symbol and union polygon geometry.
Add that graphics to the previously added graphics layer.
Feel free to shoot your further queries.
Hoping this will help you :)
I have a LeafletJS map with a GeoJSON layer that contains multiple polygons. If a user enters a latitude/longitude coordinate that falls within the GeoJSON layer, the script should retrieve the feature that contains that point and log some information about it to the console.
I can't simply use Leaflet's built-in event handling because the latitude and longitude coordinates are generated by a separate input field, not by direct interaction with the map. So my question is not a duplicate of this.
I'm looking for something similar to getFeatureContainingLatLng() in the example below:
var map = L.map('map');
var geojson = L.geoJson(myGeojson);
geojson.addTo(map);
$.on('address input changed event', function(lat, lng) {
var myFeature = geojson.getFeatureContainingLatLng(lat, lng);
console.log(myFeature.properties);
});
The plugins Leaflet.CheapLayerAt or Leaflet-pip should help. Both approaches will solve your problem, albeit they have different advantages and disadvantages specially in terms of algorithmic complexity.
I used JSON method to save Google overlays in database. For example I save a circle in the database by this code:
var shape_properties;
shape_properties.center = array_shapes_object[counter].center;
shape_properties.redius = array_shapes_object[counter].radius;
shape_properties.type = array_shapes_object[counter].type;
shape_properties.zIndex = array_shapes_object[counter].zIndex;
shape_properties.fillColor = array_shapes_object[counter].get('fillColor');
shape_properties.name = array_shapes_object[counter].name;
array_shapes_string.push(JSON.stringify(shape_properties));
I have a variable named shape_properties and I save all circle properties inside of it and then change it to string by using JSON.stringify(shape_properties) and finally save this string to database.
And when I want to draw this circle on the map, I use something similar. I mean read these string contains circle properties from database and then change it to object by using JSON.parse(array_shapes_string[counter]) and finally draw it by using this code:
newShape = new google.maps.Circle({
center:new google.maps.LatLng(array_shapes_object[counter].center.d, array_shapes_object[counter].center.e),
radius:array_shapes_object[counter].redius,
zIndex:array_shapes_object[counter].zIndex,
fillColor:array_shapes_object[counter].fillColor,
fillOpacity: 0.15,
strokeColor: '#FF0000',
strokeWeight: 1
});
All are OK yet. But I have a big problem.
Look at this line:
center:new google.maps.LatLng(array_shapes_object[counter].center.d, array_shapes_object[counter].center.e),
This is the center of circle contains latitude and longitude and it is saved in database like this:
"center":{"k":32.9372338139709,"A":50.91888427734375}
And all properties are saved in database like this:
{"users":"user1,","center":{"k":32.9372338139709,"A":50.91888427734375},"redius":25644.7738046513,"type":"circle","zIndex":2,"fillColor":"#FF0000","name":"Circle"}
My problem is exactly this:
Sometimes center of circle is saved in database by k and A like:
"center":{"k":32.9372338139709,"A":50.91888427734375}
But sometimes else it will save with d and e instead of k and A like this:
"center":{"d":32.9372338139709,"e":50.91888427734375}
And when I read it to draw the circle it will show me an error. I'm sure this problem related to Google maps v3 and it seems they sometimes change the name of variables. How can I fix it?
You can't store these properties, the names of these properties(that represent google.maps-class-instances like LatLng or LatLngBounds) are not consistent.
You'll need your own format/methods to be able to store & restore these data(fetched via the methods provided by the API, e.g. lat() and lng() for a LatLng )
See How to save a Google maps overlay shape in the database? for a possible solution
Is there some library for node.js or javascript in general that provides a function to check if a coordinate is in a geojson multipolygon?
I'm trying to create a small HTTP API that tells me which multipolygons (representing countries, counties, cities, etc.) contain a given coordinate.
I thought that I'll hold a list of all multipolygons & their bounding-box in memory and then first check for each polygon if its bounding box cointains the coordinate. If yes, then it'll check if the coordinate is in the multipolygon itself.
I know there's a library called "clipper" that got ported to javascript, but it seems that the library does not provide a simple "pointInPolygon" function, even if the library itself is very powerful.. Is it still possible with this library?
Additionally, I've found another library called "geojson-js-utils" but it does not seem to support multipolygons (at least it's not mentioned there)
I've found some other libraries that can check if a point is in a polygon, but I don't know how to use them to check if a point is in a multipolygon.
Any hints?
In newest Clipper there is an efficient PointInPolygon function. It uses algorithm The Point in Polygon Problem for Arbitrary Polygons by Hormann & Agathos.
The documentation of Javascript Clipper's PointInPolygon function says:
ClipperLib.Clipper.PointInPolygon()
Number PointInPolygon(IntPoint pt, Path poly)
Returns 0 if false, -1 if pt is on poly and +1 if pt is in poly.
Usage:
var poly = [{X:10,Y:10},{X:110,Y:10},{X:110,Y:110},{X:10,Y:110}];
var pt = new ClipperLib.IntPoint(50,50);
var inpoly = ClipperLib.Clipper.PointInPolygon(pt, poly);
// inpoly is 1, which means that pt is in polygon
To test multipolygon, you can traverse subpolygons and check them using PointInPolygon.
I am getting line latitude & longitude as
LINESTRING(1491215.4689647 6893983.2031826,1494163.0718675 6894785.7919795)
after seeing this solution.
how to get points return from OpenLayers.Control.DrawFeature
Now what I want to do is that I want to display start point & end point on my web page.
So how can I extract latitude & longitude from here so that I can show it in my page.
If your linestring is already in OpenLayers, there is no reason to convert it to WKT. Linestring geometry contains array of Points. You can access components of geometry in several ways, for example:
drawControls[key].events.register('featureadded', drawControls[key], function(f) {
// First point
var firstPointGeom = f.feature.geometry.components[0].clone();
// Last point
var secondPointGeom = f.feature.geometry.components[f.feature.geometry.components.length - 1].clone();
// Now you got geometries, let's create features from them...
var firstPointFeat = new OpenLayers.Feature.Vector(firstPointGeom);
var secondPointGeom = new OpenLayers.Feature.Vector(secondPointGeom);
yourVectorLayer.addFeatures([firstPointFeat, secondPointGeom]);
});
Pay attention - this works with LineStrings. Probably it's not necessary to go into detail about clone(), it's up to particular use case, whether you need it, or you can use just var firstPointGeom = f.feature.geometry.components[0];
Thats WKT format, you're looking at. You'll potentially need to reproject those coordinates to the target projection if they are not in the same projection. After than, you should be able ot ask openlayers for the points of any given geometry using the base geometry functionaily. Get the point array from the linestring instance and iterate over it. Make sure you know the right coordinate order for your projection / data model.
Hope that helps!