Skip to content
Snippets Groups Projects
Commit 631a9245 authored by Oleksandr Husak's avatar Oleksandr Husak
Browse files

display relative position

parent cc3d414c
No related branches found
No related tags found
No related merge requests found
......@@ -35,7 +35,8 @@
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.scss"
"src/styles.scss",
"./node_modules/leaflet/dist/leaflet.css"
],
"scripts": []
},
......
This diff is collapsed.
......@@ -22,6 +22,7 @@
"@angular/router": "~12.2.0",
"@asymmetrik/ngx-leaflet": "^8.1.0",
"leaflet": "^1.7.1",
"ngx-mqtt": "^9.0.5",
"rxjs": "~6.6.0",
"tslib": "^2.3.0",
"zone.js": "~0.11.4"
......
......@@ -4,5 +4,3 @@
<app-map class="wrapper"></app-map>
<router-outlet></router-outlet>
......@@ -4,6 +4,11 @@ import { BrowserModule } from '@angular/platform-browser';
// --- Map
import { LeafletModule } from '@asymmetrik/ngx-leaflet';
// --- MQTT
import { MqttModule } from 'ngx-mqtt';
import { MQTTconfig } from './../environments/environment';
// --- WS
// import * as SockJS from 'sockjs-client';
......@@ -14,7 +19,6 @@ import { CoreModule } from './core/core.module';
// --- Services
import { ApiService } from "./core/api.service";
// import { StompService, StompConfig } from '@stomp/ng2-stompjs';
import { environment } from './../environments/environment';
// --- Components
import { AppComponent } from './app.component';
......@@ -35,7 +39,8 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
SharedModule,
CoreModule,
LeafletModule,
BrowserAnimationsModule
BrowserAnimationsModule,
MqttModule.forRoot(MQTTconfig)
],
providers: [ApiService],
bootstrap: [AppComponent]
......
.map {
margin-bottom: 20px;
height: 70vh
}
table {
width: 100%;
}
.table {
margin-bottom: 35px;
th.mat-header-cell {
vertical-align: middle;
}
}
\ No newline at end of file
import { NONE_TYPE } from '@angular/compiler';
import { Component, OnInit } from '@angular/core';
import * as L from "leaflet";
class Location {
id: string;
type = 'position';
lat: Float32Array;
lng: Float32Array;
constructor(obj: any, id: any) {
this.id = id
this.lat = obj.lat
this.lng = obj.lng
}
}
import { Subscription } from 'rxjs';
class Measurements {
id: string
type = 'measurements'
data: number[];
import * as L from "leaflet";
import { IMqttMessage, MqttService } from 'ngx-mqtt';
constructor(dist: any, id: any) {
this.id = id
this.data = dist
}
}
import { environment } from 'src/environments/environment';
import {RelativePos, WGS84} from 'src/app/model/base-model';
@Component({
selector: 'app-map',
......@@ -33,90 +14,122 @@ class Measurements {
})
export class MapComponent implements OnInit {
_stompService: any;
map: L.Map;
private subsPosition: Subscription;
private subsOrigin: Subscription;
constructor() {
this.map = L.map('map', {
center: [51.505, -0.09],
zoom: 13
});
}
private map!: L.Map;
ngOnInit(): void {
// wait on new Location
this._stompService.watch('/topic/locations').subscribe((message: any) => {
let payload = JSON.parse(message.body);
this.addNewMarker(payload)
private origin!: WGS84;
agentsInfo = new Map();
markOverlays = new Map();
posOverlays: { [key: string]: L.LayerGroup<any> } = {};
constructor(private _mqttService: MqttService) {
this.origin = {"latitude": 51.02545, "longitude": 13.72295}
this.subsPosition = this._mqttService.observe('testtopic/5699').subscribe((message: IMqttMessage) => {
let pos: RelativePos = JSON.parse(message.payload.toString())
this.updatePosition('default', pos)
});
// wait on new measurements
this._stompService.watch('/topic/positions').subscribe((message: any) => {
let payload = JSON.parse(message.body);
console.log('positions', payload)
this.addPosition(payload)
this.subsOrigin = this._mqttService.observe('testtopic/5699/origin').subscribe((message: IMqttMessage) => {
this.origin = JSON.parse(message.payload.toString())
});
}
addPosition(point: any) {
let marker = L.marker(point.position, {
icon: L.icon({
iconSize: [25, 41],
iconAnchor: [13, 41],
iconUrl: 'assets/marker-icon-red.png',
iconRetinaUrl: 'assets/marker-icon-2x-red.png',
shadowUrl: 'assets/marker-shadow.png'
})
}).bindPopup(point.id).openPopup();
marker.addTo(this.map);
}
ngOnInit(): void {}
// --- Controllers
updatePosition(key: string, pos: RelativePos) {
// estimated position of an agent
let glob_pos = this.convert2wgs(pos)
// let point = L.point(pos.x, pos.y);
// let glob_pos = (this.map).layerPointToLatLng(point)
// --- Leyers
if (key in this.posOverlays) {
this.posOverlays[key].clearLayers();
} else {
this.posOverlays[key] = L.layerGroup().addTo(<L.Map>this.map)
}
// --- Info
this.agentsInfo.set(key, {"glob_pos": glob_pos})
L.circle(glob_pos, 6, { color: '#d32f2f' }
).addTo(this.posOverlays[key]);
}
convert2wgs(pos: RelativePos) {
let origin = L.latLng([this.origin.latitude, this.origin.longitude]);
let point = this.map.latLngToContainerPoint(origin);
let newPoint = L.point([point.x + pos.x, point.y + pos.y]);
let newLatLng = this.map.containerPointToLatLng(newPoint);
return newLatLng
}
// @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: '&copy; <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: '&copy; <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.streets',
id: 'mapbox.gis',
attribution: 'Tiles &copy; Esri &mdash; 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>'
})
options = {
layers: [this.streetMaps],
zoom: 15,
center: L.latLng([51.037845, 13.762852])
layers: [this.mapBoxMaps],
zoom: 19,
center: L.latLng([51.02545, 13.72295])
};
onMapReady(map: L.Map) {
this.map = map
// Layers control object with our two base layers and the three overlay layers
this.map = map;
let baseLayers = {
'MapBox': this.mapBoxMaps,
'Street Maps': this.streetMaps,
'Wikimedia Maps': this.wMaps,
'Satellite': this.satelliteMaps
}
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> Agents </span><br>';
div.innerHTML += '<i class="est-pos"></i> <span> Estimated position </span><br>';
return div;
};
legend.addTo(this.map);
}
addNewMarker(obj: any) {
let marker = L.marker([obj.lat, obj.lng], {
icon: L.icon({
iconSize: [25, 41],
iconAnchor: [13, 41],
iconUrl: 'assets/marker-icon-grey.png',
iconRetinaUrl: 'assets/marker-icon-2x-grey.png',
shadowUrl: 'assets/marker-shadow.png'
})
}).bindPopup(obj.id).openPopup();
marker.addTo(this.map);
public ngOnDestroy() {
this.subsPosition.unsubscribe();
this.subsOrigin.unsubscribe();
}
}
export interface WGS84 {
latitude: number
longitude: number
}
export interface RelativePos {
x: number
y: number
}
interface IposConfigWrapper {
frames: IposFrameConfig[]
objects: IposObject[]
objectConfigs: IposObjectConfig[]
refSystems: RefSystem[]
monitoringRequests: IposMonitoringRequest[]
}
interface IposObjectConfig {
agentId: string
sensorId: string
agentType: string
sensorType: string
}
// note: IposObjectConfigs are used to register sensors. Beacon-positions are POIs and should be sent to sensor after registration. Bluetooth/UWB sensor need to know a reference system id. All Beacon-position sent to the Bluetooth/UWB sensor should have the same reference system id
interface IposPositionEvent {
object: IposObject[]
type: string
// repeated IposZoneDescriptor zoneDescriptors = 2; // contains information about all zones that this position belongs to
}
interface IposZoneDescriptor {
zoneId: string
type: string
}
interface IposObject {
id: string
sensorId: string
type: string
sensorType: string
position: IposPosition
orientation: IposSimpleOrientation
lastPosUpdate: string
}
interface IposFrameConfig {
id: string
space: IposSpace[]
}
interface RefSystem {
id: string
position: IposPosition
orientation: IposSimpleOrientation
}
interface IposMonitoringRequest {
frameId: string
// repeated string frameIds = 1;
delta: number
updateFrequency: number
type: string[]
id: string[]
fusionStrategy: string
exit_notification: boolean
properties: string[]
monitoringTaskId: string
requestorProtocol: string
}
interface IposMonitoringResponse {
monitoringTaskId: string
status: string
}
interface IposPosition {
refSystemId: string
point: IposPoint3D
accuracy: number
}
interface IposPoint3D {
x: number
y: number
z: number
}
interface IposSpace {
position: IposPosition
orientation: IposSimpleOrientation
x: number
y: number
z: number
}
interface IposSimpleOrientation {
x: number
y: number
z: number
w: number
}
......@@ -47,7 +47,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
MatCardModule,
MatExpansionModule,
MatSidenavModule,
MatTooltipModule
MatTooltipModule,
],
exports: [
FormsModule,
......@@ -67,7 +67,7 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
MatCardModule,
MatExpansionModule,
MatSidenavModule,
MatTooltipModule
MatTooltipModule,
]
})
export class SharedModule { }
......@@ -2,17 +2,27 @@
// `ng build` replaces `environment.ts` with `environment.prod.ts`.
// The list of file replacements can be found in `angular.json`.
import { IMqttServiceOptions } from 'ngx-mqtt';
export const environment = {
production: false,
APIEndpoint: 'http://localhost:7071',
mapbox: {
accessToken: 'pk.eyJ1IjoidmFsYXZhbmNhIiwiYSI6ImNrbGZlNzhpaTJhb3oyeG4weHEyZ2dvaDMifQ.3CSKC5AkzxrAtQ40BD5tsQ'
accessToken1: 'pk.eyJ1IjoidmFsYXZhbmNhIiwiYSI6ImNrbGZlNzhpaTJhb3oyeG4weHEyZ2dvaDMifQ.3CSKC5AkzxrAtQ40BD5tsQ',
accessToken2: 'pk.eyJ1IjoidmFsYXZhbmNhIiwiYSI6ImNrbGZlYm13ZTJtZ2gyb25wbGhqdGhmZzkifQ.atRzBqwKjY9wEUlue2YLzQ'
},
indoorequal: {
APIkey: 'l70N1y3m02lRDrlIqOzYyB'
}
},
};
export const MQTTconfig: IMqttServiceOptions = {
hostname: 'broker.hivemq.com',
port: 8000,
path: '/mqtt'
};
......
......@@ -11,6 +11,10 @@
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<app-root></app-root>
<app-root>
<div style="margin:20px; font-size:16px;">
Loading...
</div>
</app-root>
</body>
</html>
......@@ -18,3 +18,54 @@ app-root {
html, body { height: 100%; }
body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
/*Legend specific*/
.legend {
padding: 6px 8px;
font: 14px Arial, Helvetica, sans-serif;
background: white;
background: rgba(255, 255, 255, 0.8);
/*box-shadow: 0 0 15px rgba(0, 0, 0, 0.2);*/
/*border-radius: 5px;*/
line-height: 24px;
color: $primary-text-color;
h4 {
text-align: center;
font-size: 16px;
margin: 2px 12px 8px;
color: $primary-text-color;
}
span {
position: relative;
bottom: 3px;
}
i {
width: 18px;
height: 18px;
float: left;
margin: 0 8px 0 0;
opacity: 0.7;
.icon {
background-size: 18px;
background-color: rgba(255, 255, 255, 1);
}
}
img {
height: 35px;
}
.est-pos {
border: 3px solid #d32f2f;
background-color: rgba(211, 47, 47, .4);
border-radius: 50%;
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment