Skip to content

Commit

Permalink
Close #1293 markers: support polygons with holes
Browse files Browse the repository at this point in the history
  • Loading branch information
mistic100 committed May 15, 2024
1 parent 9d0b53d commit 640aeeb
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 24 deletions.
11 changes: 8 additions & 3 deletions examples/plugin-markers.html
Original file line number Diff line number Diff line change
Expand Up @@ -210,16 +210,21 @@ <h2>Lorem ipsum</h2>
id: 'polygon-1',
// prettier-ignore
polygonPixels: [
[2941, 1413], [3042, 1402], [3041, 1555], [2854, 1559],
[2739, 1516], [2775, 1469], [2941, 1413],
[
[2941, 1413], [3042, 1402], [3041, 1555], [2854, 1559],
[2739, 1516], [2775, 1469], [2941, 1413],
],
[
[2900, 1450], [2950, 1450], [2950, 1500], [2900, 1500],
]
],
svgStyle: {
fill: 'rgba(255,0,0,0.2)',
stroke: 'rgba(255, 0, 50, 0.8)',
strokeWidth: '2px',
},
tooltip: {
content: 'Simple polygon',
content: 'Polygon with hole',
position: 'bottom right',
},
});
Expand Down
77 changes: 58 additions & 19 deletions packages/markers-plugin/src/markers/MarkerPolygon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ import { AbstractDomMarker } from './AbstractDomMarker';
* @internal
*/
export class MarkerPolygon extends AbstractDomMarker {

private positions3D: Vector3[][];

constructor(viewer: Viewer, plugin: MarkersPlugin, config: MarkerConfig) {
super(viewer, plugin, config);
}

override createElement(): void {
this.element = document.createElementNS(SVG_NS, this.isPolygon ? 'polygon' : 'polyline');
this.element = document.createElementNS(SVG_NS, 'path');
this.element[MARKER_DATA] = this;
}

Expand Down Expand Up @@ -45,16 +48,34 @@ export class MarkerPolygon extends AbstractDomMarker {
return this.type === MarkerType.polyline || this.type === MarkerType.polylinePixels;
}

private get coords(): [number, number][][] {
return this.definition;
}

override render(): Point {
const positions = this.__getPolyPositions();
const isVisible = positions.length > (this.isPolygon ? 2 : 1);
const positions = this.__getAllPolyPositions();
const isVisible = positions[0].length > (this.isPolygon ? 2 : 1);

if (isVisible) {
const position = this.viewer.dataHelper.sphericalCoordsToViewerCoords(this.state.position);

const points = positions.map((pos) => pos.x - position.x + ',' + (pos.y - position.y)).join(' ');
const points = positions
.filter((innerPos, i) => {
return innerPos.length > 0 && (this.isPolygon || i === 0);
})
.map((innerPos, i) => {
let innerPoints = 'M';
innerPoints += (i === 0 ? innerPos : innerPos.reverse())
.map((pos) => `${pos.x - position.x},${pos.y - position.y}`)
.join('L');
if (this.isPolygon) {
innerPoints += 'Z';
}
return innerPoints;
})
.join(' ');

this.domElement.setAttributeNS(null, 'points', points);
this.domElement.setAttributeNS(null, 'd', points);
this.domElement.setAttributeNS(null, 'transform', `translate(${position.x} ${position.y})`);

return position;
Expand Down Expand Up @@ -89,49 +110,67 @@ export class MarkerPolygon extends AbstractDomMarker {
}

// fold arrays: [1,2,3,4] => [[1,2],[3,4]]
const actualPoly: any = this.config[this.type];
let actualPoly: any = this.config[this.type];
if (!Array.isArray(actualPoly[0])) {
for (let i = 0; i < actualPoly.length; i++) {
// @ts-ignore
actualPoly.splice(i, 2, [actualPoly[i], actualPoly[i + 1]]);
}
}

if (!Array.isArray(actualPoly[0][0])) {
actualPoly = [actualPoly];
}

// convert texture coordinates to spherical coordinates
if (this.isPixels) {
this.definition = (actualPoly as Array<[number, number]>).map((coord) => {
const sphericalCoords = this.viewer.dataHelper.textureCoordsToSphericalCoords({
textureX: coord[0],
textureY: coord[1],
this.definition = (actualPoly as [number, number][][]).map((coords) => {
return coords.map((coord) => {
const sphericalCoords = this.viewer.dataHelper.textureCoordsToSphericalCoords({
textureX: coord[0],
textureY: coord[1],
});
return [sphericalCoords.yaw, sphericalCoords.pitch];
});
return [sphericalCoords.yaw, sphericalCoords.pitch];
});
}
// clean angles
else {
this.definition = (actualPoly as Array<[number | string, number | string]>).map((coord) => {
return [utils.parseAngle(coord[0]), utils.parseAngle(coord[1], true)];
this.definition = (actualPoly as [number | string, number | string][][]).map((coords) => {
return coords.map((coord) => {
return [utils.parseAngle(coord[0]), utils.parseAngle(coord[1], true)];
});
});
}

const centroid = this.isPolygon ? getPolygonCenter(this.definition) : getPolylineCenter(this.definition);
const centroid = this.isPolygon ? getPolygonCenter(this.coords[0]) : getPolylineCenter(this.coords[0]);
this.state.position = { yaw: centroid[0], pitch: centroid[1] };

// compute x/y/z positions
this.state.positions3D = (this.definition as Array<[number, number]>).map((coord) => {
return this.viewer.dataHelper.sphericalCoordsToVector3({ yaw: coord[0], pitch: coord[1] });
this.positions3D = this.coords.map((coords) => {
return coords.map((coord) => {
return this.viewer.dataHelper.sphericalCoordsToVector3({ yaw: coord[0], pitch: coord[1] });
});
});

this.state.positions3D = this.positions3D[0];
}

private __getAllPolyPositions(): Point[][] {
return this.positions3D.map(positions => {
return this.__getPolyPositions(positions);
});
}

/**
* Computes viewer coordinates of each point of a polygon/polyline<br>
* It handles points behind the camera by creating intermediary points suitable for the projector
*/
private __getPolyPositions(): Point[] {
const nbVectors = this.state.positions3D.length;
private __getPolyPositions(positions: Vector3[]): Point[] {
const nbVectors = positions.length;

// compute if each vector is visible
const positions3D = this.state.positions3D.map((vector) => {
const positions3D = positions.map((vector) => {
return {
vector: vector,
visible: vector.dot(this.viewer.state.direction) > 0,
Expand Down
12 changes: 10 additions & 2 deletions packages/markers-plugin/src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,20 @@ export type MarkerConfig = {
* Array of points defining the polygon in spherical coordinates
*/
// eslint-disable-next-line @typescript-eslint/array-type
polygon?: [number, number][] | [string, string][] | number[] | string[];
polygon?:
| [number, number][]
| [number, number][][]
| [string, string][]
| number[]
| string[];
/**
* Array of points defining the polygon in pixel coordinates on the panorama image
*/
// eslint-disable-next-line @typescript-eslint/array-type
polygonPixels?: [number, number][] | number[];
polygonPixels?:
| [number, number][]
| [number, number][][]
| number[];
/**
* Array of points defining the polyline in spherical coordinates
*/
Expand Down

0 comments on commit 640aeeb

Please sign in to comment.