Work on compass

This commit is contained in:
Fuhrmann 2025-03-19 13:56:08 +01:00
parent b94151bc01
commit 63fc0d1187
4 changed files with 176 additions and 65 deletions

View file

@ -1,118 +1,157 @@
import {
BufferGeometry,
CanvasTexture,
GridHelper,
Group,
Line,
LineBasicMaterial,
Sprite,
SpriteMaterial,
Vector4,
Vector3,
} from "three";
import { Extent } from "./build-scene";
import { getCenter3D } from "./utils";
enum Orientation {
Horizontal,
Vertical,
X,
Y,
Z,
}
export function buildCoordinateGrid(extent: Extent) {
const center = getCenter3D(extent);
// Calculate the width and height of the grid
const gridWidth = extent.xmax - extent.xmin;
const gridHeight = extent.ymax - extent.ymin;
// Decide on the number of divisions (e.g., 20 divisions along each axis)
const divisions = 20;
// Decide on the number of divisions
const divisions = 10;
// Create a grid helper with the calculated grid size and divisions
const gridHelper = new GridHelper(Math.max(gridWidth, gridHeight), divisions);
// Position the grid in the scene to match the given extent
gridHelper.position.set(center.x, center.y, 0);
// Rotate the grid to align with the XY-plane
gridHelper.rotation.x = Math.PI / 2;
// Retrieve the geometry of the grid helper
const geometry = gridHelper.geometry;
const positionAttr = geometry.getAttribute("position");
const startingPointsHorizontal = [];
const startingPointsVertical = [];
for (let i = 0; i < positionAttr.count; i++) {
const x = positionAttr.getX(i);
const z = positionAttr.getZ(i);
const v = new Vector4(x + center.x, z + center.y, 0, 1);
if (i % 4 === 0) {
startingPointsVertical.push(v);
} else if (i % 2 == 0) {
startingPointsHorizontal.push(v);
}
const xOffset = gridWidth / divisions;
let x = extent.xmin - xOffset;
const xPairs = [];
for (let i = 0; i < divisions + 1; i++) {
x += xOffset;
const start = new Vector3(x, extent.ymin, extent.zmin);
const end = new Vector3(x, extent.ymax, extent.zmin);
xPairs.push([start, end]);
}
const xLines = createLines(xPairs);
const yOffset = gridHeight / divisions;
let y = extent.ymin - yOffset;
const yPairs = [];
for (let i = 0; i < divisions + 1; i++) {
y += yOffset;
const start = new Vector3(extent.xmin, y, extent.zmin);
const end = new Vector3(extent.xmax, y, extent.zmin);
yPairs.push([start, end]);
}
const yLines = createLines(yPairs);
const annotations = [];
for (const point of startingPointsHorizontal) {
const label = createLabel(
`${point.x.toFixed(2)}`,
point,
Orientation.Horizontal
);
for (let i = 0; i < xPairs.length - 1; i++) {
const [start, _] = xPairs[i];
const label = createLabel(`${start.x.toFixed(0)}m`, start, Orientation.X);
annotations.push(label);
}
for (const point of startingPointsVertical) {
const label = createLabel(
`${point.y.toFixed(2)}`,
point,
Orientation.Vertical
);
for (let i = 0; i < yPairs.length - 1; i++) {
const [start, _] = yPairs[i];
const label = createLabel(`${start.y.toFixed(0)}m`, start, Orientation.Y);
annotations.push(label);
}
const gridHelper = new Group();
gridHelper.add(...xLines, ...yLines);
return { gridHelper, annotations };
}
export function buildHeightGrid(extent: Extent) {
const gridHeight = extent.zmax - extent.zmin;
const divisions = 5;
const offset = gridHeight / divisions;
let z = extent.zmin - offset;
const pointPairs = [];
for (let i = 0; i < divisions + 1; i++) {
z += offset;
const start = new Vector3(extent.xmax, extent.ymin, z);
const end = new Vector3(extent.xmax, extent.ymax, z);
pointPairs.push([start, end]);
}
const lines = createLines(pointPairs);
const annotations = [];
for (const pointPair of pointPairs) {
const start = pointPair[0];
const label = createLabel(`${start.z.toFixed(0)}m`, start, Orientation.Z);
annotations.push(label);
}
const gridHelper = new Group();
gridHelper.add(...lines);
return { heightGridHelper: gridHelper, heightAnnotations: annotations };
}
// Function to create annotation (sprite with text)
function createLabel(
text: string,
position: Vector4,
position: Vector3,
orientation: Orientation
) {
const spriteMaterial = new SpriteMaterial({
map: new CanvasTexture(generateTextCanvas(text, orientation)), // Create text texture
map: new CanvasTexture(generateTextCanvas(text)), // Create text texture
transparent: true,
});
const sprite = new Sprite(spriteMaterial);
// Set position according to axis orientation
if (orientation === Orientation.Horizontal) {
sprite.position.set(position.x + 1000, position.y - 1500, position.z + 500);
if (orientation === Orientation.X) {
sprite.position.set(position.x + 500, position.y - 1500, position.z + 500);
} else if (orientation === Orientation.Y) {
sprite.position.set(position.x - 3000, position.y + 500, position.z + 500);
} else {
sprite.position.set(position.x, position.y - 500, position.z + 500);
sprite.position.set(position.x + 3000, position.y, position.z + 500);
}
sprite.scale.set(5000, 2500, 1); // Scale the sprite to make the text readable
sprite.scale.set(5000, 2500, 1);
return sprite;
}
// Function to generate a text canvas for the annotation
function generateTextCanvas(text: string, orientation: Orientation) {
function generateTextCanvas(text: string) {
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
if (context) {
canvas.width = 800;
canvas.height = 160;
const width = 800;
const height = 200;
canvas.width = width;
canvas.height = height;
// Set the text style
context.font = "45px Arial";
context.font = `${height - 30}px Arial`;
context.fillStyle = "black";
if (orientation === Orientation.Horizontal) {
//context.fillText(text, 300, 160);
context.fillText(text, 100, 90);
} else {
context.fillText(text, 100, 90);
}
context.fillText(text, 0, height - 15);
}
return canvas;
}
function createLines(pointPairs: Vector3[][]) {
const lines = [];
for (const pair of pointPairs) {
const geometry = new BufferGeometry().setFromPoints(pair);
// Line material
const material = new LineBasicMaterial({ color: 0x444444 });
// Create line
const line = new Line(geometry, material);
lines.push(line);
}
return lines;
}