Finish slicing box
This commit is contained in:
parent
7c78015894
commit
e71980ad17
4 changed files with 395 additions and 210 deletions
|
@ -30,7 +30,12 @@ import {
|
||||||
OBJExporter,
|
OBJExporter,
|
||||||
OrbitControls,
|
OrbitControls,
|
||||||
} from "three/examples/jsm/Addons.js";
|
} from "three/examples/jsm/Addons.js";
|
||||||
import { MapTilerProvider, MapView, OpenStreetMapsProvider } from "geo-three";
|
import {
|
||||||
|
LODFrustum,
|
||||||
|
MapTilerProvider,
|
||||||
|
MapView,
|
||||||
|
OpenStreetMapsProvider,
|
||||||
|
} from "geo-three";
|
||||||
import { CustomMapHeightNodeShader } from "./CustomMapHeightNodeShader";
|
import { CustomMapHeightNodeShader } from "./CustomMapHeightNodeShader";
|
||||||
import { Data, createSVG } from "./utils/create-borehole-svg";
|
import { Data, createSVG } from "./utils/create-borehole-svg";
|
||||||
|
|
||||||
|
@ -361,6 +366,7 @@ export class SceneView extends EventTarget {
|
||||||
this._extent.zmax = this._model.userData.zmax;
|
this._extent.zmax = this._model.userData.zmax;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reset clipping box
|
||||||
const box = this._scene.getObjectByName("clipping-box");
|
const box = this._scene.getObjectByName("clipping-box");
|
||||||
let visible = false;
|
let visible = false;
|
||||||
if (box) {
|
if (box) {
|
||||||
|
@ -464,7 +470,10 @@ async function init(container: HTMLElement, modelId = MODEL_ID) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create the map view for OSM topography
|
// Create the map view for OSM topography
|
||||||
const map = new MapView(MapView.PLANAR, provider, heightProvider);
|
const lod = new LODFrustum();
|
||||||
|
|
||||||
|
// @ts-expect-error Type definition for MapView is incorrect - missing parameter for lod
|
||||||
|
const map = new MapView(MapView.PLANAR, provider, heightProvider, lod);
|
||||||
const customNode = new CustomMapHeightNodeShader(undefined, map);
|
const customNode = new CustomMapHeightNodeShader(undefined, map);
|
||||||
map.setRoot(customNode);
|
map.setRoot(customNode);
|
||||||
map.rotateX(Math.PI / 2);
|
map.rotateX(Math.PI / 2);
|
||||||
|
|
|
@ -26,6 +26,9 @@ export enum Orientation {
|
||||||
X = "X",
|
X = "X",
|
||||||
Y = "Y",
|
Y = "Y",
|
||||||
Z = "Z",
|
Z = "Z",
|
||||||
|
NX = "NX",
|
||||||
|
NY = "NY",
|
||||||
|
NZ = "NZ",
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlaneMesh = Mesh<PlaneGeometry, MeshBasicMaterial, Object3DEventMap>;
|
type PlaneMesh = Mesh<PlaneGeometry, MeshBasicMaterial, Object3DEventMap>;
|
||||||
|
@ -37,10 +40,13 @@ type EdgeMesh = LineSegments<
|
||||||
type PlaneMeshMap = {
|
type PlaneMeshMap = {
|
||||||
[key in Orientation]: PlaneMesh;
|
[key in Orientation]: PlaneMesh;
|
||||||
};
|
};
|
||||||
type EdgeMashMap = {
|
type EdgeMeshMap = {
|
||||||
[key in Orientation]: EdgeMesh;
|
[key in Orientation]: EdgeMesh;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let currentExtent: Extent;
|
||||||
|
const BUFFER = 500;
|
||||||
|
|
||||||
export function buildClippingplanes(
|
export function buildClippingplanes(
|
||||||
renderer: WebGLRenderer,
|
renderer: WebGLRenderer,
|
||||||
camera: PerspectiveCamera,
|
camera: PerspectiveCamera,
|
||||||
|
@ -50,6 +56,9 @@ export function buildClippingplanes(
|
||||||
scene: Scene,
|
scene: Scene,
|
||||||
visible: boolean
|
visible: boolean
|
||||||
) {
|
) {
|
||||||
|
// Set current extent to given extent
|
||||||
|
currentExtent = { ...extent };
|
||||||
|
|
||||||
const planesData = [
|
const planesData = [
|
||||||
{
|
{
|
||||||
normal: new Vector3(1, 0, 0),
|
normal: new Vector3(1, 0, 0),
|
||||||
|
@ -61,10 +70,25 @@ export function buildClippingplanes(
|
||||||
d: -extent.ymin,
|
d: -extent.ymin,
|
||||||
orientation: Orientation.Y,
|
orientation: Orientation.Y,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
normal: new Vector3(0, 0, 1),
|
||||||
|
d: -extent.zmin,
|
||||||
|
orientation: Orientation.Z,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
normal: new Vector3(-1, 0, 0),
|
||||||
|
d: extent.xmax,
|
||||||
|
orientation: Orientation.NX,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
normal: new Vector3(0, -1, 0),
|
||||||
|
d: extent.ymax,
|
||||||
|
orientation: Orientation.NY,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
normal: new Vector3(0, 0, -1),
|
normal: new Vector3(0, 0, -1),
|
||||||
d: extent.zmax,
|
d: extent.zmax,
|
||||||
orientation: Orientation.Z,
|
orientation: Orientation.NZ,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -72,7 +96,7 @@ export function buildClippingplanes(
|
||||||
const edgeMeshes: EdgeMesh[] = [];
|
const edgeMeshes: EdgeMesh[] = [];
|
||||||
const planes: Plane[] = [];
|
const planes: Plane[] = [];
|
||||||
const planeMeshMap = {} as Partial<PlaneMeshMap>;
|
const planeMeshMap = {} as Partial<PlaneMeshMap>;
|
||||||
const edgeMeshMap = {} as Partial<EdgeMashMap>;
|
const edgeMeshMap = {} as Partial<EdgeMeshMap>;
|
||||||
|
|
||||||
// Create plane meshes
|
// Create plane meshes
|
||||||
for (const p of planesData) {
|
for (const p of planesData) {
|
||||||
|
@ -80,32 +104,35 @@ export function buildClippingplanes(
|
||||||
let planeCenter;
|
let planeCenter;
|
||||||
let width;
|
let width;
|
||||||
let height;
|
let height;
|
||||||
if (p.orientation === Orientation.X) {
|
if (p.orientation === Orientation.X || p.orientation === Orientation.NX) {
|
||||||
name = Orientation.X;
|
name = p.orientation;
|
||||||
width = extent.ymax - extent.ymin;
|
width = extent.ymax - extent.ymin;
|
||||||
height = extent.zmax - extent.zmin;
|
height = extent.zmax - extent.zmin;
|
||||||
planeCenter = new Vector3(
|
planeCenter = new Vector3(
|
||||||
-p.d,
|
p.orientation === Orientation.X ? -p.d : p.d,
|
||||||
extent.ymax - width / 2,
|
extent.ymax - width / 2,
|
||||||
extent.zmin + height / 2
|
extent.zmax - height / 2
|
||||||
);
|
);
|
||||||
} else if (p.orientation === Orientation.Y) {
|
} else if (
|
||||||
name = Orientation.Y;
|
p.orientation === Orientation.Y ||
|
||||||
|
p.orientation === Orientation.NY
|
||||||
|
) {
|
||||||
|
name = p.orientation;
|
||||||
width = extent.xmax - extent.xmin;
|
width = extent.xmax - extent.xmin;
|
||||||
height = extent.zmax - extent.zmin;
|
height = extent.zmax - extent.zmin;
|
||||||
planeCenter = new Vector3(
|
planeCenter = new Vector3(
|
||||||
extent.xmax - width / 2,
|
extent.xmax - width / 2,
|
||||||
-p.d,
|
p.orientation === Orientation.Y ? -p.d : p.d,
|
||||||
extent.zmin + height / 2
|
extent.zmax - height / 2
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
name = Orientation.Z;
|
name = p.orientation;
|
||||||
width = extent.xmax - extent.xmin;
|
width = extent.xmax - extent.xmin;
|
||||||
height = extent.ymax - extent.ymin;
|
height = extent.ymax - extent.ymin;
|
||||||
planeCenter = new Vector3(
|
planeCenter = new Vector3(
|
||||||
extent.xmax - width / 2,
|
extent.xmax - width / 2,
|
||||||
extent.ymax - height / 2,
|
extent.ymax - height / 2,
|
||||||
p.d
|
p.orientation === Orientation.Z ? -p.d : p.d
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,12 +164,15 @@ export function buildClippingplanes(
|
||||||
edges.position.set(planeCenter.x, planeCenter.y, planeCenter.z);
|
edges.position.set(planeCenter.x, planeCenter.y, planeCenter.z);
|
||||||
|
|
||||||
// Rotate meshes
|
// Rotate meshes
|
||||||
if (p.orientation === Orientation.X) {
|
if (p.orientation === Orientation.X || p.orientation === Orientation.NX) {
|
||||||
planeMesh.rotateY(Math.PI / 2);
|
planeMesh.rotateY(Math.PI / 2);
|
||||||
planeMesh.rotateZ(Math.PI / 2);
|
planeMesh.rotateZ(Math.PI / 2);
|
||||||
edges.rotateY(Math.PI / 2);
|
edges.rotateY(Math.PI / 2);
|
||||||
edges.rotateZ(Math.PI / 2);
|
edges.rotateZ(Math.PI / 2);
|
||||||
} else if (p.orientation === Orientation.Y) {
|
} else if (
|
||||||
|
p.orientation === Orientation.Y ||
|
||||||
|
p.orientation === Orientation.NY
|
||||||
|
) {
|
||||||
planeMesh.rotateX(Math.PI / 2);
|
planeMesh.rotateX(Math.PI / 2);
|
||||||
edges.rotateX(Math.PI / 2);
|
edges.rotateX(Math.PI / 2);
|
||||||
}
|
}
|
||||||
|
@ -194,118 +224,163 @@ export function buildClippingplanes(
|
||||||
const plane = event.object.userData.plane;
|
const plane = event.object.userData.plane;
|
||||||
const width = object.geometry.parameters.width;
|
const width = object.geometry.parameters.width;
|
||||||
const height = object.geometry.parameters.height;
|
const height = object.geometry.parameters.height;
|
||||||
let orientation: Orientation;
|
const orientation = object.name as Orientation;
|
||||||
if (object.name === Orientation.Z) {
|
|
||||||
orientation = Orientation.Z;
|
if (orientation === Orientation.Z || orientation === Orientation.NZ) {
|
||||||
// Fix rotation of dragged mesh
|
// Fix rotation of dragged mesh
|
||||||
event.object.rotation.set(0, 0, 0);
|
event.object.rotation.set(0, 0, 0);
|
||||||
|
|
||||||
let newZ;
|
let newZ = 0;
|
||||||
if (event.object.position.z > extent.zmax) {
|
if (orientation === Orientation.Z) {
|
||||||
newZ = extent.zmax;
|
if (event.object.position.z < extent.zmin) {
|
||||||
} else if (event.object.position.z < extent.zmin) {
|
|
||||||
newZ = extent.zmin;
|
newZ = extent.zmin;
|
||||||
|
} else if (event.object.position.z > currentExtent.zmax - BUFFER) {
|
||||||
|
newZ = currentExtent.zmax - BUFFER;
|
||||||
} else {
|
} else {
|
||||||
newZ = event.object.position.z;
|
newZ = event.object.position.z;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (event.object.position.z > extent.zmax) {
|
||||||
|
newZ = extent.zmax;
|
||||||
|
} else if (event.object.position.z < currentExtent.zmin + BUFFER) {
|
||||||
|
newZ = currentExtent.zmin + BUFFER;
|
||||||
|
} else {
|
||||||
|
newZ = event.object.position.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reset position of plane
|
// Reset position of plane
|
||||||
plane.constant = newZ;
|
plane.constant = orientation === Orientation.Z ? -newZ : newZ;
|
||||||
|
|
||||||
|
// Update current extent
|
||||||
|
if (orientation === Orientation.Z) {
|
||||||
|
currentExtent.zmin = newZ;
|
||||||
|
} else {
|
||||||
|
currentExtent.zmax = newZ;
|
||||||
|
}
|
||||||
|
|
||||||
// Set position of dragged meshes
|
// Set position of dragged meshes
|
||||||
object.position.x = extent.xmax - width / 2;
|
object.position.x = currentExtent.xmax - width / 2;
|
||||||
object.position.y = extent.ymax - height / 2;
|
object.position.y = currentExtent.ymax - height / 2;
|
||||||
object.position.z = newZ;
|
object.position.z = newZ;
|
||||||
|
|
||||||
const edgeMesh = edgeMeshMap[Orientation.Z];
|
const edgeMesh = edgeMeshMap[orientation];
|
||||||
if (edgeMesh) {
|
if (edgeMesh) {
|
||||||
edgeMesh.position.x = extent.xmax - width / 2;
|
edgeMesh.position.x = currentExtent.xmax - width / 2;
|
||||||
edgeMesh.position.y = extent.ymax - height / 2;
|
edgeMesh.position.y = currentExtent.ymax - height / 2;
|
||||||
edgeMesh.position.z = newZ;
|
edgeMesh.position.z = newZ;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize other meshes to disable dragging of clipped surface parts
|
// Resize other meshes to disable dragging of clipped surface parts
|
||||||
resizeMeshes(
|
resizeMeshes(
|
||||||
Orientation.Z,
|
orientation,
|
||||||
newZ,
|
|
||||||
planeMeshMap as PlaneMeshMap,
|
planeMeshMap as PlaneMeshMap,
|
||||||
edgeMeshMap as EdgeMashMap,
|
edgeMeshMap as EdgeMeshMap
|
||||||
extent
|
|
||||||
);
|
);
|
||||||
} else if (object.name === Orientation.Y) {
|
} else if (
|
||||||
orientation = Orientation.Y;
|
orientation === Orientation.Y ||
|
||||||
|
orientation === Orientation.NY
|
||||||
|
) {
|
||||||
// Fix rotation of dragged mesh
|
// Fix rotation of dragged mesh
|
||||||
event.object.rotation.set(Math.PI / 2, 0, 0);
|
event.object.rotation.set(Math.PI / 2, 0, 0);
|
||||||
|
|
||||||
let newY;
|
let newY = 0;
|
||||||
if (event.object.position.y > extent.ymax) {
|
if (orientation === Orientation.Y) {
|
||||||
newY = extent.ymax;
|
if (event.object.position.y < extent.ymin) {
|
||||||
} else if (event.object.position.y < extent.ymin) {
|
|
||||||
newY = extent.ymin;
|
newY = extent.ymin;
|
||||||
|
} else if (event.object.position.y > currentExtent.ymax - BUFFER) {
|
||||||
|
newY = currentExtent.ymax - BUFFER;
|
||||||
} else {
|
} else {
|
||||||
newY = event.object.position.y;
|
newY = event.object.position.y;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (event.object.position.y > extent.ymax) {
|
||||||
|
newY = extent.ymax;
|
||||||
|
} else if (event.object.position.y < currentExtent.ymin + BUFFER) {
|
||||||
|
newY = currentExtent.ymin + BUFFER;
|
||||||
|
} else {
|
||||||
|
newY = event.object.position.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reset position of plane
|
// Reset position of plane
|
||||||
plane.constant = -newY;
|
plane.constant = orientation === Orientation.Y ? -newY : newY;
|
||||||
|
|
||||||
|
// Update current extent
|
||||||
|
if (orientation === Orientation.Y) {
|
||||||
|
currentExtent.ymin = newY;
|
||||||
|
} else {
|
||||||
|
currentExtent.ymax = newY;
|
||||||
|
}
|
||||||
|
|
||||||
// Set position of dragged mesh
|
// Set position of dragged mesh
|
||||||
object.position.x = extent.xmax - width / 2;
|
object.position.x = currentExtent.xmax - width / 2;
|
||||||
object.position.y = newY;
|
object.position.y = newY;
|
||||||
object.position.z = extent.zmin + height / 2;
|
object.position.z = currentExtent.zmax - height / 2;
|
||||||
|
|
||||||
const edgeMesh = edgeMeshMap[Orientation.Y];
|
const edgeMesh = edgeMeshMap[orientation];
|
||||||
if (edgeMesh) {
|
if (edgeMesh) {
|
||||||
edgeMesh.position.x = extent.xmax - width / 2;
|
edgeMesh.position.x = currentExtent.xmax - width / 2;
|
||||||
edgeMesh.position.y = newY;
|
edgeMesh.position.y = newY;
|
||||||
edgeMesh.position.z = extent.zmin + height / 2;
|
edgeMesh.position.z = currentExtent.zmax - height / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize other meshes
|
// Resize other meshes
|
||||||
resizeMeshes(
|
resizeMeshes(
|
||||||
Orientation.Y,
|
orientation,
|
||||||
newY,
|
|
||||||
planeMeshMap as PlaneMeshMap,
|
planeMeshMap as PlaneMeshMap,
|
||||||
edgeMeshMap as EdgeMashMap,
|
edgeMeshMap as EdgeMeshMap
|
||||||
extent
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
orientation = Orientation.X;
|
|
||||||
|
|
||||||
// Fix rotation of dragged mesh
|
// Fix rotation of dragged mesh
|
||||||
event.object.rotation.set(0, Math.PI / 2, Math.PI / 2);
|
event.object.rotation.set(0, Math.PI / 2, Math.PI / 2);
|
||||||
|
|
||||||
let newX;
|
let newX = 0;
|
||||||
if (event.object.position.x > extent.xmax) {
|
if (orientation === Orientation.X) {
|
||||||
newX = extent.xmax;
|
if (event.object.position.x < extent.xmin) {
|
||||||
} else if (event.object.position.x < extent.xmin) {
|
|
||||||
newX = extent.xmin;
|
newX = extent.xmin;
|
||||||
|
} else if (event.object.position.x > currentExtent.xmax - BUFFER) {
|
||||||
|
newX = currentExtent.xmax - BUFFER;
|
||||||
} else {
|
} else {
|
||||||
newX = event.object.position.x;
|
newX = event.object.position.x;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (event.object.position.x > extent.xmax) {
|
||||||
|
newX = extent.xmax;
|
||||||
|
} else if (event.object.position.x < currentExtent.xmin + BUFFER) {
|
||||||
|
newX = currentExtent.xmin + BUFFER;
|
||||||
|
} else {
|
||||||
|
newX = event.object.position.x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reset position of plane
|
// Reset position of plane
|
||||||
plane.constant = -newX;
|
plane.constant = orientation === Orientation.X ? -newX : newX;
|
||||||
|
|
||||||
|
// Update current extent
|
||||||
|
if (orientation === Orientation.X) {
|
||||||
|
currentExtent.xmin = newX;
|
||||||
|
} else {
|
||||||
|
currentExtent.xmax = newX;
|
||||||
|
}
|
||||||
|
|
||||||
// Set position of dragged mesh
|
// Set position of dragged mesh
|
||||||
object.position.x = newX;
|
object.position.x = newX;
|
||||||
object.position.y = extent.ymax - width / 2;
|
object.position.y = currentExtent.ymax - width / 2;
|
||||||
object.position.z = extent.zmin + height / 2;
|
object.position.z = currentExtent.zmax - height / 2;
|
||||||
|
|
||||||
const edgeMesh = edgeMeshMap[Orientation.X];
|
const edgeMesh = edgeMeshMap[orientation];
|
||||||
if (edgeMesh) {
|
if (edgeMesh) {
|
||||||
edgeMesh.position.x = newX;
|
edgeMesh.position.x = newX;
|
||||||
edgeMesh.position.y = extent.ymax - width / 2;
|
edgeMesh.position.y = currentExtent.ymax - width / 2;
|
||||||
edgeMesh.position.z = extent.zmin + height / 2;
|
edgeMesh.position.z = currentExtent.zmax - height / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize other meshes
|
// Resize other meshes
|
||||||
resizeMeshes(
|
resizeMeshes(
|
||||||
Orientation.X,
|
orientation,
|
||||||
newX,
|
|
||||||
planeMeshMap as PlaneMeshMap,
|
planeMeshMap as PlaneMeshMap,
|
||||||
edgeMeshMap as EdgeMashMap,
|
edgeMeshMap as EdgeMeshMap
|
||||||
extent
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,121 +416,157 @@ export function buildClippingplanes(
|
||||||
|
|
||||||
function resizeMeshes(
|
function resizeMeshes(
|
||||||
orientation: Orientation,
|
orientation: Orientation,
|
||||||
newCoordinate: number,
|
|
||||||
planeMeshes: PlaneMeshMap,
|
planeMeshes: PlaneMeshMap,
|
||||||
edgeMeshes: EdgeMashMap,
|
edgeMeshes: EdgeMeshMap
|
||||||
extent: Extent
|
|
||||||
) {
|
) {
|
||||||
if (orientation === Orientation.X) {
|
if (orientation === Orientation.X || orientation === Orientation.NX) {
|
||||||
// Resize y-clipping plane
|
// Resize y-clipping-planes
|
||||||
let planeMesh = planeMeshes[Orientation.Y];
|
for (const o of [Orientation.Y, Orientation.NY]) {
|
||||||
let edgeMesh = edgeMeshes[Orientation.Y];
|
const planeMesh = planeMeshes[o];
|
||||||
let width = extent.xmax - newCoordinate;
|
const width = currentExtent.xmax - currentExtent.xmin;
|
||||||
let height = planeMesh.geometry.parameters.height;
|
const height = planeMesh.geometry.parameters.height;
|
||||||
let planeGeometry = new PlaneGeometry(width, height);
|
|
||||||
const y = planeMesh.position.y;
|
const y = planeMesh.position.y;
|
||||||
planeMesh.geometry.dispose();
|
const newPosition = new Vector3(
|
||||||
planeMesh.geometry = planeGeometry;
|
currentExtent.xmax - width / 2,
|
||||||
planeMesh.position.set(
|
|
||||||
extent.xmax - width / 2,
|
|
||||||
y,
|
y,
|
||||||
extent.zmin + height / 2
|
currentExtent.zmax - height / 2
|
||||||
);
|
);
|
||||||
edgeMesh.geometry.dispose();
|
resizeClippingPlane(
|
||||||
edgeMesh.geometry = new EdgesGeometry(planeGeometry);
|
o,
|
||||||
edgeMesh.position.set(extent.xmax - width / 2, y, extent.zmin + height / 2);
|
planeMeshes,
|
||||||
|
edgeMeshes,
|
||||||
// Resize z-clipping-plane
|
width,
|
||||||
planeMesh = planeMeshes[Orientation.Z];
|
height,
|
||||||
edgeMesh = edgeMeshes[Orientation.Z];
|
newPosition
|
||||||
width = extent.xmax - newCoordinate;
|
|
||||||
height = planeMesh.geometry.parameters.height;
|
|
||||||
planeGeometry = new PlaneGeometry(width, height);
|
|
||||||
const z = planeMesh.position.z;
|
|
||||||
planeMesh.geometry.dispose();
|
|
||||||
planeMesh.geometry = planeGeometry;
|
|
||||||
planeMesh.position.set(
|
|
||||||
extent.xmax - width / 2,
|
|
||||||
extent.ymax - height / 2,
|
|
||||||
z
|
|
||||||
);
|
);
|
||||||
edgeMesh.geometry.dispose();
|
|
||||||
edgeMesh.geometry = new EdgesGeometry(planeGeometry);
|
|
||||||
edgeMesh.position.set(extent.xmax - width / 2, extent.ymax - height / 2, z);
|
|
||||||
} else if (orientation === Orientation.Y) {
|
|
||||||
// Resize x-clipping plane
|
|
||||||
let planeMesh = planeMeshes[Orientation.X];
|
|
||||||
let edgeMesh = edgeMeshes[Orientation.X];
|
|
||||||
let width = extent.ymax - newCoordinate;
|
|
||||||
let height = planeMesh.geometry.parameters.height;
|
|
||||||
let planeGeometry = new PlaneGeometry(width, height);
|
|
||||||
const x = planeMesh.position.x;
|
|
||||||
planeMesh.geometry.dispose();
|
|
||||||
planeMesh.geometry = planeGeometry;
|
|
||||||
planeMesh.position.set(
|
|
||||||
x,
|
|
||||||
extent.ymax - width / 2,
|
|
||||||
extent.zmin + height / 2
|
|
||||||
);
|
|
||||||
edgeMesh.geometry.dispose();
|
|
||||||
edgeMesh.geometry = new EdgesGeometry(planeGeometry);
|
|
||||||
edgeMesh.position.set(x, extent.ymax - width / 2, extent.zmin + height / 2);
|
|
||||||
|
|
||||||
// Resize z-clipping-plane
|
|
||||||
planeMesh = planeMeshes[Orientation.Z];
|
|
||||||
edgeMesh = edgeMeshes[Orientation.Z];
|
|
||||||
width = planeMesh.geometry.parameters.width;
|
|
||||||
height = extent.ymax - newCoordinate;
|
|
||||||
planeGeometry = new PlaneGeometry(width, height);
|
|
||||||
const z = planeMesh.position.z;
|
|
||||||
planeMesh.geometry.dispose();
|
|
||||||
planeMesh.geometry = planeGeometry;
|
|
||||||
planeMesh.position.set(
|
|
||||||
extent.xmax - width / 2,
|
|
||||||
extent.ymax - height / 2,
|
|
||||||
z
|
|
||||||
);
|
|
||||||
edgeMesh.geometry.dispose();
|
|
||||||
edgeMesh.geometry = new EdgesGeometry(planeGeometry);
|
|
||||||
edgeMesh.position.set(extent.xmax - width / 2, extent.ymax - height / 2, z);
|
|
||||||
} else if (orientation === Orientation.Z) {
|
|
||||||
// Resize x-clipping-plane
|
|
||||||
let planeMesh = planeMeshes[Orientation.X];
|
|
||||||
let edgeMesh = edgeMeshes[Orientation.X];
|
|
||||||
let width = planeMesh.geometry.parameters.width;
|
|
||||||
let height = newCoordinate - extent.zmin;
|
|
||||||
let planeGeometry = new PlaneGeometry(width, height);
|
|
||||||
const x = planeMesh.position.x;
|
|
||||||
planeMesh.geometry.dispose();
|
|
||||||
planeMesh.geometry = planeGeometry;
|
|
||||||
planeMesh.position.set(
|
|
||||||
x,
|
|
||||||
extent.ymax - width / 2,
|
|
||||||
extent.zmin + height / 2
|
|
||||||
);
|
|
||||||
edgeMesh.geometry.dispose();
|
|
||||||
edgeMesh.geometry = new EdgesGeometry(planeGeometry);
|
|
||||||
edgeMesh.position.set(x, extent.ymax - width / 2, extent.zmin + height / 2);
|
|
||||||
|
|
||||||
// Resize y-clipping plane
|
|
||||||
planeMesh = planeMeshes[Orientation.Y];
|
|
||||||
edgeMesh = edgeMeshes[Orientation.Y];
|
|
||||||
width = planeMesh.geometry.parameters.width;
|
|
||||||
height = newCoordinate - extent.zmin;
|
|
||||||
planeGeometry = new PlaneGeometry(width, height);
|
|
||||||
const y = planeMesh.position.y;
|
|
||||||
planeMesh.geometry.dispose();
|
|
||||||
planeMesh.geometry = planeGeometry;
|
|
||||||
planeMesh.position.set(
|
|
||||||
extent.xmax - width / 2,
|
|
||||||
y,
|
|
||||||
extent.zmin + height / 2
|
|
||||||
);
|
|
||||||
|
|
||||||
edgeMesh.geometry.dispose();
|
|
||||||
edgeMesh.geometry = new EdgesGeometry(planeGeometry);
|
|
||||||
edgeMesh.position.set(extent.xmax - width / 2, y, extent.zmin + height / 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resize z-clipping-planes
|
||||||
|
for (const o of [Orientation.Z, Orientation.NZ]) {
|
||||||
|
const planeMesh = planeMeshes[o];
|
||||||
|
const width = currentExtent.xmax - currentExtent.xmin;
|
||||||
|
const height = planeMesh.geometry.parameters.height;
|
||||||
|
const z = planeMesh.position.z;
|
||||||
|
const newPosition = new Vector3(
|
||||||
|
currentExtent.xmax - width / 2,
|
||||||
|
currentExtent.ymax - height / 2,
|
||||||
|
z
|
||||||
|
);
|
||||||
|
resizeClippingPlane(
|
||||||
|
o,
|
||||||
|
planeMeshes,
|
||||||
|
edgeMeshes,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
newPosition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else if (orientation === Orientation.Y || orientation === Orientation.NY) {
|
||||||
|
// Resize x-clipping-planes
|
||||||
|
for (const o of [Orientation.X, Orientation.NX]) {
|
||||||
|
const planeMesh = planeMeshes[o];
|
||||||
|
const width = currentExtent.ymax - currentExtent.ymin;
|
||||||
|
const height = planeMesh.geometry.parameters.height;
|
||||||
|
const x = planeMesh.position.x;
|
||||||
|
const newPosition = new Vector3(
|
||||||
|
x,
|
||||||
|
currentExtent.ymax - width / 2,
|
||||||
|
currentExtent.zmax - height / 2
|
||||||
|
);
|
||||||
|
resizeClippingPlane(
|
||||||
|
o,
|
||||||
|
planeMeshes,
|
||||||
|
edgeMeshes,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
newPosition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize z-clipping-planes
|
||||||
|
for (const o of [Orientation.Z, Orientation.NZ]) {
|
||||||
|
const planeMesh = planeMeshes[o];
|
||||||
|
const width = planeMesh.geometry.parameters.width;
|
||||||
|
const height = currentExtent.ymax - currentExtent.ymin;
|
||||||
|
const z = planeMesh.position.z;
|
||||||
|
const newPosition = new Vector3(
|
||||||
|
currentExtent.xmax - width / 2,
|
||||||
|
currentExtent.ymax - height / 2,
|
||||||
|
z
|
||||||
|
);
|
||||||
|
resizeClippingPlane(
|
||||||
|
o,
|
||||||
|
planeMeshes,
|
||||||
|
edgeMeshes,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
newPosition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Resize x-clipping-planes
|
||||||
|
for (const o of [Orientation.X, Orientation.NX]) {
|
||||||
|
const height = currentExtent.zmax - currentExtent.zmin;
|
||||||
|
const planeMesh = planeMeshes[o];
|
||||||
|
const width = planeMesh.geometry.parameters.width;
|
||||||
|
const x = planeMesh.position.x;
|
||||||
|
const newPosition = new Vector3(
|
||||||
|
x,
|
||||||
|
currentExtent.ymax - width / 2,
|
||||||
|
currentExtent.zmax - height / 2
|
||||||
|
);
|
||||||
|
resizeClippingPlane(
|
||||||
|
o,
|
||||||
|
planeMeshes,
|
||||||
|
edgeMeshes,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
newPosition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resize y-clipping-planes
|
||||||
|
for (const o of [Orientation.Y, Orientation.NY]) {
|
||||||
|
const planeMesh = planeMeshes[o];
|
||||||
|
const width = planeMesh.geometry.parameters.width;
|
||||||
|
const height = currentExtent.zmax - currentExtent.zmin;
|
||||||
|
const y = planeMesh.position.y;
|
||||||
|
const newPosition = new Vector3(
|
||||||
|
currentExtent.xmax - width / 2,
|
||||||
|
y,
|
||||||
|
currentExtent.zmax - height / 2
|
||||||
|
);
|
||||||
|
resizeClippingPlane(
|
||||||
|
o,
|
||||||
|
planeMeshes,
|
||||||
|
edgeMeshes,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
newPosition
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resizeClippingPlane(
|
||||||
|
orientation: Orientation,
|
||||||
|
planeMeshes: PlaneMeshMap,
|
||||||
|
edgeMeshes: EdgeMeshMap,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
position: Vector3
|
||||||
|
) {
|
||||||
|
const planeMesh = planeMeshes[orientation];
|
||||||
|
const edgeMesh = edgeMeshes[orientation];
|
||||||
|
const planeGeometry = new PlaneGeometry(width, height);
|
||||||
|
|
||||||
|
planeMesh.geometry.dispose();
|
||||||
|
planeMesh.geometry = planeGeometry;
|
||||||
|
planeMesh.position.copy(position);
|
||||||
|
|
||||||
|
edgeMesh.geometry.dispose();
|
||||||
|
edgeMesh.geometry = new EdgesGeometry(planeGeometry);
|
||||||
|
edgeMesh.position.copy(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extract contour and generate cap
|
// Extract contour and generate cap
|
||||||
|
|
|
@ -40,9 +40,14 @@ async function buildMesh(layerData: MappedFeature) {
|
||||||
|
|
||||||
// Transform coordinates to EPSG 3857
|
// Transform coordinates to EPSG 3857
|
||||||
const vertices3857 = new Float32Array(vertices.length);
|
const vertices3857 = new Float32Array(vertices.length);
|
||||||
|
|
||||||
|
// Reduce coordinate precision
|
||||||
for (let i = 0; i < vertices.length; i += 3) {
|
for (let i = 0; i < vertices.length; i += 3) {
|
||||||
const vertex = Array.from(vertices.slice(i, i + 3));
|
const vertex = Array.from(vertices.slice(i, i + 3));
|
||||||
vertices3857.set(transform(vertex), i);
|
vertices3857.set(
|
||||||
|
transform(vertex).map((c) => parseInt(c.toFixed(0))),
|
||||||
|
i
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const positions = new BufferAttribute(vertices3857, 3);
|
const positions = new BufferAttribute(vertices3857, 3);
|
||||||
|
|
|
@ -6,10 +6,15 @@ import {
|
||||||
DirectionalLight,
|
DirectionalLight,
|
||||||
Group,
|
Group,
|
||||||
Object3D,
|
Object3D,
|
||||||
AxesHelper,
|
|
||||||
OrthographicCamera,
|
OrthographicCamera,
|
||||||
Color,
|
Color,
|
||||||
Vector3,
|
Vector3,
|
||||||
|
BufferGeometry,
|
||||||
|
BufferAttribute,
|
||||||
|
DoubleSide,
|
||||||
|
Mesh,
|
||||||
|
MeshBasicMaterial,
|
||||||
|
ConeGeometry,
|
||||||
} from "three";
|
} from "three";
|
||||||
|
|
||||||
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
|
||||||
|
@ -28,12 +33,13 @@ let controls: OrbitControls;
|
||||||
let renderer: WebGLRenderer;
|
let renderer: WebGLRenderer;
|
||||||
let camera: PerspectiveCamera;
|
let camera: PerspectiveCamera;
|
||||||
let scene: Scene;
|
let scene: Scene;
|
||||||
let axesHelper: AxesHelper;
|
|
||||||
let overlayCamera: OrthographicCamera;
|
let overlayCamera: OrthographicCamera;
|
||||||
let overlayScene: Scene;
|
let overlayScene: Scene;
|
||||||
let overlayWidth = 200;
|
|
||||||
let overlayHeight = 200;
|
|
||||||
let maxSize = 0;
|
let maxSize = 0;
|
||||||
|
const compass = new Group();
|
||||||
|
const UI_WIDTH = 200;
|
||||||
|
const UI_HEIGHT = 200;
|
||||||
|
|
||||||
export function buildScene(container: HTMLElement, extent: Extent) {
|
export function buildScene(container: HTMLElement, extent: Extent) {
|
||||||
maxSize = getMaxSize(extent);
|
maxSize = getMaxSize(extent);
|
||||||
const center = getCenter3D(extent);
|
const center = getCenter3D(extent);
|
||||||
|
@ -63,8 +69,8 @@ export function buildScene(container: HTMLElement, extent: Extent) {
|
||||||
container.appendChild(renderer.domElement);
|
container.appendChild(renderer.domElement);
|
||||||
|
|
||||||
controls = new OrbitControls(camera, renderer.domElement);
|
controls = new OrbitControls(camera, renderer.domElement);
|
||||||
controls.target.set(center.x, center.y, center.z); // Focus on the center
|
controls.target.set(center.x, center.y, center.z);
|
||||||
controls.enableDamping = true; // Smooth camera movement
|
controls.enableDamping = true;
|
||||||
controls.dampingFactor = 0.1;
|
controls.dampingFactor = 0.1;
|
||||||
controls.maxDistance = maxSize * 3;
|
controls.maxDistance = maxSize * 3;
|
||||||
controls.minDistance = maxSize / 5;
|
controls.minDistance = maxSize / 5;
|
||||||
|
@ -74,34 +80,32 @@ export function buildScene(container: HTMLElement, extent: Extent) {
|
||||||
// Set wireframe to false on initial load
|
// Set wireframe to false on initial load
|
||||||
scene = new Scene();
|
scene = new Scene();
|
||||||
scene.userData.wireframe = false;
|
scene.userData.wireframe = false;
|
||||||
scene.background = new Color(0xbfd1e5);
|
const backgroundColor = new Color(0xbfd1e5);
|
||||||
|
scene.background = backgroundColor;
|
||||||
|
renderer.setClearColor(backgroundColor);
|
||||||
|
|
||||||
// Add lights to the scene
|
// Add lights to the scene
|
||||||
buildDefaultLights(scene, extent);
|
buildDefaultLights(scene, extent);
|
||||||
|
|
||||||
|
// Create Scene for UI overlay
|
||||||
overlayScene = new Scene();
|
overlayScene = new Scene();
|
||||||
|
|
||||||
// Create an overlay camera
|
// Create an overlay camera
|
||||||
overlayWidth = maxSize;
|
|
||||||
overlayHeight = maxSize;
|
|
||||||
overlayCamera = new OrthographicCamera(
|
overlayCamera = new OrthographicCamera(
|
||||||
-overlayWidth / 2,
|
-maxSize / 2,
|
||||||
overlayWidth / 2,
|
maxSize / 2,
|
||||||
overlayHeight / 2,
|
maxSize / 2,
|
||||||
-overlayHeight / 2,
|
-maxSize / 2,
|
||||||
0.1,
|
0.1,
|
||||||
10 * maxSize
|
10 * maxSize
|
||||||
);
|
);
|
||||||
|
|
||||||
// Position the camera similarly to how you did with PerspectiveCamera
|
// Sync overlay camera with main camera
|
||||||
overlayCamera.position.copy(camera.position);
|
overlayCamera.position.copy(camera.position);
|
||||||
overlayCamera.up.copy(camera.up);
|
overlayCamera.rotation.copy(camera.rotation);
|
||||||
overlayCamera.lookAt(center);
|
|
||||||
|
|
||||||
// Create the AxesHelper
|
// Create compass
|
||||||
axesHelper = new AxesHelper(maxSize);
|
createCompass(center);
|
||||||
axesHelper.position.set(center.x, center.y, center.z);
|
|
||||||
overlayScene.add(axesHelper);
|
|
||||||
|
|
||||||
return { renderer, scene, camera, controls };
|
return { renderer, scene, camera, controls };
|
||||||
}
|
}
|
||||||
|
@ -121,32 +125,31 @@ function animate() {
|
||||||
// Update controls for main camera
|
// Update controls for main camera
|
||||||
controls.update();
|
controls.update();
|
||||||
|
|
||||||
renderer.autoClear = false;
|
|
||||||
renderer.render(scene, camera);
|
renderer.render(scene, camera);
|
||||||
|
|
||||||
|
// Render the UI overlay
|
||||||
renderOverlay();
|
renderOverlay();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render the overlay scene as an overlay
|
// Render the overlay scene as an overlay
|
||||||
function renderOverlay() {
|
function renderOverlay() {
|
||||||
// Update the overlay camera position and orientation to match the main camera
|
// Sync overlay camera
|
||||||
overlayCamera.position.copy(camera.position);
|
overlayCamera.position.copy(camera.position);
|
||||||
overlayCamera.rotation.copy(camera.rotation);
|
overlayCamera.rotation.copy(camera.rotation);
|
||||||
|
|
||||||
|
// Sync compass
|
||||||
const dir = new Vector3();
|
const dir = new Vector3();
|
||||||
overlayCamera.getWorldDirection(dir);
|
camera.getWorldDirection(dir);
|
||||||
axesHelper.position.set(
|
compass.position.set(
|
||||||
camera.position.x + maxSize * dir.x,
|
camera.position.x + maxSize * dir.x,
|
||||||
camera.position.y + maxSize * dir.y,
|
camera.position.y + maxSize * dir.y,
|
||||||
camera.position.z + maxSize * dir.z
|
camera.position.z + maxSize * dir.z
|
||||||
);
|
);
|
||||||
|
|
||||||
// Render the overlay scene to the screen (position it in the bottom left)
|
// Render the overlay scene to the screen (position it in the bottom left)
|
||||||
const width = 200;
|
|
||||||
const height = 200;
|
|
||||||
renderer.setScissorTest(true);
|
renderer.setScissorTest(true);
|
||||||
renderer.setScissor(10, 10, width, height);
|
renderer.setScissor(10, 10, UI_WIDTH, UI_HEIGHT);
|
||||||
renderer.setViewport(10, 10, width, height);
|
renderer.setViewport(10, 10, UI_WIDTH, UI_HEIGHT);
|
||||||
renderer.render(overlayScene, overlayCamera);
|
renderer.render(overlayScene, overlayCamera);
|
||||||
renderer.setScissorTest(false); // Disable scissor testing for the rest of the scene
|
renderer.setScissorTest(false); // Disable scissor testing for the rest of the scene
|
||||||
renderer.setViewport(
|
renderer.setViewport(
|
||||||
|
@ -194,3 +197,60 @@ function buildDefaultLights(scene: Scene, extent: Extent) {
|
||||||
lightsGroup.add(...lights);
|
lightsGroup.add(...lights);
|
||||||
scene.add(lightsGroup);
|
scene.add(lightsGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createCompass(center: Vector3) {
|
||||||
|
const vertices = new Float32Array(
|
||||||
|
[
|
||||||
|
[0.2, 0, 0],
|
||||||
|
[0, 1, 0],
|
||||||
|
[-0.2, 0, 0],
|
||||||
|
[-0.2, 0, 0],
|
||||||
|
[0, -1, 0],
|
||||||
|
[0.2, 0, 0],
|
||||||
|
].flat()
|
||||||
|
);
|
||||||
|
const positions = new BufferAttribute(vertices, 3);
|
||||||
|
|
||||||
|
const geometry = new BufferGeometry();
|
||||||
|
geometry.setAttribute("position", positions);
|
||||||
|
|
||||||
|
const colors = new Float32Array([
|
||||||
|
1,
|
||||||
|
12 / 255,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
12 / 255,
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
12 / 255,
|
||||||
|
0,
|
||||||
|
113 / 255,
|
||||||
|
99 / 255,
|
||||||
|
183 / 255,
|
||||||
|
113 / 255,
|
||||||
|
99 / 255,
|
||||||
|
183 / 255,
|
||||||
|
113 / 255,
|
||||||
|
99 / 255,
|
||||||
|
183 / 255,
|
||||||
|
]);
|
||||||
|
geometry.setAttribute("color", new BufferAttribute(colors, 3));
|
||||||
|
|
||||||
|
const material = new MeshBasicMaterial({
|
||||||
|
side: DoubleSide,
|
||||||
|
vertexColors: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const needle = new Mesh(geometry, material);
|
||||||
|
|
||||||
|
const coneGeometry = new ConeGeometry(0.1, 0.1, 32);
|
||||||
|
const coneMaterial = new MeshBasicMaterial({ color: 0x444444 });
|
||||||
|
const cone = new Mesh(coneGeometry, coneMaterial);
|
||||||
|
cone.position.z = 0.055;
|
||||||
|
cone.rotateX(Math.PI / 2);
|
||||||
|
|
||||||
|
compass.add(needle, cone);
|
||||||
|
compass.position.copy(center);
|
||||||
|
compass.scale.set(maxSize * 0.5, maxSize * 0.5, maxSize * 0.5);
|
||||||
|
overlayScene.add(compass);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
editor.link_modal.header
Reference in a new issue