polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
111 lines (98 loc) • 3.38 kB
text/typescript
/**
* Splits a geometry into multiple objects
*
* @remarks
* This is useful to isolate parts of a geometry that matches a specific attribute.
*
*/
import {TypedSopNode} from './_Base';
import {
AttribSize,
ATTRIBUTE_TYPES,
AttribType,
AttribTypeMenuEntries,
objectTypeFromConstructor,
} from '../../../core/geometry/Constant';
import {CoreGroup, Object3DWithGeometry} from '../../../core/geometry/Group';
import {Object3D} from 'three/src/core/Object3D';
import {NodeParamsConfig, ParamConfig} from '../utils/params/ParamsConfig';
import {CoreObject} from '../../../core/geometry/Object';
import {CorePoint} from '../../../core/geometry/Point';
import {CoreGeometry} from '../../../core/geometry/Geometry';
import {MapUtils} from '../../../core/MapUtils';
class DeleteSopParamsConfig extends NodeParamsConfig {
/** @param type of attribute to use */
attribType = ParamConfig.INTEGER(ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), {
menu: {
entries: AttribTypeMenuEntries,
},
});
/** @param name of the attribute */
attribName = ParamConfig.STRING('');
}
const ParamsConfig = new DeleteSopParamsConfig();
export class SplitSopNode extends TypedSopNode<DeleteSopParamsConfig> {
params_config = ParamsConfig;
static type() {
return 'split';
}
static displayedInputNames(): string[] {
return ['geometry to split in multiple objects'];
}
initializeNode() {
this.io.inputs.setCount(1);
}
private _new_objects: Object3D[] = [];
async cook(input_contents: CoreGroup[]) {
const core_group = input_contents[0];
this._new_objects = [];
if (this.pv.attribName != '') {
this._split_core_group(core_group);
}
this.setObjects(this._new_objects);
}
async _split_core_group(core_group: CoreGroup) {
const core_objects = core_group.coreObjects();
for (let core_object of core_objects) {
this._split_core_object(core_object);
}
}
private _split_core_object(core_object: CoreObject) {
let core_geometry = core_object.coreGeometry();
let attribName: string = this.pv.attribName;
let points_by_value: Map<string | number, CorePoint[]> = new Map();
if (core_geometry) {
const object = core_object.object() as Object3DWithGeometry;
const points = core_geometry.pointsFromGeometry();
const first_point = points[0];
if (first_point) {
const attrib_size = first_point.attribSize(attribName);
if (!(attrib_size == AttribSize.FLOAT || first_point.isAttribIndexed(attribName))) {
this.states.error.set(`attrib '${attribName}' must be a float or a string`);
return;
}
let val: string | number;
if (first_point.isAttribIndexed(attribName)) {
for (let point of points) {
val = point.indexedAttribValue(attribName);
MapUtils.push_on_array_at_entry(points_by_value, val, point);
}
} else {
for (let point of points) {
val = point.attribValue(attribName) as number;
MapUtils.push_on_array_at_entry(points_by_value, val, point);
}
}
}
const object_type = objectTypeFromConstructor(object.constructor);
points_by_value.forEach((points, value) => {
const new_geometry = CoreGeometry.geometryFromPoints(points, object_type);
if (new_geometry) {
const object = this.create_object(new_geometry, object_type);
CoreObject.addAttribute(object, attribName, value);
this._new_objects.push(object);
}
});
}
}
}