Leaflet playback place marker - leaflet

I am using the playback plugin and i am using it on an image overlay.
https://github.com/hallahan/LeafletPlayback
I need to scale the floor map before placing the marker. with the plugin the marker is placed some where outside of the floor map.
I am able to solve the issue for GPS tracking, where i have written a function to scale the map and place the marker inside pointToLayer method of layer property.
I want to do the same for marker too. any help is appreciated.
const playbackOptions = {
playControl: true,
dateControl: true,
orientIcons: true,
fadeMarkersWhenStale: true,
// layer and marker options
layer: {
pointToLayer(featureData, latlng) {
const { lat, lng } = latlng;
let result = {};
if (featureData && featureData.properties && featureData.properties.path_options) {
result = featureData.properties.path_options;
}
if (!result.radius) {
result.radius = 5;
}
const scaleX = width / details.width;
const scaleY = height / details.length;
const m = {
x: lat * scaleX,
y: lng * scaleY,
};
const iconCls = 'asset-icon';
const item = L.marker(self.map.unproject([m.x, m.y], self.map.getMaxZoom()), {
icon: makeMarker(iconCls, 0),
opacity: 0.9,
type: 'asset',
lat,
lng,
});
item.bindTooltip(`<p>${lat}, ${lng}`, { className: 'asset-label', offset: [0, 0] });
return item;
}
},
marker: {
getPopup(featureData) {
let result = '';
if (featureData && featureData.properties && featureData.properties.title) {
result = featureData.properties.title;
}
return result;
}
}
};

If you retrieve actual GPS coordinates, it would probably be easier to actually do the reverse, i.e. to georeference your image overlay once for good, instead of trying to fiddle with the geographic coordinates of each of the feature you try to show relatively to your image.

Related

How to have Leaflet.draw display Imperial units while drawing?

