From bcc64baef8a86f2e10b3bd12664596d140c1e469 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Tue, 4 Oct 2022 20:10:50 -0400 Subject: [PATCH] move legacy 3d path generator to geo.paths --- src/geo/paths.js | 96 ++++++++++++++++++++ src/kiri/layers.js | 213 +++++++++++++-------------------------------- web/kiri/index.css | 8 +- 3 files changed, 162 insertions(+), 155 deletions(-) diff --git a/src/geo/paths.js b/src/geo/paths.js index fa0c7129..14f02588 100644 --- a/src/geo/paths.js +++ b/src/geo/paths.js @@ -356,9 +356,105 @@ function pathTo3D(path, height, z) { return out; } +// produces indexed geometry which isn't ideal for rendering because +// the default threejs generated vertex normals aren't accurate +function shapeToPath(shape, points, closed) { + closed = closed !== undefined ? closed : true; + + const profileGeometry = new THREE.ShapeGeometry(shape); + profileGeometry.rotateX(Math.PI * .5); + + const profile = profileGeometry.attributes.position; + const faces = new Float32Array(profile.count * points.length * 3); + + for (let i = 0; i < points.length; i++) { + const v1 = new THREE.Vector2().subVectors(points[i - 1 < 0 ? points.length - 1 : i - 1], points[i]); + const v2 = new THREE.Vector2().subVectors(points[i + 1 == points.length ? 0 : i + 1], points[i]); + const angle = v2.angle() - v1.angle(); + const halfAngle = angle * .5; + let hA = halfAngle; + let tA = v2.angle() + Math.PI * .5; + + if (!closed){ + if (i == 0 || i == points.length - 1) {hA = Math.PI * .5;} + if (i == points.length - 1) {tA = v1.angle() - Math.PI * .5;} + } + + const shift = Math.tan(hA - Math.PI * .5); + const shiftMatrix = new THREE.Matrix4().set( + 1, 0, 0, 0, + -shift, 1, 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); + + const tempAngle = tA; + const rotationMatrix = new THREE.Matrix4().set( + Math.cos(tempAngle), -Math.sin(tempAngle), 0, 0, + Math.sin(tempAngle), Math.cos(tempAngle), 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1 + ); + + const translationMatrix = new THREE.Matrix4().set( + 1, 0, 0, points[i].x, + 0, 1, 0, points[i].y, + 0, 0, 1, 0, + 0, 0, 0, 1, + ); + + const cloneProfile = profile.clone(); + cloneProfile.applyMatrix4(shiftMatrix); + cloneProfile.applyMatrix4(rotationMatrix); + cloneProfile.applyMatrix4(translationMatrix); + + faces.set(cloneProfile.array, cloneProfile.count * i * 3); + } + + const index = []; + const lastCorner = closed == false ? points.length - 1: points.length; + + for (let i = 0; i < lastCorner; i++) { + for (let j = 0; j < profile.count; j++) { + const currCorner = i; + const nextCorner = i + 1 == points.length ? 0 : i + 1; + const currPoint = j; + const nextPoint = j + 1 == profile.count ? 0 : j + 1; + + const a = nextPoint + profile.count * currCorner; + const b = currPoint + profile.count * currCorner; + const c = currPoint + profile.count * nextCorner; + const d = nextPoint + profile.count * nextCorner; + + index.push(a, b, d); + index.push(b, c, d); + } + } + + if (!closed) { + // cheating because we know the profile length is 4 (for now) + const p1 = 0 + profile.count * 0; + const p2 = 1 + profile.count * 0; + const p3 = 2 + profile.count * 0; + const p4 = 3 + profile.count * 0; + index.push(p1, p2, p3); + index.push(p1, p3, p4); + const lc = lastCorner; + const p5 = 0 + profile.count * lc; + const p6 = 1 + profile.count * lc; + const p7 = 2 + profile.count * lc; + const p8 = 3 + profile.count * lc; + index.push(p7, p6, p5); + index.push(p8, p7, p5); + } + + return {index, faces}; +} + base.paths = { poly2polyEmit, tip2tipEmit, + shapeToPath, pointsToPath, pathTo3D }; diff --git a/src/kiri/layers.js b/src/kiri/layers.js index 3c87e4f2..54a16c97 100644 --- a/src/kiri/layers.js +++ b/src/kiri/layers.js @@ -9,6 +9,7 @@ */ // dep: geo.base +// dep: geo.paths // dep: geo.polygon // dep: geo.polygons gapp.register("kiri.layers", [], (root, exports) => { @@ -219,7 +220,7 @@ class Layers { continue; } const z = opts.z || poly.getZ(); - const faces = poly.toPath3D(offset * 1, height, 0); + const faces = poly.toPath3D(offset, height, 0); const cur = this.current; const one = cur.paths[0]; if (one) { @@ -251,65 +252,65 @@ class Layers { } this.stats.contour++; } - return this; - } - - const profiles = this.profiles; - const prokey = `${offset}x${height}`; - if (!profiles[prokey]) { - const profile = new THREE.Shape(); - profile.moveTo(-offset, -height); - profile.lineTo(-offset, height); - profile.lineTo( offset, height); - profile.lineTo( offset, -height); - profiles[prokey] = profile; - } - const profile = profiles[prokey].clone(); - - polys.forEach(poly => { - const contour = []; - poly = poly.debur(0.05); - if (!poly) return; - poly = poly.miter(); - poly.points.forEach(p => { - contour.push(new THREE.Vector2(p.x, p.y)); - }); - const {index, faces} = ProfiledContourGeometry(profile, contour, poly.isClosed()); - const cur = this.current; - const one = cur.paths[0]; - if (one) { - // merge all contour geometry for massive speed gain - // todo: recode to concat all geometries at once, and not incrementally - const add = one.faces.length / 3; - for (let i=0; i { + const contour = []; + poly = poly.debur(0.05); + if (!poly) return; + poly = poly.miter(); + poly.points.forEach(p => { + contour.push(new THREE.Vector2(p.x, p.y)); + }); + const {index, faces} = base.paths.shapeToPath(profile, contour, poly.isClosed()); + const cur = this.current; + const one = cur.paths[0]; + if (one) { + // merge all contour geometry for massive speed gain + // todo: recode to concat all geometries at once, and not incrementally + const add = one.faces.length / 3; + for (let i=0; i