Flutter AR - add pin on real time position - flutter

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.

Related

GeoFire query only returns last result

We are trying to loop through a set of documents in Firestore that are geo based, though the query only appears to be returning the last result and we cannot work out why
Future fetchTasksNearBy(double lat, double lng) async {
debugPrint('getting tasks in location');
GeoFirePoint center = geo.point(latitude: lat, longitude: lng);
double radius = 70; //in km
String field = 'location';
// Reading nearby tasks based on lat, lng parameters
try {
// Collection ref
var collectionReference = tasksRef.where('status', isEqualTo: 'Posted');
var geoRef = geo.collection(collectionRef: collectionReference);
Stream<List<DocumentSnapshot>> placesStream = geoRef.within(
center: center,
radius: radius,
field: field,
strictMode: true,
); // = false includes borderline places
await for (var doclist in placesStream) {
for (DocumentSnapshot ds in doclist) {
GeoPoint point = ds['location']['geopoint'];
_tasks.add(Task.fromDoc(ds));
return _tasks;
}
}
} catch (e) {
throw Exception(e);
}
}

Efficiently Drawing a Large Number of Identifiable Polygons in Mapbox GL

"I am using Mapbox GL to draw a large number of equal-sized polygons on the map. I am currently using the addLayer method to achieve this, but when the number of polygons becomes large, the performance of the map becomes very slow and it becomes difficult to use. Is there any other way to draw a large number of polygons that is more efficient and does not compromise the performance of the map? It is also important that each individual polygon is identifiable so that I can interact with it."
I manage to draw 50*50 rectangles, however, the page became really slow. This is my code implementation:
useEffect(() => {
const map = new mapboxgl.Map({
container: mapContainerRef.current,
style: "mapbox://styles/mapbox/light-v11",
center: origin,
zoom: 22, // starting zoom
});
map.on("load", () => {
// Add a data source containing GeoJSON data.
var iter;
var destination = [-86.872238, 40.46873];
for (var i = 0; i < 50; i++) {
for (var j = 0; j < 50; j++) {
var pixelOrigin = merc.px(origin, 22);
const pixelDest1 = [pixelOrigin[0], pixelOrigin[1] - 38];
const pixelDest2 = [pixelOrigin[0] + 38, pixelOrigin[1] - 38];
const pixelDest3 = [pixelOrigin[0] + 38, pixelOrigin[1]];
const cordDest1 = merc.ll(pixelDest1, 22);
const cordDest2 = merc.ll(pixelDest2, 22);
const cordDest3 = merc.ll(pixelDest3, 22);
if (j == 0) {
iter = cordDest3;
}
map.addSource("x: " + i + "y: " + j, {
type: "geojson",
data: {
type: "Feature",
geometry: {
type: "Polygon",
// These coordinates outline Maine.
coordinates: [
[origin, cordDest1, cordDest2, cordDest3, origin],
],
},
},
});
origin = cordDest1;
map.addLayer({
id: "x: " + i + "y: " + j,
type: "line",
source: "x: " + i + "y: " + j,
layout: {},
paint: {
"line-color": "#808080",
"line-width": 1,
},
});
}
origin = iter;
}
// Add a black outline around the polygon.
});
// Clean up on unmount
return () => map.remove();
}, []);
You should use only one source with all features and one layer to render them.
You can make the individual features identifiable via their properties (you can use Map#queryRenderedFeatures to access the property).
const features = [];
for (var i = 0; i < 50; i++) {
for (var j = 0; j < 50; j++) {
...
const feature = {
"type": "Feature",
"properties": {
id: "x:" + i + "y:" + j,
},
geometry: {
type: "Polygon",
coordinates: [[origin, cordDest1, cordDest2, cordDest3, origin]],
}
};
features.push(feature);
}
}
map.addSource("polygons", {
"type": "FeatureCollection",
"features": features,
});

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.

Leaflet playback place marker

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.