Skip to content

Commit

Permalink
feat: constant KPs and KP-Station Manager (#351)
Browse files Browse the repository at this point in the history
* Fix : Moving setupEvents to Contructor + Camera zoomToCursor

* feat: Cluster Management + Initial KP Labels

* Unclustering of labels + managing overlapping labels

* Start and End KPs

* Constant KPs at Fixed Intervals
  • Loading branch information
aka-blackboots authored Apr 9, 2024
1 parent bee851a commit 2bdf974
Show file tree
Hide file tree
Showing 9 changed files with 1,269 additions and 637 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"liveServer.settings.port": 5502
}
Binary file added resources/.DS_Store
Binary file not shown.
1,437 changes: 841 additions & 596 deletions resources/openbim-components.js

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions src/civil/RoadElevationNavigator/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as FRAGS from "bim-fragment";
import { UI, UIElement } from "../../base-types";
import { Drawer } from "../../ui";
import { Components } from "../../core";
Expand Down Expand Up @@ -26,6 +27,15 @@ export class RoadElevationNavigator extends RoadNavigator implements UI {
return null as any;
}

showKPStations(mesh: FRAGS.CurveMesh) {
// TODO: Discuss and Implement the Logic for Vertical Views and KP Stations
console.log(mesh);
}

clearKPStations(): void {
// Clearing KP Stations
}

