From ae3dab81de2bfbbc2235453d7a1f4e5a52fa3667 Mon Sep 17 00:00:00 2001 From: Felipe Moreira <118832082+Felipemore96@users.noreply.github.com> Date: Wed, 13 Mar 2024 07:20:48 -0600 Subject: [PATCH 1/6] Implemented cameracontrols to simple2Dscene & added bounding box calculation to RoadNavigator --- src/civil/RoadNavigator/index.ts | 30 +++++++++++++++++++++++++++- src/civil/RoadPlanNavigator/index.ts | 5 +++++ src/core/Simple2DScene/index.ts | 16 +++++++-------- 3 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/civil/RoadNavigator/index.ts b/src/civil/RoadNavigator/index.ts index 73c6d57cc..cc9d93929 100644 --- a/src/civil/RoadNavigator/index.ts +++ b/src/civil/RoadNavigator/index.ts @@ -13,6 +13,8 @@ export abstract class RoadNavigator extends Component { abstract view: "horizontal" | "vertical"; + private totalBBox: THREE.Box3 = new THREE.Box3(); + protected _curves = new Set(); protected constructor(components: Components) { @@ -33,6 +35,7 @@ export abstract class RoadNavigator extends Component { const allIDs = ids || alignments.keys(); const scene = this.scene.get(); + this.totalBBox.makeEmpty(); for (const id of allIDs) { const alignment = alignments.get(id); @@ -49,12 +52,37 @@ export abstract class RoadNavigator extends Component { if (firstCurve) { const pos = curve.mesh.geometry.attributes.position.array; const [x, y, z] = pos; - this.scene.controls.target.set(x, y, z); + this.scene.controls.setTarget(x, y, z); this.scene.camera.position.set(x, y, z + 10); firstCurve = false; } } } + this.totalBBox.min.x = Number.MAX_VALUE; + this.totalBBox.min.y = Number.MAX_VALUE; + this.totalBBox.min.z = Number.MAX_VALUE; + this.totalBBox.max.x = -Number.MAX_VALUE; + this.totalBBox.max.y = -Number.MAX_VALUE; + this.totalBBox.max.z = -Number.MAX_VALUE; + for (const curve of this._curves) { + curve.mesh.geometry.computeBoundingBox(); + const cbox = curve.mesh.geometry.boundingBox; + if (!(cbox instanceof THREE.Box3)) { + return; + } + const max = cbox.max.clone().applyMatrix4(curve.mesh.matrixWorld); + const min = cbox.min.clone().applyMatrix4(curve.mesh.matrixWorld); + if (min instanceof THREE.Vector3 && max instanceof THREE.Vector3) { + if (max.x > this.totalBBox.max.x) this.totalBBox.max.x = min.x; + if (max.y > this.totalBBox.max.y) this.totalBBox.max.y = max.y; + if (min.x < this.totalBBox.min.x) this.totalBBox.min.x = min.x; + if (min.y < this.totalBBox.min.y) this.totalBBox.min.y = max.y; + } + } + } + + getTotalBBox(): THREE.Box3 { + return this.totalBBox; } clear() { diff --git a/src/civil/RoadPlanNavigator/index.ts b/src/civil/RoadPlanNavigator/index.ts index 0e88f9586..c0ffde855 100644 --- a/src/civil/RoadPlanNavigator/index.ts +++ b/src/civil/RoadPlanNavigator/index.ts @@ -22,8 +22,13 @@ export class RoadPlanNavigator extends RoadNavigator implements UI { this.components.ui.add(floatingWindow); floatingWindow.visible = false; const hContainer = this.scene.uiElement.get("container"); + console.log("hContainer", hContainer); + const totalBBox = this.getTotalBBox(); + console.log("totalBBox", totalBBox); floatingWindow.addChild(hContainer); + // this.scene.controls.fitToBox(totalBBox,false,); + floatingWindow.onResized.add(() => this.scene.grid.regenerate()); floatingWindow.slots.content.domElement.style.padding = "0"; diff --git a/src/core/Simple2DScene/index.ts b/src/core/Simple2DScene/index.ts index b4e8010f8..0447e1ab9 100644 --- a/src/core/Simple2DScene/index.ts +++ b/src/core/Simple2DScene/index.ts @@ -1,5 +1,5 @@ import * as THREE from "three"; -import { OrbitControls } from "three/examples/jsm/controls/OrbitControls"; +import CameraControls from "camera-controls"; import { Component, Updateable, @@ -49,7 +49,7 @@ export class Simple2DScene }>(); /** The camera controls that move around in the scene. */ - controls: OrbitControls; + readonly controls: CameraControls; /** The camera that renders the scene. */ readonly camera: THREE.OrthographicCamera; @@ -135,11 +135,11 @@ export class Simple2DScene this.renderer.overrideScene = this.scene; this.renderer.overrideCamera = this.camera; - this.controls = new OrbitControls(this.camera, renderer.domElement); - this.controls.target.set(0, 0, 0); - this.controls.enableRotate = false; - this.controls.enableZoom = true; - this.controls.addEventListener("change", () => this.grid.regenerate()); + this.controls = new CameraControls(this.camera, renderer.domElement); + this.controls.smoothTime = 0.6; + this.controls.setTarget(0, 0, 0); + this.controls.addEventListener("update", () => this.grid.regenerate()); + this.controls.mouseButtons.left = CameraControls.ACTION.TRUCK; } /** @@ -168,7 +168,7 @@ export class Simple2DScene /** {@link Updateable.update} */ async update() { await this.onBeforeUpdate.trigger(); - this.controls.update(); + this.controls.update(1 / 60); await this.renderer.update(); await this.onAfterUpdate.trigger(); } From 69a718c3dfdd70ebcaba0e091a9c97376cdd7e6c Mon Sep 17 00:00:00 2001 From: Felipe Moreira <118832082+Felipemore96@users.noreply.github.com> Date: Fri, 15 Mar 2024 15:15:07 -0600 Subject: [PATCH 2/6] FitToBox functionality activated for RoadNavigator tool --- src/civil/RoadNavigator/index.ts | 53 +++++++++------------------- src/civil/RoadPlanNavigator/index.ts | 5 --- src/core/Simple2DScene/index.ts | 13 ++++++- 3 files changed, 28 insertions(+), 43 deletions(-) diff --git a/src/civil/RoadNavigator/index.ts b/src/civil/RoadNavigator/index.ts index cc9d93929..17a5d9f8b 100644 --- a/src/civil/RoadNavigator/index.ts +++ b/src/civil/RoadNavigator/index.ts @@ -13,8 +13,6 @@ export abstract class RoadNavigator extends Component { abstract view: "horizontal" | "vertical"; - private totalBBox: THREE.Box3 = new THREE.Box3(); - protected _curves = new Set(); protected constructor(components: Components) { @@ -27,7 +25,7 @@ export abstract class RoadNavigator extends Component { return null as any; } - draw(model: FragmentsGroup, ids?: Iterable) { + async draw(model: FragmentsGroup, ids?: Iterable) { if (!model.civilData) { throw new Error("The provided model doesn't have civil data!"); } @@ -35,7 +33,11 @@ export abstract class RoadNavigator extends Component { const allIDs = ids || alignments.keys(); const scene = this.scene.get(); - this.totalBBox.makeEmpty(); + + const totalBBox: THREE.Box3 = new THREE.Box3(); + totalBBox.makeEmpty(); + totalBBox.min.set(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE); + totalBBox.max.set(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE); for (const id of allIDs) { const alignment = alignments.get(id); @@ -43,46 +45,23 @@ export abstract class RoadNavigator extends Component { throw new Error("Alignment not found!"); } - let firstCurve = true; - for (const curve of alignment[this.view]) { this._curves.add(curve); scene.add(curve.mesh); - if (firstCurve) { - const pos = curve.mesh.geometry.attributes.position.array; - const [x, y, z] = pos; - this.scene.controls.setTarget(x, y, z); - this.scene.camera.position.set(x, y, z + 10); - firstCurve = false; + if (!totalBBox.isEmpty()) { + totalBBox.expandByObject(curve.mesh); + } else { + curve.mesh.geometry.computeBoundingBox(); + const cbox = curve.mesh.geometry.boundingBox; + + if (cbox instanceof THREE.Box3) { + totalBBox.copy(cbox).applyMatrix4(curve.mesh.matrixWorld); + } } } } - this.totalBBox.min.x = Number.MAX_VALUE; - this.totalBBox.min.y = Number.MAX_VALUE; - this.totalBBox.min.z = Number.MAX_VALUE; - this.totalBBox.max.x = -Number.MAX_VALUE; - this.totalBBox.max.y = -Number.MAX_VALUE; - this.totalBBox.max.z = -Number.MAX_VALUE; - for (const curve of this._curves) { - curve.mesh.geometry.computeBoundingBox(); - const cbox = curve.mesh.geometry.boundingBox; - if (!(cbox instanceof THREE.Box3)) { - return; - } - const max = cbox.max.clone().applyMatrix4(curve.mesh.matrixWorld); - const min = cbox.min.clone().applyMatrix4(curve.mesh.matrixWorld); - if (min instanceof THREE.Vector3 && max instanceof THREE.Vector3) { - if (max.x > this.totalBBox.max.x) this.totalBBox.max.x = min.x; - if (max.y > this.totalBBox.max.y) this.totalBBox.max.y = max.y; - if (min.x < this.totalBBox.min.x) this.totalBBox.min.x = min.x; - if (min.y < this.totalBBox.min.y) this.totalBBox.min.y = max.y; - } - } - } - - getTotalBBox(): THREE.Box3 { - return this.totalBBox; + await this.scene.controls.fitToBox(totalBBox, false); } clear() { diff --git a/src/civil/RoadPlanNavigator/index.ts b/src/civil/RoadPlanNavigator/index.ts index c0ffde855..0e88f9586 100644 --- a/src/civil/RoadPlanNavigator/index.ts +++ b/src/civil/RoadPlanNavigator/index.ts @@ -22,13 +22,8 @@ export class RoadPlanNavigator extends RoadNavigator implements UI { this.components.ui.add(floatingWindow); floatingWindow.visible = false; const hContainer = this.scene.uiElement.get("container"); - console.log("hContainer", hContainer); - const totalBBox = this.getTotalBBox(); - console.log("totalBBox", totalBBox); floatingWindow.addChild(hContainer); - // this.scene.controls.fitToBox(totalBBox,false,); - floatingWindow.onResized.add(() => this.scene.grid.regenerate()); floatingWindow.slots.content.domElement.style.padding = "0"; diff --git a/src/core/Simple2DScene/index.ts b/src/core/Simple2DScene/index.ts index 0447e1ab9..11f75d8e3 100644 --- a/src/core/Simple2DScene/index.ts +++ b/src/core/Simple2DScene/index.ts @@ -111,7 +111,18 @@ export class Simple2DScene const { width, height } = this._size; // Creates the camera (point of view of the user) - this.camera = new THREE.OrthographicCamera(75, width / height); + const aspect = width / height; + const halfSize = this._frustumSize * 0.5; + + this.camera = new THREE.OrthographicCamera( + -halfSize * aspect, + halfSize * aspect, + halfSize, + -halfSize, + -1000, + 1000 + ); + this.scene.add(this.camera); this.camera.position.z = 10; From 5b7df251f7fdb607b0263d543d17be2014842513 Mon Sep 17 00:00:00 2001 From: Felipe Moreira <118832082+Felipemore96@users.noreply.github.com> Date: Sat, 23 Mar 2024 13:38:02 -0600 Subject: [PATCH 3/6] Added curve-highlighter to show curve information when clicked in PlanNavigatorView Still in testing phase --- src/civil/RoadNavigator/index.ts | 8 +- .../RoadNavigator/src/curve-highlighter.ts | 2 +- src/civil/RoadPlanNavigator/index.html | 3 +- src/civil/RoadPlanNavigator/index.ts | 6 ++ .../RoadPlanNavigator/src/plan-highlighter.ts | 78 +++++++++++++++++++ 5 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/civil/RoadPlanNavigator/src/plan-highlighter.ts diff --git a/src/civil/RoadNavigator/index.ts b/src/civil/RoadNavigator/index.ts index 5c041287d..7a30256cc 100644 --- a/src/civil/RoadNavigator/index.ts +++ b/src/civil/RoadNavigator/index.ts @@ -3,7 +3,7 @@ import * as FRAGS from "bim-fragment"; import { FragmentsGroup } from "bim-fragment"; import { Component, Event } from "../../base-types"; import { Components, Simple2DScene } from "../../core"; -import { CurveHighlighter } from "./src/curve-highlighter"; +// import { CurveHighlighter } from "./src/curve-highlighter"; export abstract class RoadNavigator extends Component { enabled = true; @@ -18,13 +18,13 @@ export abstract class RoadNavigator extends Component { private curveMeshes: THREE.Object3D[] = []; readonly onHighlight = new Event(); - highlighter: CurveHighlighter; + // highlighter: CurveHighlighter; protected constructor(components: Components) { super(components); this.caster.params.Line = { threshold: 5 }; this.scene = new Simple2DScene(this.components, false); - this.highlighter = new CurveHighlighter(this.scene.get()); + // this.highlighter = new CurveHighlighter(this.scene.get()); this.setupEvents(); } @@ -118,7 +118,7 @@ export abstract class RoadNavigator extends Component { } dispose() { - this.highlighter.dispose(); + // this.highlighter.dispose(); this.clear(); this.onHighlight.reset(); this.caster = null as any; diff --git a/src/civil/RoadNavigator/src/curve-highlighter.ts b/src/civil/RoadNavigator/src/curve-highlighter.ts index 7bbddc201..d91070b30 100644 --- a/src/civil/RoadNavigator/src/curve-highlighter.ts +++ b/src/civil/RoadNavigator/src/curve-highlighter.ts @@ -4,9 +4,9 @@ import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry'; import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'; export class CurveHighlighter { - private scene: THREE.Scene | THREE.Group; private _highlightColor: THREE.ColorRepresentation; activeSelection: Line2 | undefined | THREE.Line; + protected scene: THREE.Scene | THREE.Group; constructor(scene: THREE.Group | THREE.Scene) { this.scene = scene; diff --git a/src/civil/RoadPlanNavigator/index.html b/src/civil/RoadPlanNavigator/index.html index 0d254e4e7..9f68a7904 100644 --- a/src/civil/RoadPlanNavigator/index.html +++ b/src/civil/RoadPlanNavigator/index.html @@ -103,7 +103,8 @@ // navigator.highlighter.highlightColor = 0xff0000; navigator.onHighlight.add((data) => { - navigator.highlighter.highlight(data); + navigator.highlighter1.highlight(data); + navigator.highlighter2.showCurveInfo(data, scene); }); let first = true; diff --git a/src/civil/RoadPlanNavigator/index.ts b/src/civil/RoadPlanNavigator/index.ts index 0e88f9586..02abe4a6b 100644 --- a/src/civil/RoadPlanNavigator/index.ts +++ b/src/civil/RoadPlanNavigator/index.ts @@ -2,6 +2,8 @@ import { UI, UIElement } from "../../base-types"; import { FloatingWindow } from "../../ui"; import { Components } from "../../core"; import { RoadNavigator } from "../RoadNavigator"; +import { PlanHighlighter } from "./src/plan-highlighter"; +import { CurveHighlighter } from "../RoadNavigator/src/curve-highlighter"; export class RoadPlanNavigator extends RoadNavigator implements UI { static readonly uuid = "3096dea0-5bc2-41c7-abce-9089b6c9431b" as const; @@ -11,9 +13,13 @@ export class RoadPlanNavigator extends RoadNavigator implements UI { uiElement = new UIElement<{ floatingWindow: FloatingWindow; }>(); + highlighter1: CurveHighlighter; + highlighter2: PlanHighlighter; constructor(components: Components) { super(components); + this.highlighter1 = new CurveHighlighter(this.scene.get()); + this.highlighter2 = new PlanHighlighter(this.scene.get()); this.setUI(); } diff --git a/src/civil/RoadPlanNavigator/src/plan-highlighter.ts b/src/civil/RoadPlanNavigator/src/plan-highlighter.ts new file mode 100644 index 000000000..b349ec0ac --- /dev/null +++ b/src/civil/RoadPlanNavigator/src/plan-highlighter.ts @@ -0,0 +1,78 @@ +import * as THREE from "three"; +import * as FRAGS from "bim-fragment"; +import { CurveHighlighter } from "../../RoadNavigator/src/curve-highlighter"; + +export class PlanHighlighter extends CurveHighlighter { + constructor(scene: THREE.Group | THREE.Scene) { + super(scene); + } + + testMaterial = new THREE.LineBasicMaterial({ + color: 0x424242, + linewidth: 5, + }); + + showCurveInfo(curveMesh: FRAGS.CurveMesh) { + this.highlight(curveMesh); + const linePoints = []; + if (curveMesh.curve.data.TYPE === "CIRCULARARC") { + console.log("ES CIRCULARARC"); + console.log(curveMesh); + const radius = curveMesh.curve.data.RADIUS; + const positions = curveMesh.geometry.attributes.position.array; + const count = curveMesh.geometry.attributes.position.count; + const firstPoint = new THREE.Vector3( + positions[0], + positions[1], + positions[2] + ); + const lastPointIndex = (count - 1) * 3; + const lastPoint = new THREE.Vector3( + positions[lastPointIndex], + positions[lastPointIndex + 1], + positions[lastPointIndex + 2] + ); + const middlePointIndex = (count / 2) * 3; + const middlePoint = new THREE.Vector3( + positions[middlePointIndex], + positions[middlePointIndex + 1], + positions[middlePointIndex + 2] + ); + console.log("First Point:", firstPoint); + console.log("Last Point:", lastPoint); + console.log("Middle Point:", middlePoint); + const secondPoint = new THREE.Vector3( + positions[3], + positions[4], + positions[5] + ); + const thirdPoint = new THREE.Vector3( + positions[6], + positions[7], + positions[8] + ); + const line1 = new THREE.Line3(firstPoint, secondPoint); + const line2 = new THREE.Line3(secondPoint, thirdPoint); + + const delta1 = line1.end.clone().sub(line1.start); + const delta2 = line2.end.clone().sub(line2.start); + const angleBetweenSegments = delta1.angleTo(delta2); + const halfAngle = angleBetweenSegments / 2; + const angleDirection = Math.atan2(delta2.y, delta2.x) + halfAngle; + const endPointX = secondPoint.x + radius * Math.cos(angleDirection); + const endPointY = secondPoint.y + radius * Math.sin(angleDirection); + const endPointZ = secondPoint.z; + const arcCenterPoint = new THREE.Vector3(endPointX, endPointY, endPointZ); + console.log("Center of the arc:", arcCenterPoint); + linePoints.push(middlePoint); + linePoints.push(arcCenterPoint); + const testGeometry = new THREE.BufferGeometry().setFromPoints(linePoints); + const radiusLine = new THREE.Line(testGeometry, this.testMaterial); + this.scene.add(radiusLine); + } + if (curveMesh.curve.data.TYPE === "CLOTHOID") { + console.log("ES CLOTHOID"); + // logica de lineas + } + } +} From 0f98299fd3d61bc091256ec4e103c33aa53be000 Mon Sep 17 00:00:00 2001 From: Felipe Moreira <118832082+Felipemore96@users.noreply.github.com> Date: Mon, 25 Mar 2024 09:44:08 -0600 Subject: [PATCH 4/6] plan-highlighter radius line fixed --- .../RoadPlanNavigator/src/plan-highlighter.ts | 32 ++++--------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/src/civil/RoadPlanNavigator/src/plan-highlighter.ts b/src/civil/RoadPlanNavigator/src/plan-highlighter.ts index b349ec0ac..0165c0202 100644 --- a/src/civil/RoadPlanNavigator/src/plan-highlighter.ts +++ b/src/civil/RoadPlanNavigator/src/plan-highlighter.ts @@ -38,32 +38,14 @@ export class PlanHighlighter extends CurveHighlighter { positions[middlePointIndex + 1], positions[middlePointIndex + 2] ); - console.log("First Point:", firstPoint); - console.log("Last Point:", lastPoint); - console.log("Middle Point:", middlePoint); - const secondPoint = new THREE.Vector3( - positions[3], - positions[4], - positions[5] + const tangentVector = lastPoint.clone().sub(firstPoint).normalize(); + const perpendicularVector = new THREE.Vector3( + -tangentVector.y, + tangentVector.x, + 0 ); - const thirdPoint = new THREE.Vector3( - positions[6], - positions[7], - positions[8] - ); - const line1 = new THREE.Line3(firstPoint, secondPoint); - const line2 = new THREE.Line3(secondPoint, thirdPoint); - - const delta1 = line1.end.clone().sub(line1.start); - const delta2 = line2.end.clone().sub(line2.start); - const angleBetweenSegments = delta1.angleTo(delta2); - const halfAngle = angleBetweenSegments / 2; - const angleDirection = Math.atan2(delta2.y, delta2.x) + halfAngle; - const endPointX = secondPoint.x + radius * Math.cos(angleDirection); - const endPointY = secondPoint.y + radius * Math.sin(angleDirection); - const endPointZ = secondPoint.z; - const arcCenterPoint = new THREE.Vector3(endPointX, endPointY, endPointZ); - console.log("Center of the arc:", arcCenterPoint); + perpendicularVector.multiplyScalar(radius); + const arcCenterPoint = middlePoint.clone().add(perpendicularVector); linePoints.push(middlePoint); linePoints.push(arcCenterPoint); const testGeometry = new THREE.BufferGeometry().setFromPoints(linePoints); From 665fdb0421e2376f991b730930c6d8d19fd6e585 Mon Sep 17 00:00:00 2001 From: Felipe Moreira <118832082+Felipemore96@users.noreply.github.com> Date: Mon, 25 Mar 2024 19:42:33 -0600 Subject: [PATCH 5/6] Completed markup logic for circulararc and lines --- .../RoadPlanNavigator/src/plan-highlighter.ts | 180 ++++++++++++++---- 1 file changed, 146 insertions(+), 34 deletions(-) diff --git a/src/civil/RoadPlanNavigator/src/plan-highlighter.ts b/src/civil/RoadPlanNavigator/src/plan-highlighter.ts index 0165c0202..f8f5a59dd 100644 --- a/src/civil/RoadPlanNavigator/src/plan-highlighter.ts +++ b/src/civil/RoadPlanNavigator/src/plan-highlighter.ts @@ -12,49 +12,161 @@ export class PlanHighlighter extends CurveHighlighter { linewidth: 5, }); + calculateTangent(positions: THREE.TypedArray, index: number) { + const numComponents = 3; // Coordenadas en 3D (x, y, z) + const pointIndex = index * numComponents; + const prevPointIndex = Math.max(0, pointIndex - numComponents); + const nextPointIndex = Math.min( + positions.length - numComponents, + pointIndex + numComponents + ); + const prevPoint = new THREE.Vector3( + positions[prevPointIndex], + positions[prevPointIndex + 1], + positions[prevPointIndex + 2] + ); + const nextPoint = new THREE.Vector3( + positions[nextPointIndex], + positions[nextPointIndex + 1], + positions[nextPointIndex + 2] + ); + const tangent = nextPoint.clone().sub(prevPoint).normalize(); + return tangent; + } + showCurveInfo(curveMesh: FRAGS.CurveMesh) { this.highlight(curveMesh); - const linePoints = []; + + if (curveMesh.curve.data.TYPE === "LINE") { + this.showLineInfo(curveMesh); + } + if (curveMesh.curve.data.TYPE === "CIRCULARARC") { - console.log("ES CIRCULARARC"); - console.log(curveMesh); - const radius = curveMesh.curve.data.RADIUS; - const positions = curveMesh.geometry.attributes.position.array; - const count = curveMesh.geometry.attributes.position.count; - const firstPoint = new THREE.Vector3( - positions[0], - positions[1], - positions[2] - ); - const lastPointIndex = (count - 1) * 3; - const lastPoint = new THREE.Vector3( - positions[lastPointIndex], - positions[lastPointIndex + 1], - positions[lastPointIndex + 2] + this.showCircularArcInfo(curveMesh); + } + + if (curveMesh.curve.data.TYPE === "CLOTHOID") { + this.showClothoidInfo(curveMesh); + } + } + + showLineInfo(curveMesh: FRAGS.CurveMesh) { + console.log("ES LINE"); + console.log(curveMesh); + + const positions = curveMesh.geometry.attributes.position.array; + const count = curveMesh.geometry.attributes.position.count; + const parallelCurvePoints = []; + for (let i = 0; i < count; i++) { + const tangentVector = this.calculateTangent(positions, i); + // const length = curveMesh.curve.data.LENGTH; + const perpendicularVector = new THREE.Vector3( + tangentVector.y, + -tangentVector.x, + 0 ); - const middlePointIndex = (count / 2) * 3; - const middlePoint = new THREE.Vector3( - positions[middlePointIndex], - positions[middlePointIndex + 1], - positions[middlePointIndex + 2] + perpendicularVector.normalize(); + const distance = 10; // Adjust as needed + const offsetVector = perpendicularVector.clone().multiplyScalar(distance); + const pointIndex = i * 3; + const parallelPoint = new THREE.Vector3( + positions[pointIndex] + offsetVector.x, + positions[pointIndex + 1] + offsetVector.y, + positions[pointIndex + 2] + offsetVector.z ); - const tangentVector = lastPoint.clone().sub(firstPoint).normalize(); + parallelCurvePoints.push(parallelPoint); + } + const lengthGeometry = new THREE.BufferGeometry().setFromPoints( + parallelCurvePoints + ); + const lengthLine = new THREE.Line(lengthGeometry, this.testMaterial); + + this.scene.add(lengthLine); + } + + showCircularArcInfo(curveMesh: FRAGS.CurveMesh) { + console.log("ES CIRCULARARC"); + console.log(curveMesh); + + const radius = curveMesh.curve.data.RADIUS; + const positions = curveMesh.geometry.attributes.position.array; + const count = curveMesh.geometry.attributes.position.count; + + const linePoints = []; + + const firstPoint = new THREE.Vector3( + positions[0], + positions[1], + positions[2] + ); + + const lastPointIndex = (count - 1) * 3; + const lastPoint = new THREE.Vector3( + positions[lastPointIndex], + positions[lastPointIndex + 1], + positions[lastPointIndex + 2] + ); + + const middlePointIndex = (count / 2) * 3; + const middlePoint = new THREE.Vector3( + positions[middlePointIndex], + positions[middlePointIndex + 1], + positions[middlePointIndex + 2] + ); + + const tangentVector = lastPoint.clone().sub(firstPoint).normalize(); + const perpendicularVector = new THREE.Vector3( + -tangentVector.y, + tangentVector.x, + 0 + ); + + perpendicularVector.multiplyScalar(radius); + const arcCenterPoint = middlePoint.clone().add(perpendicularVector); + + linePoints.push(middlePoint); + linePoints.push(arcCenterPoint); + // createLabel(text: string, curve: FRAGS.CivilCurve, type: string) + + const testGeometry = new THREE.BufferGeometry().setFromPoints(linePoints); + const radiusLine = new THREE.Line(testGeometry, this.testMaterial); + + const parallelCurvePoints = []; + for (let i = 0; i < count; i++) { + const tangentVector = this.calculateTangent(positions, i); + const radius = curveMesh.curve.data.RADIUS; const perpendicularVector = new THREE.Vector3( - -tangentVector.y, - tangentVector.x, + tangentVector.y, + -tangentVector.x, 0 ); - perpendicularVector.multiplyScalar(radius); - const arcCenterPoint = middlePoint.clone().add(perpendicularVector); - linePoints.push(middlePoint); - linePoints.push(arcCenterPoint); - const testGeometry = new THREE.BufferGeometry().setFromPoints(linePoints); - const radiusLine = new THREE.Line(testGeometry, this.testMaterial); - this.scene.add(radiusLine); + perpendicularVector.normalize(); + // Ensure the normal vector points outward + if (radius < 0) { + perpendicularVector.negate(); + } + const distance = 10; // Adjust as needed + const offsetVector = perpendicularVector.clone().multiplyScalar(distance); + const pointIndex = i * 3; + const parallelPoint = new THREE.Vector3( + positions[pointIndex] + offsetVector.x, + positions[pointIndex + 1] + offsetVector.y, + positions[pointIndex + 2] + offsetVector.z + ); + parallelCurvePoints.push(parallelPoint); } - if (curveMesh.curve.data.TYPE === "CLOTHOID") { - console.log("ES CLOTHOID"); - // logica de lineas + const lengthGeometry = new THREE.BufferGeometry().setFromPoints( + parallelCurvePoints + ); + const lengthLine = new THREE.Line(lengthGeometry, this.testMaterial); + + this.scene.add(radiusLine, lengthLine); + } + + showClothoidInfo(curveMesh: FRAGS.CurveMesh) { + console.log("ES CLOTHOID"); + console.log(curveMesh); + } } } From ca556f0b10fdc134059d8ef5bdf439c243ec74b0 Mon Sep 17 00:00:00 2001 From: Felipe Moreira <118832082+Felipemore96@users.noreply.github.com> Date: Tue, 26 Mar 2024 11:39:35 -0600 Subject: [PATCH 6/6] plan-highlighter markups Complete tool to show and hide markups in Plan View Navigator --- .../RoadNavigator/src/curve-highlighter.ts | 73 ++++---- src/civil/RoadPlanNavigator/index.html | 8 +- .../RoadPlanNavigator/src/plan-highlighter.ts | 162 ++++++++++-------- 3 files changed, 128 insertions(+), 115 deletions(-) diff --git a/src/civil/RoadNavigator/src/curve-highlighter.ts b/src/civil/RoadNavigator/src/curve-highlighter.ts index d91070b30..f8894ce02 100644 --- a/src/civil/RoadNavigator/src/curve-highlighter.ts +++ b/src/civil/RoadNavigator/src/curve-highlighter.ts @@ -1,45 +1,46 @@ -import * as THREE from 'three'; -import { Line2 } from 'three/examples/jsm/lines/Line2'; -import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry'; -import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial'; +import * as THREE from "three"; +import { Line2 } from "three/examples/jsm/lines/Line2"; +import { LineGeometry } from "three/examples/jsm/lines/LineGeometry"; +import { LineMaterial } from "three/examples/jsm/lines/LineMaterial"; export class CurveHighlighter { - private _highlightColor: THREE.ColorRepresentation; - activeSelection: Line2 | undefined | THREE.Line; protected scene: THREE.Scene | THREE.Group; + private _highlightColor: THREE.ColorRepresentation; + activeSelection: Line2 | undefined | THREE.Line; - constructor(scene: THREE.Group | THREE.Scene) { - this.scene = scene; - this._highlightColor = 0xbcf124; - } + constructor(scene: THREE.Group | THREE.Scene) { + this.scene = scene; + this._highlightColor = 0xbcf124; + } - set highlightColor(color: THREE.ColorRepresentation) { - this._highlightColor = color; - } + set highlightColor(color: THREE.ColorRepresentation) { + this._highlightColor = color; + } - highlight(curve: THREE.LineSegments) { - if (this.activeSelection) { - this.scene.remove(this.activeSelection); - } - const lGeom = new LineGeometry(); - lGeom.setPositions(new Float32Array(curve.geometry.attributes.position.array)); - const lMat = new LineMaterial({ - color: this._highlightColor, - linewidth: 0.015, - worldUnits: false, - - }); - const line = new Line2(lGeom, lMat); - this.scene.add(line); - this.activeSelection = line; + highlight(curve: THREE.LineSegments) { + if (this.activeSelection) { + this.scene.remove(this.activeSelection); } + const lGeom = new LineGeometry(); + lGeom.setPositions( + new Float32Array(curve.geometry.attributes.position.array) + ); + const lMat = new LineMaterial({ + color: this._highlightColor, + linewidth: 0.015, + worldUnits: false, + }); + const line = new Line2(lGeom, lMat); + this.scene.add(line); + this.activeSelection = line; + } - dispose() { - if (this.activeSelection) { - this.scene.remove(this.activeSelection); - } - this.activeSelection = null as any; - this.scene = null as any; - this._highlightColor = null as any; + dispose() { + if (this.activeSelection) { + this.scene.remove(this.activeSelection); } -} \ No newline at end of file + this.activeSelection = null as any; + this.scene = null as any; + this._highlightColor = null as any; + } +} diff --git a/src/civil/RoadPlanNavigator/index.html b/src/civil/RoadPlanNavigator/index.html index 9f68a7904..f0e88c312 100644 --- a/src/civil/RoadPlanNavigator/index.html +++ b/src/civil/RoadPlanNavigator/index.html @@ -84,16 +84,14 @@ const data = await file.arrayBuffer(); const buffer = new Uint8Array(data); const model = await fragments.load(buffer); - // const properties = await fetch("../../../resources/asdf.json"); - // model.setLocalProperties(await properties.json()); - // console.log(model); + const properties = await fetch("../../../resources/asdf.json"); + model.setLocalProperties(await properties.json()); + console.log(model); const mainToolbar = new OBC.Toolbar(components, {name: 'Main Toolbar', position: 'bottom'}); components.ui.addToolbar(mainToolbar); mainToolbar.addChild(fragmentIfcLoader.uiElement.get("main")); - console.log(model); - // Set up road navigator const navigator = new OBC.RoadPlanNavigator(components); diff --git a/src/civil/RoadPlanNavigator/src/plan-highlighter.ts b/src/civil/RoadPlanNavigator/src/plan-highlighter.ts index f8f5a59dd..5eb62b00f 100644 --- a/src/civil/RoadPlanNavigator/src/plan-highlighter.ts +++ b/src/civil/RoadPlanNavigator/src/plan-highlighter.ts @@ -3,133 +3,141 @@ import * as FRAGS from "bim-fragment"; import { CurveHighlighter } from "../../RoadNavigator/src/curve-highlighter"; export class PlanHighlighter extends CurveHighlighter { + private readonly markupMaterial: THREE.LineBasicMaterial; + private readonly offset: number = 10; + private markupLines: THREE.Line[] = []; + constructor(scene: THREE.Group | THREE.Scene) { super(scene); + this.markupMaterial = new THREE.LineBasicMaterial({ + color: 0x686868, + }); } - testMaterial = new THREE.LineBasicMaterial({ - color: 0x424242, - linewidth: 5, - }); - - calculateTangent(positions: THREE.TypedArray, index: number) { - const numComponents = 3; // Coordenadas en 3D (x, y, z) + private calculateTangent( + positions: THREE.TypedArray, + index: number + ): THREE.Vector3 { + const numComponents = 3; const pointIndex = index * numComponents; const prevPointIndex = Math.max(0, pointIndex - numComponents); const nextPointIndex = Math.min( positions.length - numComponents, pointIndex + numComponents ); - const prevPoint = new THREE.Vector3( - positions[prevPointIndex], - positions[prevPointIndex + 1], - positions[prevPointIndex + 2] - ); - const nextPoint = new THREE.Vector3( - positions[nextPointIndex], - positions[nextPointIndex + 1], - positions[nextPointIndex + 2] - ); + const prevPoint = new THREE.Vector3().fromArray(positions, prevPointIndex); + const nextPoint = new THREE.Vector3().fromArray(positions, nextPointIndex); const tangent = nextPoint.clone().sub(prevPoint).normalize(); return tangent; } - showCurveInfo(curveMesh: FRAGS.CurveMesh) { + private calculateParallelCurve( + positions: THREE.TypedArray, + count: number, + offset: number + ): THREE.Vector3[] { + const parallelCurvePoints = []; + console.log(offset); + for (let i = 0; i < count; i++) { + const tangentVector = this.calculateTangent(positions, i); + const perpendicularVector = tangentVector + .clone() + .applyAxisAngle(new THREE.Vector3(0, 0, 1), Math.PI / 2); + perpendicularVector.normalize(); + const offsetVector = perpendicularVector.clone().multiplyScalar(offset); + const pointIndex = i * 3; + const parallelPoint = new THREE.Vector3() + .fromArray(positions, pointIndex) + .add(offsetVector); + parallelCurvePoints.push(parallelPoint); + } + return parallelCurvePoints; + } + + public showCurveInfo(curveMesh: FRAGS.CurveMesh): void { + this.clearMarkups(); this.highlight(curveMesh); - if (curveMesh.curve.data.TYPE === "LINE") { - this.showLineInfo(curveMesh); + // eslint-disable-next-line default-case + switch (curveMesh.curve.data.TYPE) { + case "LINE": + this.showLineInfo(curveMesh); + break; + case "CIRCULARARC": + this.showCircularArcInfo(curveMesh); + break; + case "CLOTHOID": + this.showClothoidInfo(curveMesh); + break; } + } - if (curveMesh.curve.data.TYPE === "CIRCULARARC") { - this.showCircularArcInfo(curveMesh); + private clearMarkups(): void { + for (const line of this.markupLines) { + this.scene.remove(line); } + this.markupLines = []; + } - if (curveMesh.curve.data.TYPE === "CLOTHOID") { - this.showClothoidInfo(curveMesh); - } + private addMarkupLine(geometry: THREE.BufferGeometry): void { + const markupLine = new THREE.Line(geometry, this.markupMaterial); + this.scene.add(markupLine); + this.markupLines.push(markupLine); } showLineInfo(curveMesh: FRAGS.CurveMesh) { - console.log("ES LINE"); - console.log(curveMesh); + // console.log("ES LINE"); + // console.log(curveMesh); const positions = curveMesh.geometry.attributes.position.array; - const count = curveMesh.geometry.attributes.position.count; - const parallelCurvePoints = []; - for (let i = 0; i < count; i++) { - const tangentVector = this.calculateTangent(positions, i); - // const length = curveMesh.curve.data.LENGTH; - const perpendicularVector = new THREE.Vector3( - tangentVector.y, - -tangentVector.x, - 0 - ); - perpendicularVector.normalize(); - const distance = 10; // Adjust as needed - const offsetVector = perpendicularVector.clone().multiplyScalar(distance); - const pointIndex = i * 3; - const parallelPoint = new THREE.Vector3( - positions[pointIndex] + offsetVector.x, - positions[pointIndex + 1] + offsetVector.y, - positions[pointIndex + 2] + offsetVector.z - ); - parallelCurvePoints.push(parallelPoint); - } + const parallelCurvePoints = this.calculateParallelCurve( + positions, + positions.length / 3, + this.offset + ); const lengthGeometry = new THREE.BufferGeometry().setFromPoints( parallelCurvePoints ); - const lengthLine = new THREE.Line(lengthGeometry, this.testMaterial); - - this.scene.add(lengthLine); + this.addMarkupLine(lengthGeometry); } showCircularArcInfo(curveMesh: FRAGS.CurveMesh) { - console.log("ES CIRCULARARC"); - console.log(curveMesh); + // console.log("ES CIRCULARARC"); + // console.log(curveMesh); const radius = curveMesh.curve.data.RADIUS; const positions = curveMesh.geometry.attributes.position.array; const count = curveMesh.geometry.attributes.position.count; - const linePoints = []; - const firstPoint = new THREE.Vector3( positions[0], positions[1], positions[2] ); - const lastPointIndex = (count - 1) * 3; const lastPoint = new THREE.Vector3( positions[lastPointIndex], positions[lastPointIndex + 1], positions[lastPointIndex + 2] ); - const middlePointIndex = (count / 2) * 3; const middlePoint = new THREE.Vector3( positions[middlePointIndex], positions[middlePointIndex + 1], positions[middlePointIndex + 2] ); - const tangentVector = lastPoint.clone().sub(firstPoint).normalize(); const perpendicularVector = new THREE.Vector3( -tangentVector.y, tangentVector.x, 0 ); - perpendicularVector.multiplyScalar(radius); const arcCenterPoint = middlePoint.clone().add(perpendicularVector); - linePoints.push(middlePoint); linePoints.push(arcCenterPoint); - // createLabel(text: string, curve: FRAGS.CivilCurve, type: string) - - const testGeometry = new THREE.BufferGeometry().setFromPoints(linePoints); - const radiusLine = new THREE.Line(testGeometry, this.testMaterial); + const radiusGeometry = new THREE.BufferGeometry().setFromPoints(linePoints); + this.addMarkupLine(radiusGeometry); const parallelCurvePoints = []; for (let i = 0; i < count; i++) { @@ -141,12 +149,12 @@ export class PlanHighlighter extends CurveHighlighter { 0 ); perpendicularVector.normalize(); - // Ensure the normal vector points outward if (radius < 0) { perpendicularVector.negate(); } - const distance = 10; // Adjust as needed - const offsetVector = perpendicularVector.clone().multiplyScalar(distance); + const offsetVector = perpendicularVector + .clone() + .multiplyScalar(this.offset); const pointIndex = i * 3; const parallelPoint = new THREE.Vector3( positions[pointIndex] + offsetVector.x, @@ -158,15 +166,21 @@ export class PlanHighlighter extends CurveHighlighter { const lengthGeometry = new THREE.BufferGeometry().setFromPoints( parallelCurvePoints ); - const lengthLine = new THREE.Line(lengthGeometry, this.testMaterial); - - this.scene.add(radiusLine, lengthLine); + this.addMarkupLine(lengthGeometry); } showClothoidInfo(curveMesh: FRAGS.CurveMesh) { - console.log("ES CLOTHOID"); - console.log(curveMesh); - - } + // console.log("ES CLOTHOID"); + // console.log(curveMesh); + const positions = curveMesh.geometry.attributes.position.array; + const parallelCurvePoints = this.calculateParallelCurve( + positions, + positions.length / 3, + this.offset + ); + const lengthGeometry = new THREE.BufferGeometry().setFromPoints( + parallelCurvePoints + ); + this.addMarkupLine(lengthGeometry); } }