I am trying to use the containsLocation from the Google geometry library, but can't get it to work...
var point = new google.maps.LatLng(51.331, 3.538);
var poly = [
new google.maps.LatLng(51.401818509550615, 3.547626782103622),
new google.maps.LatLng(51.397574277049365, 3.563607598960424),
new google.maps.LatLng(51.398540111384975, 3.567880788749134),
... // it is a lot bigger
];
if(google.maps.geometry.poly.containsLocation(point, poly) == true) {
alert("yes");
}
The Javascript console gives an error, but that points to a function in Google's lib. So I assume the problem should lie somewhere in this function.
Oke, stupid me
I was wrong using all the coords as an array, I had to use the created polygon object.
var polyOptions = {
...
}
draw = new google.maps.Polygon(polyOptions);
draw.setMap(map);
if(google.maps.geometry.poly.containsLocation(point, draw) == true) {
alert("yes");
}
i had the same problem ([object Object]), I could solve that creating the polygon variable like that:
draw = new google.maps.Polygon({paths:polyOptions});
Then the problem disappeared.
Related
I have added Google Maps for Flutter
i know how to add a marker as it is given clearly in there examples
MarkerOptions _options = new MarkerOptions(
position: LatLng(
driver_lat,
driver_lng,
),
infoWindowText:
const InfoWindowText('An interesting location', '*'));
Marker marker = new Marker('1', _options);
//Adding Marker
googleMapController.addMarker(_options);
And i am removing the marker like below
googleMapController.removeMarker(marker);
for adding the marker it is taking MarkerOptions object as a parameter but for removing the marker it is asking for Marker object as parameter and my removing marker code is not working.
i am getting the below error
Failed assertion: line 201 pos 12: '_markers[marker._id] == marker': is not true.
There are two ways to do this, one is via clearMarkers() Method
mapController.clearMarkers();
Another one is via targeting each marker returned by mapController.markers
mapController.markers.forEach((marker){
mapController.removeMarker(marker);
});
2020 answer:
.clearMarkers() has been deprecated as now each Marker is a Widget stored in a map. The correct way to clear all of the markers now on your Google Map is to set the state of of your marker Map to an empty map.
e.g.
...
onPressed: () {
setState(() {
gMapMarkers = {};
});
}
....
Use clearMarkers(). It will clear all markers in your map. So try googleMapController.clearMarkers();
I've came across this issue myself with the google_maps_library and the main cause of this issue '_markers[marker._id] == marker': is not true. is the fact that all GoogleMapsController methods return a Future, so this error is, let's say a concurrency issue since the method cals are async.
The correct way to add/remove a marker would be:
_testRemoveMarker() async {
Marker marker = await _mapController.addMarker(...markerOption..);
_mapController.removeMarker(marker);
}
_clearMarkersAndRead() async {
_mapController.clearMarkers().then((_) {
//TODO: add makrers as you whish;
});
}
So, if you do any operations with the markers add/remove/update, you should be sure that the previous operation that involved markers is completed.
If anyone still struggling with removing a specific marker try this method;
MarkerId id = MarkerId("Pickup");
//markers[id] = {} as Marker; clear all markers
markers.removeWhere((key, value) => key == id); //clear a specific marker
I am currently working with a KML-file via this plugin: https://github.com/sushihangover/SushiHangover.Android.Maps.Utils
The KML-file i am using gets added succesfully via this codesnippet:
var kmlLayer = new KmlLayer(googleMap, Resource.Raw.campus, Android.App.Application.Context);
kmlLayer.AddLayerToMap();
MoveCameraToKml(kmlLayer);
When it's added I run my MoveCameraToKmlfunction where I try to get the lat, lng of every point but I get a crash on this row foreach (LatLng latLng in ((KmlLineString)geo).GeometryObject); with the errormessage: object reference not set to an instance of an object
void MoveCameraToKml(KmlLayer kmlLayer)
{
//Retrieve the first container in the KML layer
var container = (KmlContainer)kmlLayer.Containers.Iterator().Next();
//Retrieve a nested container within the first container
container = (KmlContainer)container.Containers.Iterator().Next();
//Retrieve the first placemark in the nested container
var placemark = (KmlPlacemark)container.Placemarks.Iterator().Next();
var geo = placemark.Geometry;
if (geo is KmlLineString)
{
foreach (LatLng latLng in ((KmlLineString)geo).GeometryObject) //object reference not set to an instance of an object
{
System.Diagnostics.Debug.WriteLine(latLng);
}
}
}
Any idea why this is giving me a crash? I am following the example of the nuget I downloaded above.
The idea is to store the lat, lngs in a list and use a PolylineOptions to create routes.
That Google sample (MoveCameraToKml) assumes that you are using their Campus KML example. Since the KML you use will be unique to your app, you will need to review your KML/XML elements and write your code to suit your usage.
Here is an example using their Grand Canyon KML LineString hiking path:
https://developers.google.com/kml/documentation/kml_tut#paths
So looking at the KML, we will need to:
Get the first Container
Get the first Placemark in that container
Check if it has geometry and is a KML LineString
Obtain the LatLng array via GeometryJavaObject()
Use those Latlngs to build a camera viewport and move to it.
"Drive" the camera along those individual points
Grand Canyon KmlLineString Example:
void MoveCameraToKml(KmlLayer kmlLayer)
{
var container = (KmlContainer)kmlLayer.Containers.Iterator().Next();
var placemark = (KmlPlacemark)container.Placemarks.Iterator().Next();
if (placemark.HasGeometry && placemark.Geometry is KmlLineString)
{
var lineString = placemark.Geometry as KmlLineString;
var latlngArray = lineString.GeometryJavaObject() as Java.Util.ArrayList;
using (var builder = new LatLngBounds.Builder())
{
foreach (LatLng latLng in latlngArray.ToEnumerable())
{
builder.Include(latLng);
}
googleMap.MoveCamera(CameraUpdateFactory.NewLatLngBounds(
builder.Build(), mapFragment.View.Width, mapFragment.View.Height, 1)
);
}
Task.Run(async () => // run camera along KmlLineString
{
foreach (LatLng latLng in latlngArray.ToEnumerable())
{
await Task.Delay(2000);
RunOnUiThread(() => googleMap.MoveCamera(CameraUpdateFactory.NewLatLng(latLng)));
}
});
}
}
Geometry can be KmlPoint, KmlLineString, KmlPolygon or a KmlMultiGeometry.
var geo = placemark.Geometry;
if (geo is KmlPolygon) then {
var poly = (KmlPolygon)geo;
}
i'm using OpenLayers to display custom OSM maps on my website.
I've some points to respect: the map have to be fix (meaning that we can't drag it or zoom it).
I have a problem with the zoom, i can't manage to disable zoom with the mouse. Does anyone has a tip?
map = new OpenLayers.Map('map');
map.events.remove("move");
map.events.remove("movestart");
map.events.remove("moveend");
map.events.remove("zoomend");
map.events.remove("mouseover");
map.events.remove("mouseout");
map.events.remove("mousemove");
map.events.remove("zoomstart");
var nav = new OpenLayers.Control.Navigation({
defaultDblClick: function(event) { return ; }
});
map[index].addControl(nav);
Also, if someone has a tip to remove all Navigation events easier than that, it would be greatly appreciated.
Disable the default controls on your map by passing an empty array:
var map = new OpenLayers.Map('map', { controls: [] });
For OpenLayers3 the interaction array also needs to be empty.
var map = new ol.Map({
controls: [],
interactions: []
});
Simplifying approach of Mahdi results in
var i, l, c = map.getControlsBy( "zoomWheelEnabled", true );
for ( i = 0, l = c.length; i < l; i++ ) {
c[i].disableZoomWheel();
}
This way disabling zoom on mouse wheel doesn't require to customize options on constructing map e.g. by creating map without any control (though this was somewhat requested by Lght). In addition re-enabling zoom works equivalently.
In addition, by searching controls matching enabled property zoomWheelEnabled rather than class name it's supporting custom controls derived from OpenLayers.Control.Navigation.
You can do the following also:
map = new OpenLayers.Map({
// options here ...
}
var Navigation = new OpenLayers.Control.Navigation({
'zoomWheelEnabled': false,
'defaultDblClick': function ( event ) {
return;
}
});
map.addControl(Navigation);
var NavigationControls = map.getControlsByClass('OpenLayers.Control.Navigation')
, i;
for ( i = 0; i < NavigationControls.length; i++ ) {
NavigationControls[i].disableZoomWheel();
}
Found here.
For other options like disable dragging, you can take a look at the documentation and customize the above code.
Here is another easy way to restrict the zoom event based on some logic. Because OpenLayers doesnt provide a 'beforezoom'
map.zoomToProxy = map.zoomTo;
map.zoomTo = function (zoom,xy){
// if you want zoom to go through call
map.zoomToProxy(zoom,xy);
//else do nothing and map wont zoom
};
How this works:
For any kind of zooming activity, OpenLayers API ultimately calls the function called zoomTo. So before overriding it, we copy that function to a new function called 'zoomToProxy'. The we override it and add our conditional zoom logic. If we want the zoom to happen we just call new proxy function :)
You could reset the controls array and then add the Zoom and TouchNavigation to it.
var map_controls = [];
map_controls.push( new OpenLayers.Control.Zoom() );
map_controls.push( new OpenLayers.Control.TouchNavigation() );
var map = new OpenLayers.Map({
div: "map",
controls: map_controls
});
Hope it helps ! :)
I am looking to find a way of checking if a point exists inside a polygon in Google Maps v3 (JavaScript). I've searched everywhere and the only solutions I have found so far have been to do with getting the bounds of the polygon, but the code shown seems to just create a rectangle and keeps expanding its surface area to include all relevant points.
By the way, the reason I can't just use a big square i.e. getting a polygons bounds, is that I have bordering polygons on the map and they can not expand into each other's territory.
EDIT
Following on from the reply below, I have tried implementing the example code using one of my existing polygons but it is just saying that it is not defined and I can't figure out why.
Here is my declaration:
myCoordinates = [
new google.maps.LatLng(0.457301,-0.597382),
new google.maps.LatLng(0.475153,-0.569916),
new google.maps.LatLng(0.494379,-0.563049),
new google.maps.LatLng(0.506738,-0.553436),
new google.maps.LatLng(0.520470,-0.541077),
new google.maps.LatLng(0.531456,-0.536957),
new google.maps.LatLng(0.556174,-0.552063),
new google.maps.LatLng(0.536949,-0.596008),
new google.maps.LatLng(0.503991,-0.612488),
new google.maps.LatLng(0.473780,-0.612488) ];
polyOptions = {
path: myCoordinates,
strokeColor: "#FF0000",
strokeOpacity: 0.8,
strokeWeight: 2,
fillColor: "#0000FF",
fillOpacity: 0.6 };
var rightShoulderFront = new google.maps.Polygon(polyOptions);
rightShoulderFront.setMap(map);
and here is where I am checking for the point:
var coordinate = selectedmarker.getPosition();
var isWithinPolygon = rightShoulderFront.containsLatLng(coordinate);
console.log(isWithinPolygon);
But it keeps coming up with the error: Uncaught ReferenceError: rightShoulderFront is not defined
One algorithm to solve this is ray-casting. See an explanation here.
And you can find code implementing this for the Google Maps JS API V3 here.
HTH.
You can do this quite simply with Google maps geometry library.
First be sure to add the google maps geometry library.
<script type="text/javascript" src="//maps.googleapis.com/maps/api/js?libraries=geometry&sensor=false"></script>
Then, define your polygon
var rightShoulderFront = new google.maps.Polygon({
paths: myCoordinates
});
rightShoulderFront .setMap(map);
I'm going to add an event listener to handle a 'click' event, but you can adapt to fit your needs
google.maps.event.addListener(rightShoulderFront , 'click', isWithinPoly);
Create a function to handle our click event an check if coordinate exists within polygon using Google's geometry library
/** #this {google.maps.Polygon} */
function isWithinPoly(event){
var isWithinPolygon = google.maps.geometry.poly.containsLocation(event.latLng, this);
console.log(isWithinPolygon);
}
You have a very good example of containsLocation() method in Google Maps API documentation.
You should have a look about the Gmaps.js library. It has a quite simple method about geofence.
var coordinate = new google.maps.LatLng(0.457301,-0.597382);//replace with your lat and lng values
var isWithinPolygon = google.maps.geometry.poly.containsLocation(coordinate, yourPolygon);
Dont forget to include the library in your googleapis script. Read more...
<script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry"></script>
The example and implementation do not take into account that a polygon can cross the 180 degrees boundary.
The implementation does take it into account (implicitly) in the bounding box check, but the polygon check fails.
I have used the same thing and working fine and its offline code I have written this code in PHP you can write it any programming language.
class pointLocation {
var $pointOnVertex = true; // Check if the point sits exactly on one of the vertices?
function pointLocation() {
}
function pointInPolygon($point, $polygon, $pointOnVertex = true) {
$this->pointOnVertex = $pointOnVertex;
// Transform string coordinates into arrays with x and y values
$point = $this->pointStringToCoordinates($point);
$vertices = array();
foreach ($polygon as $vertex) {
$vertices[] = $this->pointStringToCoordinates($vertex);
}
// Check if the point sits exactly on a vertex
if ($this->pointOnVertex == true and $this->pointOnVertex($point, $vertices) == true) {
return "vertex";
}
// Check if the point is inside the polygon or on the boundary
$intersections = 0;
$vertices_count = count($vertices);
for ($i=1; $i < $vertices_count; $i++) {
$vertex1 = $vertices[$i-1];
$vertex2 = $vertices[$i];
if ($vertex1['y'] == $vertex2['y'] and $vertex1['y'] == $point['y'] and $point['x'] > min($vertex1['x'], $vertex2['x']) and $point['x'] < max($vertex1['x'], $vertex2['x'])) { // Check if point is on an horizontal polygon boundary
return "boundary";
}
if ($point['y'] > min($vertex1['y'], $vertex2['y']) and $point['y'] <= max($vertex1['y'], $vertex2['y']) and $point['x'] <= max($vertex1['x'], $vertex2['x']) and $vertex1['y'] != $vertex2['y']) {
$xinters = ($point['y'] - $vertex1['y']) * ($vertex2['x'] - $vertex1['x']) / ($vertex2['y'] - $vertex1['y']) + $vertex1['x'];
if ($xinters == $point['x']) { // Check if point is on the polygon boundary (other than horizontal)
return "boundary";
}
if ($vertex1['x'] == $vertex2['x'] || $point['x'] <= $xinters) {
$intersections++;
}
}
}
// If the number of edges we passed through is odd, then it's in the polygon.
if ($intersections % 2 != 0) {
return "inside";
} else {
return "outside";
}
}
function pointOnVertex($point, $vertices) {
foreach($vertices as $vertex) {
if ($point == $vertex) {
return true;
}
}
}
function pointStringToCoordinates($pointString) {
$coordinates = explode(" ", $pointString);
return array("x" => $coordinates[0], "y" => $coordinates[1]);
}
}
$pointLocation = new pointLocation();
$points = array("22.732965336387213 75.8609390258789");
$polygon = array("22.73549852921309 75.85424423217773","22.72346544538196 75.85561752319336","22.72346544538196 75.87175369262695","22.732332030848273 75.87295532226562","22.740406456758326 75.8686637878418","22.74198962160603 75.85407257080078");
echo '<pre>';
print_r($polygon);
// The last point's coordinates must be the same as the first one's, to "close the loop"
foreach($points as $key => $point) {
echo "point " . ($key+1) . " ($point): " . $pointLocation->pointInPolygon($point, $polygon) . "<br>";
}
?>
I think google has solved it with this method of containsLocation()
https://developers.google.com/maps/documentation/javascript/examples/poly-containsLocation
I cannot seem to figure out why the object returned by getProjection() is undefined. Here is my code:
// Handles the completion of the rectangle
var ne = recBounds.getNorthEast();
var sw = recBounds.getSouthWest();
$("#map_tools_selat").attr( 'value', sw.lat() );
$("#map_tools_nwlat").attr( 'value', ne.lat() );
$("#map_tools_selng").attr( 'value', ne.lng() );
$("#map_tools_nwlng").attr( 'value', sw.lng() );
// Set Zoom Level
$("#map_tools_zoomlevel").attr( 'value', HAR.map.getZoom()+1 );
document.getElementById("map_tools_centerLat").value = HAR.map.getCenter().lat();
document.getElementById("map_tools_centerLong").value = HAR.map.getCenter().lng();
// All this junk below is for getting pixel coordinates for a lat/lng =/
MyOverlay.prototype = new google.maps.OverlayView();
MyOverlay.prototype.onAdd = function() { }
MyOverlay.prototype.onRemove = function() { }
MyOverlay.prototype.draw = function() { }
function MyOverlay(map) { this.setMap(map); }
var overlay = new MyOverlay(HAR.map);
var projection = overlay.getProjection();
// END - all the junk
var p = projection.fromLatLngToContainerPixel(recBounds.getCenter());
alert(p.x+", "+p.y);
My error is: Cannot call method 'fromLatLngToContainerPixel' of undefined
Actually, i the reason why this happens is because the projection object is created after the map is idle after panning / zooming. So, a better solution is to listen on the idle event of the google.maps.Map object, and get a reference to the projection there:
// Create your map and overlay
var map;
MyOverlay.prototype = new google.maps.OverlayView();
MyOverlay.prototype.onAdd = function() { }
MyOverlay.prototype.onRemove = function() { }
MyOverlay.prototype.draw = function() { }
function MyOverlay(map) { this.setMap(map); }
var overlay = new MyOverlay(map);
var projection;
// Wait for idle map
google.maps.event.addListener(map, 'idle', function() {
// Get projection
projection = overlay.getProjection();
})
I kind of figured out what was going on. Even though it is still not crystal clear why this happens, I know that I had to instantiate the variable "overlay" right after instantiating my google map (HAR.map). So I practically moved that code snippet into my HAR class and now i use:
HAR.canvassOverlay.getProjection().fromLatLngToContainerPixel( recBounds.getCenter() );
So now, every time I create a map via my class "HAR" I also have a parallel OverlayView object within my class.
The Error could have been with losing scope of my class object, but I think it was more of the map event "projection_changed" not being fired. I got a hint from the map API docs for map class, under method getProjection():
"Returns the current Projection. If the map is not yet initialized (i.e. the mapType is still null) then the result is null. Listen to projection_changed and check its value to ensure it is not null."
If you are getting the similar issue, make sure that you assign your overlayView.setMAP( YOUR_MAP_OBJECT ) closely after instantiating the map object.