private setUI() {
const drawer = new Drawer(this.components);
this.components.ui.add(drawer);
Expand Down
25 changes: 7 additions & 18 deletions src/civil/RoadNavigator/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { Alignment, FragmentsGroup } from "bim-fragment";
import { Component, Event } from "../../base-types";
import { Components, Simple2DMarker, Simple2DScene } from "../../core";
import { CurveHighlighter } from "./src/curve-highlighter";
import { MarkerManager } from "../../core/Simple2DMarker/src/marker-manager";

export type CivilMarkerType = "hover" | "select";

Expand All @@ -17,6 +16,9 @@ export abstract class RoadNavigator extends Component<any> {

abstract highlighter: CurveHighlighter;

abstract showKPStations(curveMesh: FRAGS.CurveMesh): void;
abstract clearKPStations(): void;

readonly onHighlight = new Event<{
point: THREE.Vector3;
mesh: FRAGS.CurveMesh;
Expand All @@ -35,8 +37,6 @@ export abstract class RoadNavigator extends Component<any> {

private _curveMeshes: FRAGS.CurveMesh[] = [];

markerManager: MarkerManager;

mouseMarkers: {
hover: Simple2DMarker;
select: Simple2DMarker;
Expand All @@ -45,7 +45,6 @@ export abstract class RoadNavigator extends Component<any> {
protected constructor(components: Components) {
super(components);
this.scene = new Simple2DScene(this.components, false);
this.markerManager = new MarkerManager(this.components, this.scene);

this.mouseMarkers = {
select: this.newMouseMarker("#ffffff"),
Expand Down Expand Up @@ -79,19 +78,6 @@ export abstract class RoadNavigator extends Component<any> {
throw new Error("Alignment not found!");
}

// TODO: Generate All The KPs and Stations
this.markerManager.addCivilMarker(
`0+${alignment.initialKP.toFixed(2)}`,
alignment[this.view][0].mesh,
"InitialKP"
);

this.markerManager.addCivilMarker(
"end",
alignment[this.view][alignment[this.view].length - 1].mesh,
"FinalKP"
);

for (const curve of alignment[this.view]) {
scene.add(curve.mesh);
this._curveMeshes.push(curve.mesh);
Expand Down Expand Up @@ -164,10 +150,14 @@ export abstract class RoadNavigator extends Component<any> {
await this.updateMarker(result, "select");

await this.onHighlight.trigger({ mesh, point: result.point });

this.showKPStations(mesh);

return;
}

this.highlighter.unSelect();
this.clearKPStations();
});
}

Expand All @@ -177,7 +167,6 @@ export abstract class RoadNavigator extends Component<any> {
this.onHighlight.reset();
await this.scene.dispose();
this._curveMeshes = [];
this.markerManager.dispose();
}

clear() {
Expand Down
257 changes: 257 additions & 0 deletions src/civil/RoadNavigator/src/kp-station.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
import * as FRAGS from "bim-fragment";
import * as THREE from "three";
import CameraControls from "camera-controls";
import { MarkerManager } from "../../../core/Simple2DMarker/src/marker-manager";
import { Components, SimpleRenderer } from "../../../core";
import { PostproductionRenderer } from "../../../navigation";

type CivilHighlightType = "horizontal" | "absolute" | "vertical";

export class KPStation {
private type: CivilHighlightType;

// private scene: THREE.Group | THREE.Scene;

private markerManager: MarkerManager;

private divisionLength = 100;

constructor(
components: Components,
renderer: SimpleRenderer | PostproductionRenderer,
scene: THREE.Group | THREE.Scene,
controls: CameraControls,
type: CivilHighlightType
) {
// this.scene = scene;
this.type = type;

this.markerManager = new MarkerManager(
components,
renderer,
scene,
controls
);
}

showKPStations(mesh: FRAGS.CurveMesh) {
if (this.type === "horizontal") {
const endKPStations = this.generateStartAndEndKP(mesh);
for (const [, data] of endKPStations) {
this.markerManager.addKPStation(data.value, data.normal);
}

const constantKPStations = this.generateConstantKP(mesh);
for (const [, data] of constantKPStations) {
this.markerManager.addKPStation(data.value, data.normal);
}
}
}

private generateStartAndEndKP(mesh: FRAGS.CurveMesh) {
const { alignment } = mesh.curve;
const data = new Map<
number,
{
value: string;
distance: number;
point: THREE.Vector3;
normal: THREE.Line;
}
>();

for (const curve of alignment.horizontal) {
const length = curve.getLength();
if (data.size > 0) {
const last = curve.index - 1;
const previousData = data.get(last);
const updateDistance = previousData!.distance + length;

const curvePosition = curve.mesh.geometry.getAttribute("position");
const lastSegmentIndex = curvePosition.count - 1;

const lastSegment = new THREE.Vector3();
lastSegment.x = curvePosition.getX(lastSegmentIndex);
lastSegment.y = curvePosition.getY(lastSegmentIndex);
lastSegment.z = curvePosition.getZ(lastSegmentIndex);

const normalLine = this.createNormalLine(curve.mesh);

data.set(curve.index, {
value: this.getShortendKPValue(updateDistance),
distance: updateDistance,
point: lastSegment,
normal: normalLine,
});
} else {
const curvePosition = curve.mesh.geometry.getAttribute("position");
const lastSegmentIndex = curvePosition.count - 1;

const lastSegment = new THREE.Vector3();
lastSegment.x = curvePosition.getX(lastSegmentIndex);
lastSegment.y = curvePosition.getY(lastSegmentIndex);
lastSegment.z = curvePosition.getZ(lastSegmentIndex);

const normalLine = this.createNormalLine(curve.mesh);

data.set(curve.index, {
value: this.getShortendKPValue(length),
distance: length,
point: lastSegment,
normal: normalLine,
});
}
}

return data;
}

private createNormalLine(curveMesh: FRAGS.CurveMesh) {
const lastIndex = curveMesh.geometry.attributes.position.count - 1;
const secondLastIndex = lastIndex - 1;

const lastPoint = new THREE.Vector3();
lastPoint.x = curveMesh.geometry.attributes.position.getX(lastIndex);
lastPoint.y = curveMesh.geometry.attributes.position.getY(lastIndex);
lastPoint.z = curveMesh.geometry.attributes.position.getZ(lastIndex);

const secondLastPoint = new THREE.Vector3();
secondLastPoint.x =
curveMesh.geometry.attributes.position.getX(secondLastIndex);
secondLastPoint.y =
curveMesh.geometry.attributes.position.getY(secondLastIndex);
secondLastPoint.z =
curveMesh.geometry.attributes.position.getZ(secondLastIndex);

const direction = new THREE.Vector3().subVectors(
lastPoint,
secondLastPoint
);

const normal = direction
.clone()
.applyAxisAngle(new THREE.Vector3(0, 0, 1), Math.PI * 0.5)
.normalize();
const normalGeom = new THREE.BufferGeometry().setFromPoints([
normal.clone().setLength(10).add(lastPoint),
normal.clone().setLength(-10).add(lastPoint),
]);
const normalLine = new THREE.Line(normalGeom);
// this.scene.add(normalLine);

return normalLine;
}

private generateConstantKP(mesh: FRAGS.CurveMesh) {
const { alignment } = mesh.curve;
const data = new Map<
number,
{
value: string;
distance: number;
point: THREE.Vector3;
normal: THREE.Line;
}
>();

const alignmentLength = alignment.getLength("horizontal");
const divisions = Math.floor(alignmentLength / this.divisionLength);
for (let i = 0; i < divisions; i++) {
const percentage = i / divisions;
const kpPoint = alignment.getPointAt(percentage, "horizontal");
const length = alignmentLength * percentage;
// const curve = alignment.getCurveAt(percentage, "horizontal");
const normalLine = this.getNormal(alignment, kpPoint);
data.set(i, {
value: this.getShortendKPValue(length),
distance: length,
point: kpPoint,
normal: normalLine,
});
}

return data;
}

// TODO: Move Generation of Points to Previous Method Call
private getNormal(curve: FRAGS.Alignment, point: THREE.Vector3) {
const pointsInCurve = [];
const normalPoints = {
start: new THREE.Vector3(),
end: new THREE.Vector3(),
};

for (let i = 0; i < curve.horizontal.length; i++) {
const curveMesh = curve.horizontal[i].mesh;
const position = curveMesh.geometry.attributes.position;
const length = position.count;

for (let j = 0; j < length; j++) {
const x = position.getX(j);
const y = position.getY(j);
const z = position.getZ(j);
pointsInCurve.push(new THREE.Vector3(x, y, z));
}
}

for (let i = 0; i < pointsInCurve.length - 1; i++) {
const p1 = pointsInCurve[i];
const p2 = pointsInCurve[i + 1];

const distanceP1 = p1.distanceTo(point);
const distanceP2 = p2.distanceTo(point);
const distanceP1P2 = p1.distanceTo(p2);

const epsilion = 0.00001;
const isOnLine = Math.abs(distanceP1 + distanceP2 - distanceP1P2);

if (isOnLine < epsilion) {
normalPoints.start = p1;
normalPoints.end = p2;
}
}

const direction = new THREE.Vector3().subVectors(
normalPoints.end,
normalPoints.start
);
const normal = direction
.clone()
.applyAxisAngle(new THREE.Vector3(0, 0, 1), Math.PI * 0.5)
.normalize();
const normalGeom = new THREE.BufferGeometry().setFromPoints([
normal.clone().setLength(10).add(point),
normal.clone().setLength(-10).add(point),
]);
const normalLine = new THREE.Line(
normalGeom,
new THREE.LineBasicMaterial({ color: 0xff0000 })
);
return normalLine;
}

private getShortendKPValue(value: number) {
const formattedValue = value.toFixed(2);
const [integerPart, fractionalPart] = formattedValue.toString().split(".");
const formattedFractionalPart = fractionalPart || "00";

if (parseInt(integerPart, 10) > 1000 && parseInt(integerPart, 10) < 10000) {
const [first, ...rest] = integerPart;
return `${first}+${rest.join("")}.${formattedFractionalPart}`;
}
if (parseInt(integerPart, 10) > 10000) {
const [first, second, ...rest] = integerPart;
return `${first}${second}+${rest.join("")}.${formattedFractionalPart}`;
}

return `0+${integerPart.padStart(3, "0")}.${formattedFractionalPart}`;
}

clearKPStations() {
this.markerManager.clearMarkers();
}

dispose() {
this.markerManager.dispose();
}
}
Loading

0 comments on commit 2bdf974

Please sign in to comment.