@jscad/modeling
Version:
Constructive Solid Geometry (CSG) Library for JSCAD
79 lines (63 loc) • 2.42 kB
JavaScript
const { EPS } = require('../../maths/constants')
const vec3 = require('../../maths/vec3')
const poly3 = require('../../geometries/poly3')
const slice = require('./slice')
// https://en.wikipedia.org/wiki/Greatest_common_divisor#Using_Euclid's_algorithm
const gcd = (a, b) => {
if (a === b) { return a }
if (a < b) { return gcd(b, a) }
if (b === 1) { return 1 }
if (b === 0) { return a }
return gcd(b, a % b)
}
const lcm = (a, b) => (a * b) / gcd(a, b)
// Return a set of edges that encloses the same area by splitting
// the given edges to have newlength total edges.
const repartitionEdges = (newlength, edges) => {
// NOTE: This implementation splits each edge evenly.
const multiple = newlength / edges.length
if (multiple === 1) {
return edges
}
const divisor = vec3.fromValues(multiple, multiple, multiple)
const newEdges = []
edges.forEach((edge) => {
const increment = vec3.subtract(vec3.create(), edge[1], edge[0])
vec3.divide(increment, increment, divisor)
// repartition the edge
let prev = edge[0]
for (let i = 1; i <= multiple; ++i) {
const next = vec3.add(vec3.create(), prev, increment)
newEdges.push([prev, next])
prev = next
}
})
return newEdges
}
const EPSAREA = (EPS * EPS / 2) * Math.sin(Math.PI / 3)
/*
* Extrude (build) walls between the given slices.
* Each wall consists of two triangles, which may be invalid if slices are overlapping.
*/
const extrudeWalls = (slice0, slice1) => {
let edges0 = slice.toEdges(slice0)
let edges1 = slice.toEdges(slice1)
if (edges0.length !== edges1.length) {
// different shapes, so adjust one or both to the same number of edges
const newlength = lcm(edges0.length, edges1.length)
if (newlength !== edges0.length) edges0 = repartitionEdges(newlength, edges0)
if (newlength !== edges1.length) edges1 = repartitionEdges(newlength, edges1)
}
const walls = []
edges0.forEach((edge0, i) => {
const edge1 = edges1[i]
const poly0 = poly3.create([edge0[0], edge0[1], edge1[1]])
const poly0area = poly3.measureArea(poly0)
if (Number.isFinite(poly0area) && poly0area > EPSAREA) walls.push(poly0)
const poly1 = poly3.create([edge0[0], edge1[1], edge1[0]])
const poly1area = poly3.measureArea(poly1)
if (Number.isFinite(poly1area) && poly1area > EPSAREA) walls.push(poly1)
})
return walls
}
module.exports = extrudeWalls