UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

133 lines (125 loc) 4.42 kB
import {Object3D, Material, Matrix4, Box3, Sphere, Vector3} from 'three'; import {CsgGeometryType, CsgTypeMap, CSGTesselationParams} from './CsgCommon'; import {csgGeometryTypeFromGeometry} from './CsgCoreType'; import {ObjectContent, CoreObjectType, ObjectGeometryMap, objectContentCopyProperties} from '../../ObjectContent'; import {path2ToObject3D} from './toObject3D/CsgPath2ToObject3D'; import {geom2ToObject3D} from './toObject3D/CsgGeom2ToObject3D'; import {geom3ToObject3D} from './toObject3D/CsgGeom3ToObject3D'; import {matrix4ToMat4} from './math/CsgMat4'; import {csgBoundingBoxPath2, csgBoundingBoxGeom2, csgBoundingBoxGeom3} from './math/CsgBoundingBox'; import {TypeAssert} from '../../../../engine/poly/Assert'; import {isArray} from '../../../Type'; const _box = new Box3(); const _size = new Vector3(); export class CsgObject<T extends CsgGeometryType> implements ObjectContent<CoreObjectType.CSG> { public visible = true; get geometry() { return this._geometry as ObjectGeometryMap[CoreObjectType.CSG]; } get type() { return this._type; } userData = {}; name = ''; castShadow = true; receiveShadow = true; renderOrder = 0; frustumCulled = true; matrixAutoUpdate = false; material: Material | undefined; children: ObjectContent<CoreObjectType.CSG>[] = []; parent: ObjectContent<CoreObjectType.CSG> | null = null; private _type: T; constructor(private _geometry: CsgTypeMap[T]) { this._type = csgGeometryTypeFromGeometry(this._geometry); this._validate(); } setGeometry<TE extends CsgGeometryType>(geometry: CsgTypeMap[TE]) { this._geometry = geometry as CsgTypeMap[T]; this._validate(); } private _validate() { const type = csgGeometryTypeFromGeometry(this._geometry) as T; if (type) { this._type = type; } else { console.error('no type for geometry', this._geometry); } } csgGeometry() { return this.geometry! as CsgTypeMap[T]; } dispose() {} applyMatrix4(matrix: Matrix4) { matrix4ToMat4(matrix, this.csgGeometry().transforms); } add(...object: ObjectContent<CoreObjectType>[]) {} remove(...object: ObjectContent<CoreObjectType>[]) {} dispatchEvent(event: {type: string}) {} traverse(callback: (object: CsgObject<T>) => any) { callback(this); } clone(): CsgObject<T> { // const geometry = cloneCsgGeometry(this.type, this.csgGeometry()); const geometry = JSON.parse(JSON.stringify(this.csgGeometry())); const clone = new CsgObject(geometry) as CsgObject<T>; objectContentCopyProperties(this, clone); return clone; } toObject3D(tesselationParams: CSGTesselationParams): Object3D | Object3D[] | undefined { const object = CsgObject.toObject3D(this, this.type, tesselationParams); if (object) { if (isArray(object)) { for (const element of object) { objectContentCopyProperties(this, element); } } else { objectContentCopyProperties(this, object); } } return object; } static toObject3D<T extends CsgGeometryType>( csgObject: CsgObject<T>, type: T, tesselationParams: CSGTesselationParams ): Object3D | Object3D[] | undefined { switch (type) { case CsgGeometryType.PATH2: { return path2ToObject3D(csgObject.csgGeometry() as CsgTypeMap[CsgGeometryType.PATH2], tesselationParams); } case CsgGeometryType.GEOM2: { return geom2ToObject3D(csgObject.csgGeometry() as CsgTypeMap[CsgGeometryType.GEOM2], tesselationParams); } case CsgGeometryType.GEOM3: { return geom3ToObject3D(csgObject.csgGeometry() as CsgTypeMap[CsgGeometryType.GEOM3], tesselationParams); } } TypeAssert.unreachable(type); } boundingBox(target: Box3): void { // using the measurement functions from jscad // modifies the geometry matrix, // which shouldn't happen const type = this.type; switch (type) { case CsgGeometryType.PATH2: { return csgBoundingBoxPath2(this.csgGeometry() as CsgTypeMap[CsgGeometryType.PATH2], target); } case CsgGeometryType.GEOM2: { return csgBoundingBoxGeom2(this.csgGeometry() as CsgTypeMap[CsgGeometryType.GEOM2], target); } case CsgGeometryType.GEOM3: { return csgBoundingBoxGeom3(this.csgGeometry() as CsgTypeMap[CsgGeometryType.GEOM3], target); } } TypeAssert.unreachable(type); } boundingSphere(target: Sphere): void { this.boundingBox(_box); _box.getSize(_size); _box.getSize(target.center); const diameter = Math.max(_size.x, _size.y, _size.z); target.radius = diameter * 0.5; } }