From 99c7dd85cedc9875f8dfd9f953fc3f4a8067ea8a Mon Sep 17 00:00:00 2001 From: Oscar Lorentzon Date: Thu, 23 Jun 2016 22:31:25 +0200 Subject: [PATCH] Create polygon tags. Add support for creating new polygons. Remove last vertex by clicking it. Abort creation by clicking original vertext when fewer than 4. Complete polygon by clicking original vertex. --- debug/tags.html | 9 +- src/component/tag/TagComponent.ts | 13 ++- src/component/tag/TagCreator.ts | 9 ++ src/component/tag/tag/OutlineCreateTag.ts | 122 ++++++++++++++++++---- styles/TagComponent.css | 6 ++ 5 files changed, 132 insertions(+), 27 deletions(-) diff --git a/debug/tags.html b/debug/tags.html index 3fe0db70..70291a2e 100644 --- a/debug/tags.html +++ b/debug/tags.html @@ -14,6 +14,7 @@
+ @@ -79,14 +80,14 @@ var createdIndex = 0; - function createOutlineTag(geometry) { + function createOutlineTag(geometry, text) { createdIndex += 1; var id = "created" + createdIndex; var options = { editable: true, lineColor: 0x00FFFF, lineWidth: 1, - text: "Rectangle", + text: text, textColor: 0x00FFFF, }; @@ -114,7 +115,9 @@ tagComponent.on(Mapillary.TagComponent.TagComponent.geometrycreated, function(geometry) { if (geometry instanceof Mapillary.TagComponent.RectGeometry) { - createOutlineTag(geometry); + createOutlineTag(geometry, "Rectangle"); + } else if (geometry instanceof Mapillary.TagComponent.PolygonGeometry) { + createOutlineTag(geometry, "Polygon"); } else if (geometry instanceof Mapillary.TagComponent.PointGeometry) { createSpotTag(geometry); } diff --git a/src/component/tag/TagComponent.ts b/src/component/tag/TagComponent.ts index 62545a14..eca36484 100644 --- a/src/component/tag/TagComponent.ts +++ b/src/component/tag/TagComponent.ts @@ -12,6 +12,8 @@ import { ITagConfiguration, PointGeometry, OutlineCreateTag, + PolygonGeometry, + RectGeometry, Tag, TagCreator, TagDOMRenderer, @@ -413,7 +415,8 @@ export class TagComponent extends Component { .flatMapLatest( (configuration: ITagConfiguration): rx.Observable => { return configuration.creating && - configuration.createType === "rect" ? + configuration.createType === "rect" || + configuration.createType === "polygon" ? this._validBasicClick$.take(1) : rx.Observable.empty(); }) @@ -468,7 +471,11 @@ export class TagComponent extends Component { camera, transform); - tag.geometry.setVertex2d(3, basic, transform); + if (tag.geometry instanceof RectGeometry) { + tag.geometry.setVertex2d(3, basic, transform); + } else if (tag.geometry instanceof PolygonGeometry) { + tag.geometry.setVertex2d((tag.geometry).polygon.length - 2, basic, transform); + } }); this._addPointSubscription = this._creating$ @@ -621,7 +628,7 @@ export class TagComponent extends Component { this._container.spriteService.spriteAtlas$, this._tags$.startWith([]), this._tagChanged$.startWith(null), - this._tagCreator.tag$.startWith(null), + this._tagCreator.tag$.merge(this._createGeometryChanged$).startWith(null), (rc: RenderCamera, atlas: ISpriteAtlas, tags: Tag[], tag: Tag, createTag: OutlineCreateTag): [RenderCamera, ISpriteAtlas, Tag[], Tag, OutlineCreateTag] => { return [rc, atlas, tags, tag, createTag]; diff --git a/src/component/tag/TagCreator.ts b/src/component/tag/TagCreator.ts index 7e60c5f7..e33f7c07 100644 --- a/src/component/tag/TagCreator.ts +++ b/src/component/tag/TagCreator.ts @@ -5,6 +5,7 @@ import * as rx from "rx"; import { GeometryType, OutlineCreateTag, + PolygonGeometry, RectGeometry, } from "../../Component"; @@ -56,6 +57,14 @@ export class TagCreator { coordinate[1], ]); + return new OutlineCreateTag(geometry); + } else if (type === "polygon") { + let geometry: PolygonGeometry = new PolygonGeometry([ + [coordinate[0], coordinate[1]], + [coordinate[0], coordinate[1]], + [coordinate[0], coordinate[1]], + ]); + return new OutlineCreateTag(geometry); } diff --git a/src/component/tag/tag/OutlineCreateTag.ts b/src/component/tag/tag/OutlineCreateTag.ts index 8f8fd284..6d7cd434 100644 --- a/src/component/tag/tag/OutlineCreateTag.ts +++ b/src/component/tag/tag/OutlineCreateTag.ts @@ -4,7 +4,11 @@ import * as rx from "rx"; import * as THREE from "three"; import * as vd from "virtual-dom"; -import {VertexGeometry, RectGeometry} from "../../../Component"; +import { + PolygonGeometry, + RectGeometry, + VertexGeometry, +} from "../../../Component"; import {Transform} from "../../../Geo"; export class OutlineCreateTag { @@ -64,41 +68,117 @@ export class OutlineCreateTag { vd.VNode[] { let vNodes: vd.VNode[] = []; - let polygonPoints3d: number[][] = this._geometry.getVertices3d(transform); - let abort: (e: MouseEvent) => void = (e: MouseEvent): void => { + e.stopPropagation(); this._aborted$.onNext(this); }; - let topLeftCameraSpace: THREE.Vector3 = this._convertToCameraSpace(polygonPoints3d[1], matrixWorldInverse); - if (topLeftCameraSpace.z < 0) { - let centerCanvas: number[] = this._projectToCanvas(topLeftCameraSpace, projectionMatrix); - let centerCss: string[] = centerCanvas.map((coord: number): string => { return (100 * coord) + "%"; }); + if (this._geometry instanceof RectGeometry) { + let topLeftPoint3d: number[] = this._geometry.getVertex3d(1, transform); - let pointProperties: vd.createProperties = { - style: { background: "#FFFFFF", left: centerCss[0], position: "absolute", top: centerCss[1] }, - }; + let topLeftCameraSpace: THREE.Vector3 = this._convertToCameraSpace(topLeftPoint3d, matrixWorldInverse); + if (topLeftCameraSpace.z < 0) { + let centerCanvas: number[] = this._projectToCanvas(topLeftCameraSpace, projectionMatrix); + let centerCss: string[] = centerCanvas.map((coord: number): string => { return (100 * coord) + "%"; }); - let completerProperties: vd.createProperties = { - onclick: abort, - style: { left: centerCss[0], position: "absolute", top: centerCss[1] }, - }; + let pointProperties: vd.createProperties = { + style: { background: "#FFFFFF", left: centerCss[0], position: "absolute", top: centerCss[1] }, + }; - vNodes.push(vd.h("div.TagInteractor", completerProperties, [])); - vNodes.push(vd.h("div.TagVertex", pointProperties, [])); + let completerProperties: vd.createProperties = { + onclick: abort, + style: { left: centerCss[0], position: "absolute", top: centerCss[1] }, + }; + + vNodes.push(vd.h("div.TagInteractor", completerProperties, [])); + vNodes.push(vd.h("div.TagVertex", pointProperties, [])); + } + } else if (this._geometry instanceof PolygonGeometry) { + let polygonGeometry: PolygonGeometry = this._geometry; + + if (polygonGeometry.polygon.length > 3) { + let lastVertex3d: number[] = this._geometry.getVertex3d(polygonGeometry.polygon.length - 3, transform); + + let lastCameraSpace: THREE.Vector3 = this._convertToCameraSpace(lastVertex3d, matrixWorldInverse); + if (lastCameraSpace.z < 0) { + let centerCanvas: number[] = this._projectToCanvas(lastCameraSpace, projectionMatrix); + let centerCss: string[] = centerCanvas.map((coord: number): string => { return (100 * coord) + "%"; }); + + let remove: (e: MouseEvent) => void = (e: MouseEvent): void => { + e.stopPropagation(); + polygonGeometry.removeVertex2d(polygonGeometry.polygon.length - 3); + }; + + let completerProperties: vd.createProperties = { + onclick: remove, + style: { left: centerCss[0], position: "absolute", top: centerCss[1] }, + }; + + vNodes.push(vd.h("div.TagInteractor", completerProperties, [])); + } + } + + let firstVertex3d: number[] = this._geometry.getVertex3d(0, transform); + let firstCameraSpace: THREE.Vector3 = this._convertToCameraSpace(firstVertex3d, matrixWorldInverse); + if (firstCameraSpace.z < 0) { + let centerCanvas: number[] = this._projectToCanvas(firstCameraSpace, projectionMatrix); + let centerCss: string[] = centerCanvas.map((coord: number): string => { return (100 * coord) + "%"; }); + + let firstOnclick: (e: MouseEvent) => void = polygonGeometry.polygon.length > 4 ? + (e: MouseEvent): void => { + e.stopPropagation(); + polygonGeometry.removeVertex2d(polygonGeometry.polygon.length - 2); + this._created$.onNext(this); + } : + abort; + + let completerProperties: vd.createProperties = { + onclick: firstOnclick, + style: { left: centerCss[0], position: "absolute", top: centerCss[1] }, + }; + + let firstClass: string = polygonGeometry.polygon.length > 4 ? + "TagCompleter" : + "TagInteractor"; + + vNodes.push(vd.h("div." + firstClass, completerProperties, [])); + } + + let vertices3d: number[][] = this._geometry.getVertices3d(transform); + vertices3d.splice(-2, 2); + + for (let vertex of vertices3d) { + let vertexCameraSpace: THREE.Vector3 = this._convertToCameraSpace(vertex, matrixWorldInverse); + if (vertexCameraSpace.z < 0) { + let centerCanvas: number[] = this._projectToCanvas(vertexCameraSpace, projectionMatrix); + let centerCss: string[] = centerCanvas.map((coord: number): string => { return (100 * coord) + "%"; }); + + let pointProperties: vd.createProperties = { + style: { background: "#FFFFFF", left: centerCss[0], position: "absolute", top: centerCss[1] }, + }; + + vNodes.push(vd.h("div.TagVertex", pointProperties, [])); + } + } } return vNodes; } public addPoint(point: number[]): void { - let rectGeometry: RectGeometry = this._geometry; + if (this._geometry instanceof RectGeometry) { + let rectGeometry: RectGeometry = this._geometry; - if (!rectGeometry.validate(point)) { - return; + if (!rectGeometry.validate(point)) { + return; + } + + this._created$.onNext(this); + } else if (this._geometry instanceof PolygonGeometry) { + let polygonGeometry: PolygonGeometry = this._geometry; + + polygonGeometry.addVertex2d(point); } - - this._created$.onNext(this); } private _getPositions(polygon3d: number[][]): Float32Array { diff --git a/styles/TagComponent.css b/styles/TagComponent.css index d5c0e182..15ccae18 100644 --- a/styles/TagComponent.css +++ b/styles/TagComponent.css @@ -49,6 +49,7 @@ } .TagInteractor, +.TagCompleter, .TagSpotInteractor { transform: translate(-50%, -50%); pointer-events: all; @@ -58,10 +59,15 @@ opacity: 0; } +.TagCompleter { + background: limegreen; +} + .TagInteractor { background: orangered; } +.TagCompleter:hover, .TagInteractor:hover { opacity: 0.6; }