UNPKG

@jscad/modeling

Version:

Constructive Solid Geometry (CSG) Library for JSCAD

63 lines (55 loc) 1.85 kB
const poly3 = require('../poly3') const isA = require('./isA') /** * Determine if the given object is a valid 3D geometry. * Checks for valid data structure, convex polygon faces, and manifold edges. * * **If the geometry is not valid, an exception will be thrown with details of the geometry error.** * * @param {Object} object - the object to interrogate * @throws {Error} error if the geometry is not valid * @alias module:modeling/geometries/geom3.validate */ const validate = (object) => { if (!isA(object)) { throw new Error('invalid geom3 structure') } // check polygons object.polygons.forEach(poly3.validate) validateManifold(object) // check transforms if (!object.transforms.every(Number.isFinite)) { throw new Error(`geom3 invalid transforms ${object.transforms}`) } // TODO: check for self-intersecting } /* * Check manifold edge condition: Every edge is in exactly 2 faces */ const validateManifold = (object) => { // count of each edge const edgeCount = new Map() object.polygons.forEach(({ vertices }) => { vertices.forEach((v, i) => { const v1 = `${v}` const v2 = `${vertices[(i + 1) % vertices.length]}` // sort for undirected edge const edge = `${v1}/${v2}` const count = edgeCount.has(edge) ? edgeCount.get(edge) : 0 edgeCount.set(edge, count + 1) }) }) // check that edges are always matched const nonManifold = [] edgeCount.forEach((count, edge) => { const complementEdge = edge.split('/').reverse().join('/') const complementCount = edgeCount.get(complementEdge) if (count !== complementCount) { nonManifold.push(edge.replace('/', ' -> ')) } }) if (nonManifold.length > 0) { throw new Error(`non-manifold edges ${nonManifold.length}\n${nonManifold.join('\n')}`) } } module.exports = validate