This doesn't work for much of anything really that I can tell.
I want to remove the meters while drawing without having to do it in a hackish way. I am thinking I can just grab it and do some stuff outside of the normal functionality but would rather it just work.
While I'm drawing I want the tooltip to show imperial units.
Leaflet Version is currently 1.7.1. - I should upgrade.
Using CDN link for leaflet.draw currently.
'''
function mapDraw() {
var drawLayer = new L.featureGroup();
map.addLayer( drawLayer );
// Add the edit toolbar
let drawControl = new L.Control.Draw({
draw: {
circle: {
metric: false,
feet: true
},
polyline: {
metric: false,
feet: 'feet'
},
polygon: {
metric: false,
feet: 'feet'
},
rectangle: {
metric: false,
feet: true
},
},
edit: {
featureGroup: drawLayer
}
});
map.on(L.Draw.Event.CREATED, function (e) {
var type = e.layerType;
layer = e.layer;
if ( type === 'polygon' || type === 'rectangle' ) {
var area = L.GeometryUtil.geodesicArea( layer.getLatLngs()[0] );
var readableArea = L.GeometryUtil.readableArea( area );
layer.bindTooltip( readableArea );
} else if ( type === 'circle' ) {
var radius = layer.getRadius();
var area = Math.PI * radius ** 2;
readableArea = L.GeometryUtil.readableArea( area );
layer.bindTooltip( readableArea );
} else if ( type === 'polyline' ) {
var latlng = layer.getLatLngs();
var distance = 0;
for ( var i = 0; i < latlng.length - 1; i++ ) {
distance += latlng[i].distanceTo( latlng[i+1] );
}
distanceInFeet = distance * 100 / 2.54 / 12;
distanceInYards = distanceInFeet / 3;
distanceInMiles = distanceInYards / 1760;
layer.bindTooltip( distanceInFeet.toFixed(2) + ' ft' );
}
drawLayer.addLayer( layer );
});
map.addControl(drawControl);
}

Flutter AR - add pin on real time position

I'm trying to implement AR on flutter platform for mobile devices using ar_flutter_plugin. I don't know how calculate position for ARNode object. The method for adding object to real time :
Future<void> addPointsOnmap() async {
var location = await Geolocator.getCurrentPosition();
var data = await GetObjekti.getResults(
location.latitude.toString() + "," + location.longitude.toString(), 2);
List<Result> results = data["results"];
for (var i = 0; i < results.length; i++) {
//I need to calculate value of position
ARNode node = ARNode(
type: NodeType.localGLTF2,
uri: "assets/Chicken_01/Chicken_01.gltf",
scale: Vector3(100.0, 100.0, 100.0),
position: Vector3(0.0, 0.0, 0.0),
rotation: Vector4(1.0, 0.0, 0.0, 0.0));
results[i].arNodeName = node.name;
bool? addNode = await arObjectManager.addNode(node);
if (addNode!){
nodes.add(node);
}
}
}
Method getResults fetchs data from API and example of one object from response is:
{
"distance": 0.48079831661545036,
"centroid": {
"lon": 16.343588998,
"lat": 46.294568693
},
"label": "Some label",
"id": 106405,
"object_id": 10575,
"feature_class_id": 1431
}
Where distance is calculated distance from the geolocation of user to place from result in km (kilometers) and centroid contains geo longitude and latitude. Any suggestion or help are welcome.

How to draw SVG polygon on openStreetMap programitically in flutter

Hello I want to use this api nominatim.org to find svg shape and latLng coordiante of one address.
I called this api in flutter and try to show it by Polygon in my flutter code in open street map
this is my code
late PolyEditor polyEditor;
List<Polygon> polygons = [];
var testPolygon = Polygon(
color: Colors.black.withOpacity(0.3),
points: [],
borderColor: Colors.black,
isFilled: true,
borderStrokeWidth: 1.0);
#override
void initState() {
super.initState();
polyEditor = PolyEditor(
addClosePathMarker: true,
points: testPolygon.points,
pointIcon: const Icon(
Icons.lens,
size: 15,
color: Colors.black,
),
intermediateIcon: const Icon(Icons.lens, size: 15, color: Colors.black),
callbackRefresh: () => {setState(() {})},
);
polygons.add(testPolygon);
}
SearchController searchController = Get.put(SearchController());
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
alignment: Alignment.center,
children: [
Center(
child: FlutterMap(
options: MapOptions(
allowPanningOnScrollingParent: false,
onTap: (_, ll) {
print(ll);
polyEditor.add(testPolygon.points, ll);
},
plugins: [
DragMarkerPlugin(),
],
center: LatLng(32.5231, 51.6765),
zoom: 9.4,
),
layers: [
TileLayerOptions(
urlTemplate:
'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
subdomains: ['a', 'b', 'c']),
PolygonLayerOptions(polygons: polygons),
DragMarkerPluginOptions(markers: polyEditor.edit()),
],
),
),
I called this api and tried to show this svg as a polygon
"svg": "M 13.397511 -52.517283599999999 L 13.397829400000001 -52.517299800000004
13.398131599999999 -52.517315099999998 13.398159400000001 -52.517112099999999 13.3975388
-52.517080700000001 Z",
but I dont know how to convert this svg string of coordinate to Polygon and show it on map when called this api and recieve this svg
I used this plugin
import 'package:flutter_map_line_editor/polyeditor.dart';
the result should be like this
see this picture
You're facing several problems:
The retrieved svg data from nominatim is not a polygon but a path
Besides it describes a single point i.e. it doesn't have any height or width.
Quite likely, the polyeditor expects a proper polygon based on an array of geodata based coordinates.
Change nominatim query to get polygon coordinates
You could change the query to something like this:
https://nominatim.openstreetmap.org/search?q=London&format=json&polygon_geojson=1
Most address search queries won't return a polygon unless they are a sight or public building like "London+Downing+street+10".
If you're searching for a city, county, state, district or sight, the json response will include polygon coordinates describing the border of the queried region.
polygon_geojson=1 parameter will return an array polygon coordinates that could be displayed on you map.
Unfortunately, you need to change the order of coordinates to use them in leaflet since geojson will return [lon, lng] instead of [lat, lon]
Js example fetching polygon from nominatim
You might translate this example to work with flutter.
function initMap(lat, lon, zoom, coords = [], bBox = []) {
var map = L.map("map").setView([lat, lon], zoom);
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", {
maxZoom: 19,
attribution: "© OpenStreetMap"
}).addTo(map);
var marker = L.marker([lat, lon]).addTo(map);
if (coords.length) {
/**
* change coordinate order from [lon, lat] to [lat, lon]
* and reduce number of polygon vertices to 64
*/
let polygonPoints = getGeoJsonPoly(coords, 64);
var polygon = L.polygon(polygonPoints).addTo(map);
}
var southWest = new L.LatLng(bBox[0], bBox[2]),
northEast = new L.LatLng(bBox[1], bBox[3]),
bounds = new L.LatLngBounds(southWest, northEast);
map.fitBounds(bounds);
}
let query = "City-of-London";
//query = "London+Downing+street+10";
let url = `https://nominatim.openstreetmap.org/search?q=${query}&format=json&polygon_geojson=1`;
fetchJson(url);
function fetchJson(url) {
fetch(url)
.then((response) => response.json())
.then(function(data) {
let result = data[0];
let type = result.osm_type;
if (type != 'relation') {
result = data[1];
}
let [lat, lon] = [result.lat, result.lon];
let coords = result["geojson"]["coordinates"][0];
let bBox = result.boundingbox ? result.boundingbox : [];
initMap(lat, lon, 10, coords, bBox);
})
.catch(function(error) {
console.error(error);
});
}
function getGeoJsonPoly(coords, vertices = 0) {
let coordsL = coords.length;
let step = vertices != 0 ? Math.ceil(coordsL / vertices) : 1;
let polygonPoints = [];
for (let i = 0; i < coordsL; i += step) {
let p = coords[i];
let [lat, lon] = [p[1], p[0]];
polygonPoints.push([lat, lon]);
}
return polygonPoints;
}
#map {
height: 90vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.8.0/leaflet.js"></script>
<link rel="stylesheet" href="https://unpkg.com/leaflet#1.8.0/dist/leaflet.css" />
<h3>Query: London+Downing+street+10</h3>
<div id="map"></div>
Optional: reducing polygon vertices
For better performance you might need to reduce the (usually huge) number of vertices.
While looping through the geoJson coordinate array you might drop coordinates like so:
/**
* change coordinate order from [lon, lat] to [lat, lon]
* and reduce number of polygon vertices to 64
*/
function getGeoJsonPoly(coords, vertices=0, round=0){
let coordsL = coords.length;
let step = vertices!=0 ? Math.ceil(coordsL / vertices) : 1;
let polygonPoints = [];
for (let i = 0; i < coordsL; i += step) {
let p = coords[i];
let [lat, lon] = [p[1], p[0]];
if(round>0){
[lat, lon] = [+lat.toFixed(round), +lat.toFixed(round)]
}
polygonPoints.push([lat, lon]);
}
return polygonPoints;
}

snap markers to nearest polyline point Google Maps flutter

I am writing a simple bus tracking app for my university shuttles. I have plotted out the bus GPS as navigation arrows along with the route on the map. Now as the actual GPS coordinate is a little of from the real location of bus than the plotted route, it is slightly off the road. Is there any way or method that I can call to snap these markers to the polyline nearest point in google maps flutter plugin? I just wanted to know if there is anything already in place that I am missing. I would be willing to write the custom nearest neighbor logic if necessary. Thanks!
I have done using locationIndexOnPath, computeDistanceBetween, computeHeading.
Step 1. add this function to get nearest polyline segment index based on you current location. pass your polyline coordinates list and current location. below function return index of given polyline coordinates list.
int getEdgeIndex(List<mt.LatLng> _coordinates, mt.LatLng currentLocation) {
final int edgeIndex1 = mt.PolygonUtil.locationIndexOnPath(
currentLocation, _coordinates, true,
tolerance: 1);
final int edgeIndex2 = mt.PolygonUtil.locationIndexOnPath(
currentLocation, _coordinates, true,
tolerance: 2);
final int edgeIndex6 = mt.PolygonUtil.locationIndexOnPath(
currentLocation, _coordinates, true,
tolerance: 6);
final int edgeIndex10 = mt.PolygonUtil.locationIndexOnPath(
currentLocation, _coordinates, true,
tolerance: 10);
final int edgeIndex15 = mt.PolygonUtil.locationIndexOnPath(
currentLocation, _coordinates, true,
tolerance: 15);
int finalIndex = -1;
if (edgeIndex1 >= 0) {
finalIndex = edgeIndex1;
} else if (edgeIndex2 >= 0) {
finalIndex = edgeIndex2;
} else if (edgeIndex6 >= 0) {
finalIndex = edgeIndex6;
} else if (edgeIndex10 >= 0) {
finalIndex = edgeIndex10;
} else if (edgeIndex15 >= 0) {
finalIndex = edgeIndex15;
}
print(
"getEdgeIndex: index : $edgeIndex1, $edgeIndex2, $edgeIndex6, $edgeIndex10, $edgeIndex15, $finalIndex");
return finalIndex;
}
Step 2. Now add this function to get snap LatLag to snap you current marker in centre of polyline route.
Map<String, dynamic> getSnapLatLng(LatLng currentLocation) {
final currentLocationMT =
mt.LatLng(currentLocation.latitude, currentLocation.longitude);
if (coordinatesMT.isEmpty) {
for (LatLng latLng in coordinates) {
coordinatesMT.add(mt.LatLng(latLng.latitude, latLng.longitude));
}
}
final int finalIndex = getEdgeIndex(coordinatesMT, currentLocationMT);
if (finalIndex >= 0) {
final snappedLatLng2 = (finalIndex < coordinatesMT.length - 1)
? coordinatesMT[finalIndex + 1]
: currentLocationMT;
final snappedLatLng = coordinatesMT[finalIndex];
final distanceM2 = mt.SphericalUtil.computeDistanceBetween(
snappedLatLng, currentLocationMT);
double heading = mt.SphericalUtil.computeHeading(
snappedLatLng2,
snappedLatLng,
);
final extrapolated =
mt.SphericalUtil.computeOffset(snappedLatLng, -distanceM2, heading);
print(
"snapToPolyline:distanceM $distanceM2, $heading, $finalIndex, ${coordinatesMT.length}");
return {
"index": finalIndex,
"latLng": LatLng(extrapolated.latitude, extrapolated.longitude)
};
}
return {"index": finalIndex, "latLng": currentLocation};
}
NOTE: I have used https://pub.dev/packages/maps_toolkit this package for locationIndexOnPath, computeDistanceBetween, computeHeading.

Integrating / adding Google Earth View to my map

I am creating an interactive map for a non profit association "Friends of Knox Mountain Park" but I am getting trouble with the Google Earth view.
I've been searching on the web for weeks and none of the solutions I found works for me. Can someone take a look of the code and let me know what I should do to include Google Earth View in the map? Thanks in advance.
The online project: http://www.virtualbc.ca/knoxmountain/
And this is the javascript file (mapa2.js) containing the google map's code:
google.load('earth', '1');
var map;
var googleEarth;
var gmarkers = [];
var iconShadow = new google.maps.MarkerImage('icons/shadow.png',
new google.maps.Size(46, 42),
new google.maps.Point(0,0),
new google.maps.Point(13, 42));
var sites = [
['Apex Trail - Shelter',49.91174271, -119.48507050, 4, '<img src="images/apex_point_high.jpg">','magenta','14'],
['Apex Trail',49.91286999, -119.48413424, 3, '<img src="images/apex_point_low.jpg">','lemon','1'],
['Gordon Trail',49.91971281, -119.47954356, 2, '<img src="images/apex_point_low.jpg">','lemon','1'],
['Paul Tomb Bay',49.92555541, -119.47710250, 1, '<img src="images/tomb_bay.jpg">','lemon','1']
];
var infowindow = null;
var overlay;
// Used to make Google Map quard coords to MapCruncher/BingMaps quard coords
function TileToQuadKey ( x, y, zoom)
{
var quad = "";
for (var i = zoom; i > 0; i--)
{
var mask = 1 << (i - 1);
var cell = 0;
if ((x & mask) != 0)
cell++;
if ((y & mask) != 0)
cell += 2;
quad += cell;
}
return quad;
}
function init() {
var centerMap = new google.maps.LatLng(49.909671, -119.482241);
var myOptions = {
zoom: 10,
center: centerMap,
mapTypeId: google.maps.MapTypeId.SATELLITE
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
// Create the tile layers
// ASTER Tile Layer
myASTEROptions = {
getTileUrl : function (a,b) {
return "http://www.virtualbc.ca/knoxmountain/map/" + TileToQuadKey(a.x,a.y,b) + ".png";
},
isPng: true,
opacity: 1.0,
tileSize: new google.maps.Size(256,256),
name: "ASTER",
minZoom:13,
maxZoom:20
}
ASTERMapType = new google.maps.ImageMapType( myASTEROptions );
map.overlayMapTypes.insertAt(0, ASTERMapType);
// Aerial Tile Layer
myAerialOptions = {
getTileUrl : function (a,b) {
return "http://www.virtualbc.ca/knoxmountain/map/" + TileToQuadKey(a.x,a.y,b) + ".png";
},
isPng: true,
opacity: 1.0,
tileSize: new google.maps.Size(256,256),
name: "Aerial",
minZoom:15,
maxZoom:21
}
AerialMapType = new google.maps.ImageMapType( myAerialOptions );
map.overlayMapTypes.insertAt(1, AerialMapType);
var panorama = new google.maps.StreetViewPanorama(map.getDiv());
panorama.setVisible(false);
panorama.set('enableCloseButton', true);
map.setStreetView(panorama);
panorama.setPosition(centerMap);
setMarkers(map, sites);
setZoom(map, sites);
infowindow = new google.maps.InfoWindow({
content: "Loading..."
});
googleEarth = new GoogleEarth(map);
google.maps.event.addListenerOnce(map, 'tilesloaded', addOverlays);
}
/*
This functions sets the markers (array)
*/
function setMarkers(map, markers) {
for (var i = 0; i < markers.length; i++) {
var site = markers[i];
var siteLatLng = new google.maps.LatLng(site[1], site[2]);
var marker = new google.maps.Marker({
position: siteLatLng,
map: map,
title: site[0],
zIndex: site[3],
html: site[4],
// Markers drop on the map
animation: google.maps.Animation.DROP,
icon: 'http://www.virtualbc.ca/knoxmountain/icons/icon.png',
shadow: iconShadow
});
gmarkers.push(marker);
google.maps.event.addListener(marker, "click", function () {
infowindow.setContent(this.html);
infowindow.open(map, this);
});
}
}
/*
Set the zoom to fit comfortably all the markers in the map
*/
function setZoom(map, markers) {
var boundbox = new google.maps.LatLngBounds();
for ( var i = 0; i < markers.length; i++ )
{
boundbox.extend(new google.maps.LatLng(markers[i][1], markers[i][2]));
}
map.setCenter(boundbox.getCenter());
map.fitBounds(boundbox);
}
// This function picks up the click and opens the corresponding info window
function myclick(i) {
google.maps.event.trigger(gmarkers[i-1], "click");
}
google.maps.event.addDomListener(window, 'load', init);
The first issue I notice with your site is you are linking to http://www.virtualbc.ca/src/googleearth-compiled.js which does not exist.