import {
Vector2,
Vector3,
Box3,
Mesh,
PerspectiveCamera,
PointsMaterial,
MeshBasicMaterial,
Scene,
Color,
DoubleSide,
WebGLRenderer,
BufferGeometry,
Points,
Float32BufferAttribute
} from "https://esm.sh/three";
import { OrbitControls } from "https://esm.sh/three/addons";
import earcut from "https://esm.sh/earcut";
const skeletonPostProcessingResult = {
polygons: [
{
vertices: [],
edgeStart: {
x: 259505.3125,
y: 6253223.5
},
edgeEnd: {
x: 259521.140625,
y: 6253168
}
},
{
vertices: [
{
x: 259606.34375,
y: 6253192.5
},
{
x: 259598.453125,
y: 6253220.25
},
{
x: 259513.2265625,
y: 6253195.75
},
{
x: 259521.140625,
y: 6253168
}
],
edgeStart: {
x: 259521.140625,
y: 6253168
},
edgeEnd: {
x: 259606.34375,
y: 6253192.5
}
},
{
vertices: [],
edgeStart: {
x: 259606.34375,
y: 6253192.5
},
edgeEnd: {
x: 259590.5625,
y: 6253248
}
},
{
vertices: [
{
x: 259505.3125,
y: 6253223.5
},
{
x: 259513.2265625,
y: 6253195.75
},
{
x: 259598.453125,
y: 6253220.25
},
{
x: 259590.5625,
y: 6253248
}
],
edgeStart: {
x: 259590.5625,
y: 6253248
},
edgeEnd: {
x: 259505.3125,
y: 6253223.5
}
}
]
};
const skeletonBox = {
maxX: 259606.34375,
maxY: 6253248,
minX: 259505.3125,
minY: 6253168 - 20
};
const minHeight = 31;
const roofMaxHeight = 58;
const roofHeight = 10;
const roofMinHeight = 48;
const Hmax = 28.85;
const _signedDistanceToLine = function (point, line) {
const lineVector = new Vector2().subVectors(line[1], line[0]);
const pointVector = new Vector2().subVectors(point, line[0]);
const cross = lineVector.x * pointVector.y - lineVector.y * pointVector.x;
const lineLength = lineVector.length();
return cross / lineLength;
};
function createWallTriangles(positions: Array<Vector3>) {
const postionsResult = positions.slice();
for (let index = 0; index < positions.length; index++) {
const A = positions[index];
const B = positions[index + 1] ? positions[index + 1] : positions[0];
// Triangle ABA'
postionsResult.push(A); // A
postionsResult.push(B); // B
postionsResult.push(new Vector3(A.x, A.y, minHeight)); // A'
// Triangle A',B,B'
postionsResult.push(new Vector3(A.x, A.y, minHeight)); // A'
postionsResult.push(B); // B
postionsResult.push(new Vector3(B.x, B.y, minHeight)); // B'
}
return postionsResult;
}
const vertices: Vector3[] = [];
for (const polygon of skeletonPostProcessingResult.polygons) {
const edgeLine = [polygon.edgeStart, polygon.edgeEnd];
// les polygones avec uniquement 2 sommets
if (polygon.vertices.length == 0) {
const middle = new Vector2()
.addVectors(polygon.edgeStart, polygon.edgeEnd)
.multiplyScalar(0.5);
const startDst = _signedDistanceToLine(polygon.edgeStart, edgeLine);
const endDst = _signedDistanceToLine(polygon.edgeEnd, edgeLine);
// A
vertices.push(
new Vector3(
polygon.edgeStart.x,
polygon.edgeStart.y,
roofMinHeight + (roofHeight * startDst) / Hmax
)
);
// B
vertices.push(new Vector3(middle.x, middle.y, roofMaxHeight));
// C
vertices.push(
new Vector3(
polygon.edgeEnd.x,
polygon.edgeEnd.y,
roofMinHeight + (roofHeight * endDst) / Hmax
)
);
}
}
const wallTrianglesVertices = createWallTriangles(vertices);
console.log(vertices, wallTrianglesVertices);
////// THREE.JS SCENE
let camera, scene, renderer, controls;
//const material = new PointsMaterial({ color: 0x888888, size: 10 });
const material = new MeshBasicMaterial({
color: "#ffb6e9",
side: DoubleSide
});
const wallGeometry = new BufferGeometry();
wallGeometry.setFromPoints(wallTrianglesVertices);
const wallMesh = new Mesh(wallGeometry, material);
const center = new Vector3(
skeletonBox.minX + (skeletonBox.maxX - skeletonBox.minX) / 2,
skeletonBox.minY + (skeletonBox.maxY - skeletonBox.minY) / 2,
minHeight + roofHeight / 2
);
function init() {
renderer = new WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
scene = new Scene();
scene.background = new Color("white");
camera = new PerspectiveCamera(
70,
window.innerWidth / window.innerHeight,
1,
10000
);
// Our up axes here is the Z
camera.up.set(0, 0, 1);
controls = new OrbitControls(camera, renderer.domElement);
camera.position.set(skeletonBox.maxX, skeletonBox.maxY, roofMaxHeight * 2);
camera.lookAt(center);
controls.target.copy(center);
controls.update();
scene.add(wallMesh);
window.addEventListener("resize", onWindowResize);
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
controls.update();
renderer.render(scene, camera);
}
init();
animate();
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.