Find markers shown in mapView - swift

I am trying to determine the marker/s currently shown in a mapview. I have researched the following the method:
self.mapView.bounds.contains(markers[0].position)
But the contains command accepts CGPoint or CGRect. In other platforms except Swift, contains can accept the marker's position.
How do I convert the marker's position to be accepted by contains?

Use the mapview's current projection. Use the projection's method called containsCoordinate to check if you marker's position is inside the projection, i.e. currently visible.
So something like:
let coord = marker.position
let isVisible = self.mapview.projection.containsCoordinate(coord)
https://developers.google.com/maps/documentation/ios-sdk/reference/interface_g_m_s_projection.html#aa6ad29e6831e40f00435c3aaeda8e08a

In MapKit:
I assume with Marker you mean an MKAnnotation. Instead of using the bounds of the mapView you should use the visibleMapRect and see if it contains the coordinates of the Marker in MKMapPoints. This is the code I used:
let markerPoint = MKMapPointForCoordinate(markers[0].coordinate)
if MKMapRectContainsPoint(mapView.visibleMapRect, markerPoint) {
print("Found")
} else {
print("Not found")
}
Only when the coordinates of the markers are visible (in other words, the marker is being displayed), this will print "Found". If off-screen, it will print "Not found".

Related

How to detect pan gesture in map with Flutter Here SDK

I'm building an app with Flutter and am trying to listen to the pan gestures of the map to get the center of the map view and place a pin on the center. The code I've tried is as follows:
void _setPanGestureHandler({HereMapController mapController}) {
_hereMapController.gestures.panListener = PanListener.fromLambdas(
lambda_onPan: (GestureState gestureState, Point2D panStartPoint,
Point2D panEndPoint, double panVelocity) {
if (gestureState == GestureState.begin) {
print("start pan");
} else if (gestureState == GestureState.end) {
var centerPointLat = _hereMapController.viewportSize.width / 2;
var centerPointLong = _hereMapController.viewportSize.height / 2;
GeoCoordinates geoCoordinates = _hereMapController
.viewToGeoCoordinates(Point2D(centerPointLat, centerPointLong));
if (geoCoordinates == null) {
return;
}
_addPoiMapMarker(geoCoordinates);
_getAddressForCoordinates(geoCoordinates);
} else if (gestureState == GestureState.update) {
print("pan updated");
} else if (gestureState == GestureState.cancel) {
print("pan cancelled");
}
});
}
The code is part of the search_app example and I've just added a panGesture listener to it.
On panning, I get the following in the debug console
W/PanGestureDetector(21446): [WARN ] PanGestureDetector - Invalid panning of zero duration but nonzero length, skipping
W/PanGestureDetector(21446): [WARN ] PanGestureDetector - Invalid panning of zero duration but nonzero length, skipping
Please let me know how I can solve this problem.
The code snippet from your question is not part of the search_app example, so I assume it is your code. However, what you are trying to do will not work properly:
_hereMapController.viewportSize is giving you the size in pixels of the map view. It is not providing geographic coordinates. Although you can use viewToGeoCoordinates() to convert pixel points to geographic coordinates, there is an easier way: The MapCamera gives you always the current center location for free via the targetCoordinates property.
The pan gesture handler is executed multiple times. It would not be advisable to call _addPoiMapMarker() each time the GestureState.end event occurs. Instead, you can reposition an existing marker by setting new coordinates.
From your code it looks like you want to get the address of the map view's center. I assume you do not want to recenter a marker each time the map has stopped moving. So, in your case it may be better to draw a fixed widget at the center of your map view, regardless of it's current coordinates - then it will not move or lag behind any events, e.g. you may get from a MapCameraObserver.
The log messages you are receiving are only warnings, so they should not have an effect on the pan gesture event you are receiving.

Bing Maps V8 SDK - Get drawn shapes

I have a Bing map with drawing manager enabled for users to draw shapes (mostly one polygon at a time). I want to be able to get the details of the drawn polygon so I can save it in the database.
The below function can access the shapes but returns the coordinates only
function getShapes()
{
var shapes = drawingManager.getPrimitives();
if (shapes && shapes.length > 0)
{
var rings = shapes[0].getRings();
alert('Retrieved ' + rings[0] + ' from the drawing manager.');
}
else
{
alert('No shapes in the drawing manager.');
}
}
result is:
Retrieved [MapLocation (35.17314901376581, 44.72432011035158)],[MapLocation (35.10324034213123, 44.73015659716798)],[MapLocation (35.12346106720259, 44.90525120166017)],[MapLocation (35.18633788986748, 44.88362186816408)],[MapLocation (35.17314901376581, 44.72432011035158)] from the drawing manager.
How can I get the exact drawn shape details not just the coordinates?
Remove getRings() and you will have the shape object. The Get Rings function retudrrns the coordinates of a polygon.

Check if coordinates are inside a KML polygon

I have a KML file which defines a region (or polygon). I would like to make a function that checks if a given coordinate is inside or outside that polygon.
This is the KML if you want to take a look: http://pastebin.com/LGfn3L8H
I don't want to show any map, I just want to return a boolean.
Point-in-polygon (PiP) is a very well-studied computational geometry problem, so there are lots of algorithms and implementations out there that you can use. Searching SO will probably find several you can copy-paste, even.
There's a catch, though—you're dealing with polygons on the surface of the Earth... which is a sphere, not the infinite Euclidean plane that most PiP algorithms expect to work with. (You can, for example, have triangles whose internal angles add up to greater than π radians.) So naively deploying a PiP algorithm will give you incorrect answers for edge cases.
It's probably easiest to use a library that can account for differences between Euclidean and spherical (or, more precisely, Earth-shaped) geometry—that is, a mapping library like MapKit. There are tricks like the one in this SO answer that let you convert a MKPolygon to a CGPath through map projection, after which you can use the CGPathContainsPoint function to test against the flat 2D polygon corresponding to your Earth-surface polygon.
Of course, to do that you'll also need to get your KML file imported to MapKit. Apple has a sample code project illustrating how to do this.
This can be done with GMSGeometryContainsLocation.
I wrote a method that makes use of the GoogleMapsUtils library's GMUKMLParser.
func findPolygonName(_ location: CLLocationCoordinate2D) {
var name: String?
outerLoop: for placemark in kmlParser.placemarks {
if let polygon = (placemark as? GMUPlacemark)?.geometry as? GMUPolygon {
for path in polygon.paths {
if GMSGeometryContainsLocation(location, path, true) {
name = (placemark as? GMUPlacemark)?.title
break outerLoop
}
}
}
}
if let n = name, !n.isEmpty {
locationLabel.text = n
} else {
locationLabel.text = "We do not deliver here"
}
}
This function iterates over the polygon and its path to determine whether the given coordinates are within the path.

Google Earth API - drawing lines that curve?

I've been playing with the google earth API. I thought it would be neat to draw some lines between places from a relative 3D viewpoint. I've searched through the GE documentation and searched on google for answers but didn't find anything that led me down the correct path, so I thought I'd post some code and perhaps get some insight.
The following code plots two places and then draws a line between those places. Unfortunately the line that gets drawn splices the earth. Is there a method to make it wrap to the contour of the earth when drawn in 3D like this? I've attempted to vary the line height placement with a varying degree of success, but at the cost of accuracy and overall visual appeal when the line doesn't appear to connect the places.
function init() {
google.earth.createInstance('map3d', initCB, failureCB);
}
function initCB(instance) {
ge = instance;
ge.getWindow().setVisibility(true);
//---------------------------------PLACES
// Create the placemark.
var placemark = ge.createPlacemark('');
placemark.setName("Location 1");
// Set the placemark's location.
var point = ge.createPoint('');
point.setLatitude(39.96028);
point.setLongitude(-82.979736);
placemark.setGeometry(point);
// Add the placemark to Earth.
ge.getFeatures().appendChild(placemark);
// Create the placemark.
var placemark2 = ge.createPlacemark('');
placemark2.setName("Hop #2");
// Set the placemark's location.
var point2 = ge.createPoint('');
point2.setLatitude(25.7615);
point2.setLongitude(-80.2939);
placemark2.setGeometry(point2);
// Add the placemark to Earth.
ge.getFeatures().appendChild(placemark2);
//---------------------------------FOCUS
var lookAt = ge.createLookAt('');
lookAt.setLatitude(39.96028);
lookAt.setLongitude(-82.979736);
lookAt.setRange(1000000.0);
lookAt.setAltitude(0);
lookAt.setTilt(45);
ge.getView().setAbstractView(lookAt);
//---------------------------------LINES
// Create the placemark
var lineStringPlacemark = ge.createPlacemark('');
// Create the LineString
var lineString = ge.createLineString('');
lineStringPlacemark.setGeometry(lineString);
// Add LineString points
lineString.getCoordinates().pushLatLngAlt(39.96028, -82.979736, 0);
lineString.getCoordinates().pushLatLngAlt(25.7615, -80.2939, 0);
//lineString.setAltitudeMode(ge.ALTITUDE_CLAMP_TO_GROUND);
//lineString.setAltitudeMode(ge.ALTITUDE_RELATIVE_TO_GROUND);
lineString.setAltitudeMode(ge.absolute);
// Create a style and set width and color of line
lineStringPlacemark.setStyleSelector(ge.createStyle(''));
var lineStyle = lineStringPlacemark.getStyleSelector().getLineStyle();
lineStyle.setWidth(2);
lineStyle.getColor().set('9900ffff'); // aabbggrr format
// Add the feature to Earth
ge.getFeatures().appendChild(lineStringPlacemark);
}
function failureCB(errorCode) {
}
google.setOnLoadCallback(init);
You will want to set tesselation, and optionally extrude, on your linestring to true.
See https://developers.google.com/kml/documentation/kmlreference#tessellate and https://developers.google.com/kml/documentation/kmlreference#extrude for details
For the API, your syntax would be something like
lineStringPlacemark.setTessellate(true);
lineStringPlacemark.setExtrude(true);
There's some additional API examples on this at https://developers.google.com/earth/documentation/geometries

How can we know that map Coordinates are in current region or not in current region?

I am working on map view app.I want know that how we can identify that coordinates are in my current region(Map region that bound with screen) or outside of it.
Thanks In Advance.
You have different options. You can see this sample code from apple: Regions. That, has I understand, check the device position by the antenna's position.
Or tracking device position, and check if is inside a region defined by You. Check this question
If you find a better solution, please let me know.
EDIT:
To check if a coordinate is visible in the map try using this:
// Your coordinates - Lisbon for example
float lisbonLatitudeValue = 38.7069320;
float lisbonLongitudeValue = -9.1356321;
CLLocationCoordinate2D lisbonCoordinates = CLLocationCoordinate2DMake(lisbonLatitudeValue, lisbonLongitudeValue);
if (MKMapRectContainsPoint(mapView.visibleMapRect, MKMapPointForCoordinate(lisbonCoordinates)))
{
// do something
NSLog(#" - Lisbon is visible");
}
else {
// do something
NSLog(#" - Lisbon is not visible");
}
Hope it helps