Skip to content
This repository has been archived by the owner on Mar 8, 2023. It is now read-only.

Commit

Permalink
HARP-11574: Supports GeoPolygon in MapView.lookAt (#1771)
Browse files Browse the repository at this point in the history
Signed-off-by: Frauke Fritz <frauke.fritz@here.com>
  • Loading branch information
FraukeF committed Aug 19, 2020
1 parent 8f03111 commit 36fa049
Show file tree
Hide file tree
Showing 14 changed files with 1,075 additions and 199 deletions.
198 changes: 155 additions & 43 deletions @here/harp-examples/src/bounds-generation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,18 @@
import {
FeaturesDataSource,
MapViewFeature,
MapViewMultiLineFeature,
MapViewMultiPointFeature,
MapViewPolygonFeature
} from "@here/harp-features-datasource";
import { GeoCoordinates, mercatorProjection } from "@here/harp-geoutils";
import {
GeoBox,
GeoCoordinates,
GeoPolygon,
mercatorProjection,
sphereProjection
} from "@here/harp-geoutils";
import { geoCoordLikeToGeoPointLike } from "@here/harp-geoutils/lib/coordinates/GeoCoordLike";
import { MapControls, MapControlsUI } from "@here/harp-map-controls";
import { BoundsGenerator, CopyrightElementHandler, MapView } from "@here/harp-mapview";
import { VectorTileDataSource } from "@here/harp-vectortile-datasource";
Expand All @@ -18,12 +26,19 @@ import { apikey } from "../config";

export namespace BoundsExample {
const message = document.createElement("div");
message.innerHTML = ' Press "space" to generate and draw a bounds polygon of the current view ';
message.innerHTML = `
<br /> Press "space" to generate and draw a bounds polygon of the current view
<br /> Press "h" to look at the last created Polygon's BoundingBox
<br /> Press "g" to look at the last created Polygon
<br /> Press "b" to show the boundingbox of the Polygon
<br /> Press "p" to toggle the projection (!!bounds creation for sphere projection is not yet implemented)`;

message.style.position = "absolute";
message.style.cssFloat = "right";
message.style.top = "10px";
message.style.right = "10px";
message.style.textAlign = "left";
message.style.textShadow = "0px 0px 2px gray";
document.body.appendChild(message);

// Create a new MapView for the HTMLCanvasElement of the given id.
Expand All @@ -46,12 +61,38 @@ export namespace BoundsExample {
renderOrder: 10003,
attr: {
color: ["get", "color"], // "#77ccff",
opacity: 0.5,
opacity: 0.2,
lineWidth: 1,
lineColor: "#ff0000",
enabled: true
}
},
{
when: [
"all",
["==", ["geometry-type"], "LineString"],
["==", ["get", "name"], "bboxline"]
],
technique: "solid-line",
renderOrder: 10005,
attr: {
color: "#0ff",
lineWidth: "5px"
}
},
{
when: [
"all",
["==", ["geometry-type"], "Point"],
["==", ["get", "name"], "bbox"]
],
technique: "circles",
renderOrder: 10006,
attr: {
color: "#00f",
size: 20
}
},
{
when: "$geometryType == 'point'",
technique: "circles",
Expand Down Expand Up @@ -86,60 +127,44 @@ export namespace BoundsExample {
});

addVectorTileDataSource(map);
const featureList: MapViewFeature[] = []; //createFeatureList();
let featuresDataSource: FeaturesDataSource | undefined;
//@ts-ignore
featuresDataSource = addFeaturesDataSource(map, featureList);
let viewpoly: MapViewPolygonFeature;
let cornerpoints: MapViewMultiPointFeature;
const featuresDataSource = addFeaturesDataSource(map, []);
const boundsGenerator = new BoundsGenerator(
map.camera,
map.projection,
map.tileWrappingEnabled
);

let bounds: GeoPolygon | undefined;
let showBoundingBox: boolean = false;

window.addEventListener("keyup", event => {
switch (event.key) {
case " ":
// Generate the the bounds of the current view and add them as a feature
const corners = boundsGenerator.generate();
// eslint-disable-next-line no-console
console.log(corners);
if (corners && corners.length > 0) {
//add starting vertex to the end to close the polygon
corners.push(corners[0].clone());
}
//convert the array to an array usable for the MapViewPolygonFeature
const polygonArray: number[][][] = [];
const pointArray: number[][] = [];
polygonArray.push(pointArray);
corners.forEach(corner => {
if (corner === null) {
return;
}
pointArray.push([corner.longitude, corner.latitude, 50]);
});
bounds = boundsGenerator.generate();

if (viewpoly) {
//remove the former polygon
featuresDataSource?.remove(viewpoly);
if (bounds !== undefined) {
updateBoundsFeatures(bounds, featuresDataSource);
}
//add the new polygon
viewpoly = new MapViewPolygonFeature(polygonArray, {
name: "newpoly",
height: 10000,
color: "#ffff00"
});
featuresDataSource?.add(viewpoly);

// add circles at the corner points
if (cornerpoints) {
featuresDataSource?.remove(cornerpoints);
break;
case "h":
map.lookAt({ bounds: bounds?.getGeoBoundingBox() });
break;
case "g":
map.lookAt({ bounds });
break;
case "p":
map.projection =
map.projection === mercatorProjection
? sphereProjection
: mercatorProjection;
break;
case "b":
if (bounds) {
showBoundingBox = showBoundingBox ? false : true;
updateBoundingBoxFeatures(bounds, featuresDataSource, showBoundingBox);
}
cornerpoints = new MapViewMultiPointFeature(pointArray, {
name: "cornerpoints"
});
featuresDataSource?.add(cornerpoints);
break;
case "l":
// eslint-disable-next-line no-console
Expand Down Expand Up @@ -169,6 +194,93 @@ export namespace BoundsExample {
return map;
}

let viewpoly: MapViewPolygonFeature;
let cornerpoints: MapViewMultiPointFeature;
let bboxFeature: MapViewMultiPointFeature;
let bboxLineFeature: MapViewMultiLineFeature;

function updateBoundsFeatures(polygon: GeoPolygon, featuresDataSource: FeaturesDataSource) {
const corners = polygon.coordinates;
if (corners && corners.length > 0) {
//add starting vertex to the end to close the polygon
corners.push((corners[0] as GeoCoordinates).clone());
}
//convert the array to an array usable for the MapViewPolygonFeature
const polygonArray: number[][][] = [];
const pointArray: number[][] = [];
polygonArray.push(pointArray);
corners.forEach(corner => {
if (corner === null) {
return;
}
pointArray.push(geoCoordLikeToGeoPointLike(corner) as number[]);
});

if (viewpoly) {
//remove the former polygon
featuresDataSource?.remove(viewpoly);
}
//add the new polygon
viewpoly = new MapViewPolygonFeature(polygonArray, {
name: "newpoly",
height: 10000,
color: "#ffff00"
});
featuresDataSource?.add(viewpoly);

// add circles at the corner points
if (cornerpoints) {
featuresDataSource?.remove(cornerpoints);
}
cornerpoints = new MapViewMultiPointFeature(pointArray, {
name: "cornerpoints"
});
featuresDataSource?.add(cornerpoints);
}

function updateBoundingBoxFeatures(
geoPolygon: GeoPolygon,
featuresDataSource: FeaturesDataSource,
isVisible: boolean = true
) {
if (bboxFeature) {
featuresDataSource?.remove(bboxFeature);
}
if (bboxLineFeature) {
featuresDataSource?.remove(bboxLineFeature);
}
if (isVisible) {
const geoBBox = geoPolygon.getGeoBoundingBox() as GeoBox;

const geoBBoxCornerArray: number[][] = [];
[
new GeoCoordinates(geoBBox?.south, geoBBox?.west, 70),
new GeoCoordinates(geoBBox?.south, geoBBox?.east, 70),
new GeoCoordinates(geoBBox?.north, geoBBox?.east, 70),
new GeoCoordinates(geoBBox?.north, geoBBox?.west, 70),
new GeoCoordinates(geoBBox?.south, geoBBox?.west, 70),
geoPolygon.getCentroid()
].forEach(point => {
if (!point) {
return;
}
geoBBoxCornerArray.push([
point.longitude,
point.latitude,
point.altitude as number
]);
});
bboxFeature = new MapViewMultiPointFeature(geoBBoxCornerArray, {
name: "bbox"
});
featuresDataSource?.add(bboxFeature);
bboxLineFeature = new MapViewMultiLineFeature([geoBBoxCornerArray], {
name: "bboxline"
});
featuresDataSource?.add(bboxLineFeature);
}
}

function addVectorTileDataSource(map: MapView) {
const omvDataSource = new VectorTileDataSource({
baseUrl: "https://vector.hereapi.com/v2/vectortiles/base/mc",
Expand Down
2 changes: 2 additions & 0 deletions @here/harp-geoutils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export * from "./lib/coordinates/GeoBoxExtentLike";
export * from "./lib/coordinates/GeoCoordinatesLike";
export * from "./lib/coordinates/GeoCoordinates";
export * from "./lib/coordinates/GeoPointLike";
export * from "./lib/coordinates/GeoPolygonLike";
export * from "./lib/coordinates/GeoPolygon";
export * from "./lib/coordinates/LatLngLike";
export * from "./lib/projection/EarthConstants";
export * from "./lib/projection/EquirectangularProjection";
Expand Down
4 changes: 2 additions & 2 deletions @here/harp-geoutils/lib/coordinates/GeoBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
* Licensed under Apache 2.0, see full license in LICENSE
* SPDX-License-Identifier: Apache-2.0
*/

import * as THREE from "three";

import { GeoBoxExtentLike } from "./GeoBoxExtentLike";
import { GeoCoordinates } from "./GeoCoordinates";
import { GeoCoordinatesLike } from "./GeoCoordinatesLike";

/**
* `GeoBox` is used to represent a bounding box in geo coordinates.
Expand Down Expand Up @@ -223,7 +223,7 @@ export class GeoBox implements GeoBoxExtentLike {
*
* @param point - The point that may expand the bounding box.
*/
growToContain(point: GeoCoordinates) {
growToContain(point: GeoCoordinatesLike) {
this.southWest.latitude = Math.min(this.southWest.latitude, point.latitude);
this.southWest.longitude = Math.min(this.southWest.longitude, point.longitude);
this.southWest.altitude =
Expand Down
33 changes: 33 additions & 0 deletions @here/harp-geoutils/lib/coordinates/GeoCoordLike.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2017-2020 HERE Europe B.V.
* Licensed under Apache 2.0, see full license in LICENSE
* SPDX-License-Identifier: Apache-2.0
*/
import { GeoCoordinatesLike, isGeoCoordinatesLike } from "./GeoCoordinatesLike";
import { GeoPointLike, isGeoPointLike } from "./GeoPointLike";
import { isLatLngLike, LatLngLike } from "./LatLngLike";

/**
* Represents an object in different geo coordinate formats
*/
export type GeoCoordLike = GeoPointLike | GeoCoordinatesLike | LatLngLike;

export function geoCoordLikeToGeoCoordinatesLike(coord: GeoCoordLike): GeoCoordinatesLike {
return isGeoCoordinatesLike(coord)
? coord
: isLatLngLike(coord)
? { latitude: coord.lat, longitude: coord.lng }
: { latitude: coord[1], longitude: coord[0] };
}

export function geoCoordLikeToGeoPointLike(coord: GeoCoordLike): GeoPointLike {
return isGeoPointLike(coord)
? coord
: isLatLngLike(coord)
? [coord.lng, coord.lat]
: [coord.longitude, coord.latitude];
}

export function isGeoCoordLike(object: any): boolean {
return isGeoCoordinatesLike(object) || isLatLngLike(object) || !isGeoPointLike(object);
}
6 changes: 1 addition & 5 deletions @here/harp-geoutils/lib/coordinates/GeoCoordinates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,17 @@
* Licensed under Apache 2.0, see full license in LICENSE
* SPDX-License-Identifier: Apache-2.0
*/

import * as THREE from "three";

import { GeoCoordinatesLike, isGeoCoordinatesLike } from "./GeoCoordinatesLike";
import { GeoCoordLike } from "./GeoCoordLike";
import { GeoPointLike, isGeoPointLike } from "./GeoPointLike";
import { isLatLngLike, LatLngLike } from "./LatLngLike";

export const MAX_LATITUDE = 90;
export const MIN_LATITUDE = -90;
export const MAX_LONGITUDE = 180;
export const MIN_LONGITUDE = -180;
/**
* Represents an object in different geo coordinate formats
*/
export type GeoCoordLike = GeoPointLike | GeoCoordinatesLike | LatLngLike;

/**
* `GeoCoordinates` is used to represent geo positions.
Expand Down
Loading

0 comments on commit 36fa049

Please sign in to comment.