Select Git revision
mainpage.dox
map.component.ts 8.15 KiB
import { Component, OnInit } from '@angular/core';
import { Subscription } from 'rxjs';
import * as L from "leaflet";
import 'leaflet-arrowheads';
import { IMqttMessage, MqttService } from 'ngx-mqtt';
import { environment, MarkerColorMap } from 'src/environments/environment';
import {Position, PositionUpdate, RelativePos, Quaternion, WGS84} from 'src/app/model/base-model';
@Component({
selector: 'app-map',
templateUrl: './map.component.html',
styleUrls: ['./map.component.scss']
})
export class MapComponent implements OnInit {
private subsPosition: Subscription;
private subsRoot: Subscription;
private map!: L.Map;
private root!: Position;
agentsInfo: { [key: string]: {} } = {};
markOverlays: { [key: string]: L.LayerGroup<any> } = {};
posOverlays: { [key: string]: L.LayerGroup<any> } = {};
constructor(private _mqttService: MqttService) {
this.root = {"refSystemId": "ROOT", "point": {"latitude": 51.02545, "longitude": 13.72295}}
this.subsRoot = this._mqttService.observe('ipos/client/root').subscribe((message: IMqttMessage) => {
this.root = JSON.parse(message.payload.toString())
console.log("New root: ", this.root)
this.registerPoint("ROOT", {"position": this.root})
});
this.subsPosition = this._mqttService.observe('ipos/client/position').subscribe((message: IMqttMessage) => {
let upd: PositionUpdate = JSON.parse(message.payload.toString())
upd.objects.forEach(obj => this.registerPoint(obj.id, obj));
});
}
ngOnInit(): void { }
// --- Controllers
ref2root(pos: RelativePos) {
// convert a relative position to WFG84 format
let source = <WGS84>this.root.point
let origin = L.latLng([source.latitude, source.longitude])
let point = L.Projection.Mercator.project(origin)
let newPoint = L.point([point.x + pos.x, point.y + pos.y])
let newLatLng = L.Projection.Mercator.unproject(newPoint)
return newLatLng
}
registerPoint(key: string, desc: { [key: string]: any }) {
// --- Leyers for markers
if (key in this.markOverlays) {
this.markOverlays[key].clearLayers();
} else {
this.markOverlays[key] = L.layerGroup().addTo(<L.Map>this.map)
}
// --- Info
let pos = desc["position"]
this.agentsInfo[key] = desc
var props = undefined
if (desc.extractedAttributes) {
props = `<p> \
<h3>${key}</h3>
<strong>Charge</strong>: ${desc.extractedAttributes?.batteryChargeLevel}% <br>\
<strong>Items</strong>: ${desc.extractedAttributes?.loadedItems} <br>\
<strong>Errors</strong>: ${desc.extractedAttributes?.errors}\
</p>`
} else {
props = `<p><h3>${key}</h3></p>`
}
// Rotaion
let quter = desc.orientation
// if (quter) {
// // console.log("Init:", orient)
// let orient = this.calcOrient(quter.w, quter.x, quter.y, quter.z)
// // console.log("Orient:", orient)
// let orientPoint: RelativePos = {
// "x": orient[0] + pos.point.x,
// "y": orient[1] + pos.point.y,
// "z": orient[2] + pos.point.z
// }
// let globPointOrient = this.ref2root(orientPoint)
// if ('x' in pos.point) {
// var globPos = this.ref2root(pos.point)
// } else {
// var globPos = L.latLng([pos.point.latitude, pos.point.longitude]);
// }
// // add arrow
// var arrow = L.polyline([globPos, globPointOrient], {color: 'grey'}).arrowheads(
// {
// fill: true,
// // size: '30%',
// color: 'grey'
// }
// ).addTo(this.map);
// }
this.addMarker(key, pos, props, quter)
}
addMarker(key: string, pos: Position, popup: string, quter: Quaternion) {
let point = pos.point
if ('x' in point) {
var globPos = this.ref2root(point)
} else {
var globPos = L.latLng([point.latitude, point.longitude]);
}
// --- Marker
if (key in MarkerColorMap) {
var markerConf = MarkerColorMap[key]
} else {
var markerConf = MarkerColorMap['Default']
}
let marker = L.marker(globPos, {
icon: L.icon({
iconSize: [25, 41],
iconAnchor: [13, 41],
iconUrl: `assets/marker-icon-${markerConf.marker}.png`,
iconRetinaUrl: `assets/marker-icon-2x-${markerConf.marker}.png`,
shadowUrl: 'assets/marker-shadow.png',
className: 'true-position-marker'
})
}).bindPopup(popup).openPopup();
marker.addTo(this.markOverlays[key])
// --- Accuracy
if (pos?.accuracy) {
L.circle(globPos, pos.accuracy, { color: markerConf.circle}
).addTo(this.markOverlays[key]);
}
// --- Orientation
if (quter && 'x' in point) {
let orient = this.calcOrient(quter.w, quter.x, quter.y, quter.z)
let orientPoint: RelativePos = {
"x": orient[0] + point.x,
"y": orient[1] + point.y,
"z": orient[2]
}
let globPointOrient = this.ref2root(orientPoint)
// add arrow
var arrow = L.polyline([globPos, globPointOrient], {color: 'grey'}).arrowheads(
{
fill: true,
// size: '30%',
color: 'grey'
}
);
arrow.addTo(this.markOverlays[key])
}
}
quaternionMult(q: number[], r: number[]) {
return [r[0]*q[0]-r[1]*q[1]-r[2]*q[2]-r[3]*q[3],
r[0]*q[1]+r[1]*q[0]-r[2]*q[3]+r[3]*q[2],
r[0]*q[2]+r[1]*q[3]+r[2]*q[0]-r[3]*q[1],
r[0]*q[3]-r[1]*q[2]+r[2]*q[1]+r[3]*q[0]]
}
calcOrient(w: number, x: number, y: number, z: number) {
// Rotation transforms from one orientation to another
let point = [0,0,3,0] // point vector
let qConj = [w,-1*x,-1*y,-1*z]
let q = [w,x,y,z]
let point_new = this.quaternionMult(this.quaternionMult(q,point),qConj)
return point_new.slice(1)
}
// @https://asymmetrik.com/ngx-leaflet-tutorial-angular-cli/
// --- Layers: Define base layers so we can reference them multiple times
streetMaps = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
detectRetina: true,
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
wMaps = L.tileLayer('http://maps.wikimedia.org/osm-intl/{z}/{x}/{y}.png', {
detectRetina: true,
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
});
satelliteMaps = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
id: 'mapbox.gis',
attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community'
});
mapBoxMaps = L.tileLayer(
'https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=' + environment.mapbox.accessToken2, {
id: 'mapbox.streets-v11',
attribution: '© <a href="https://apps.mapbox.com/feedback/">Mapbox</a> © <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
})
cycleMaps = L.tileLayer(
'https://tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=' + environment.osm.apikey, {
attribution: '© OpenCycleMap, ' + 'Map data: opencyclemap.org',
maxZoom: 21,
})
options = {
layers: [this.cycleMaps],
zoom: 19,
center: L.latLng([51.02545, 13.72295])
};
onMapReady(map: L.Map) {
this.map = map;
let baseLayers = {
'MapBox': this.mapBoxMaps,
'Street Maps': this.streetMaps,
'Wikimedia Maps': this.wMaps,
'Satellite': this.satelliteMaps,
'Cycle': this.cycleMaps
}
L.control.layers(baseLayers).addTo(this.map);
let legend = new L.Control({ position: "bottomleft" });
legend.onAdd = function () {
var div = L.DomUtil.create("div", "legend");
div.innerHTML += '<img style="opacity: .5" src="assets/marker-icon-grey.png"> <span> Employee </span><br>';
div.innerHTML += '<i class="est-pos"></i> <span> Estimated position </span><br>';
return div;
};
// legend.addTo(this.map);
//-- check root
if (this.root) {
this.registerPoint("ROOT", {"position": this.root})
}
}
public ngOnDestroy() {
this.subsPosition.unsubscribe();
this.subsRoot.unsubscribe();
}
}