UNPKG

@polygonjs/polygonjs

Version:

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

367 lines (366 loc) 13.9 kB
"use strict"; import { TypedSopNode } from "./_Base"; import { AttribClass, ObjectType, objectTypeFromObject, AttribType, AttribTypeMenuEntries, ATTRIBUTE_TYPES, AttribSize, ATTRIBUTE_CLASSES, ATTRIBUTE_SIZE_RANGE, ATTRIBUTE_CLASSES_WITHOUT_CORE_GROUP, AttribClassMenuEntriesWithoutCoreGroup } from "../../../core/geometry/Constant"; import { InputCloneMode } from "../../poly/InputCloneMode"; import { NodeParamsConfig, ParamConfig } from "../utils/params/ParamsConfig"; import { EntitySelectionHelper } from "./utils/delete/EntitySelectionHelper"; import { ByAttributeHelper, ComparisonOperatorMenuEntries, ComparisonOperator, COMPARISON_OPERATORS } from "./utils/delete/ByAttributeHelper"; import { ByExpressionHelper } from "./utils/delete/ByExpressionHelper"; import { ByBboxHelper } from "./utils/delete/ByBboxHelper"; import { ByObjectTypeHelper, OBJECT_TYPE_MENU_ENTRIES, OBJECT_TYPES } from "./utils/delete/ByObjectTypeHelper"; import { isBooleanTrue } from "../../../core/BooleanValue"; import { ByBoundingObjectHelper } from "./utils/delete/ByBoundingObjectHelper"; import { geometryBuilder } from "../../../core/geometry/modules/three/builders/geometryBuilder"; import { SopType } from "../../poly/registers/nodes/types/Sop"; import { TypeAssert } from "../../poly/Assert"; import { primitivesFromObject } from "../../../core/geometry/entities/primitive/CorePrimitiveUtils"; import { pointsFromObject } from "../../../core/geometry/entities/point/CorePointUtils"; const _points = []; class DeleteSopParamsConfig extends NodeParamsConfig { constructor() { super(...arguments); /** @param defines the class that should be deleted (objects or vertices) */ this.class = ParamConfig.INTEGER(ATTRIBUTE_CLASSES_WITHOUT_CORE_GROUP.indexOf(AttribClass.POINT), { menu: { entries: AttribClassMenuEntriesWithoutCoreGroup } }); /** @param invert the selection created in the parameters below */ this.invert = ParamConfig.BOOLEAN(0); // hide_objects = ParamConfig.BOOLEAN(0, { // visibleIf: {class: ATTRIBUTE_CLASSES.indexOf(AttribClass.OBJECT)}, // }); // byObjectType /** @param deletes objects by object type */ this.byObjectType = ParamConfig.BOOLEAN(0, { visibleIf: { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.OBJECT) } }); /** @param sets which object types should be deleted */ this.objectType = ParamConfig.INTEGER(OBJECT_TYPES.indexOf(ObjectType.MESH), { menu: { entries: OBJECT_TYPE_MENU_ENTRIES }, visibleIf: { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.OBJECT), byObjectType: true }, separatorAfter: true }); // byExpression /** @param deletes objects by an expression */ this.byExpression = ParamConfig.BOOLEAN(0); /** @param sets the expression to select what should be deleted */ this.expression = ParamConfig.BOOLEAN("@ptnum==0", { visibleIf: { byExpression: true }, expression: { forEntities: true }, separatorAfter: true }); // byAttrib /** @param deletes objects by an attribute */ this.byAttrib = ParamConfig.BOOLEAN(0); /** @param sets the type of the attribute for which items should be deleted */ this.attribType = ParamConfig.INTEGER(ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), { menu: { entries: AttribTypeMenuEntries }, visibleIf: { byAttrib: 1 } }); /** @param name of the attribute used */ this.attribName = ParamConfig.STRING("", { visibleIf: { byAttrib: 1 } }); /** @param size of the attribute used */ this.attribSize = ParamConfig.INTEGER(1, { range: ATTRIBUTE_SIZE_RANGE, rangeLocked: [true, true], visibleIf: { byAttrib: 1, attribType: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC) } }); /** @param comparison operator */ this.attribComparisonOperator = ParamConfig.INTEGER(COMPARISON_OPERATORS.indexOf(ComparisonOperator.EQUAL), { menu: { entries: ComparisonOperatorMenuEntries }, visibleIf: { byAttrib: true, attribType: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), attribSize: AttribSize.FLOAT } }); /** @param value of the attribute to compare with (when using float attribute) */ this.attribValue1 = ParamConfig.FLOAT(0, { visibleIf: { byAttrib: 1, attribType: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), attribSize: 1 } }); /** @param value of the attribute to compare with (when using vector2 attribute) */ this.attribValue2 = ParamConfig.VECTOR2([0, 0], { visibleIf: { byAttrib: 1, attribType: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), attribSize: 2 } }); /** @param value of the attribute to compare with (when using vector3 attribute) */ this.attribValue3 = ParamConfig.VECTOR3([0, 0, 0], { visibleIf: { byAttrib: 1, attribType: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), attribSize: 3 } }); /** @param value of the attribute to compare with (when using vector4 attribute) */ this.attribValue4 = ParamConfig.VECTOR4([0, 0, 0, 0], { visibleIf: { byAttrib: 1, attribType: ATTRIBUTE_TYPES.indexOf(AttribType.NUMERIC), attribSize: 4 } }); /** @param value of the attribute to compare with (when using string attribute) */ this.attribString = ParamConfig.STRING("", { visibleIf: { byAttrib: 1, attribType: ATTRIBUTE_TYPES.indexOf(AttribType.STRING) }, separatorAfter: true }); // byBbox /** @param deletes objects that are inside a bounding box */ this.byBbox = ParamConfig.BOOLEAN(0, { visibleIf: [ { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.POINT) }, { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.PRIMITIVE) } ] }); /** @param the bounding box size */ this.bboxSize = ParamConfig.VECTOR3([1, 1, 1], { visibleIf: [ { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.POINT), byBbox: true }, { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.PRIMITIVE), byBbox: true } ] }); /** @param the bounding box center */ this.bboxCenter = ParamConfig.VECTOR3([0, 0, 0], { visibleIf: [ { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.POINT), byBbox: true }, { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.PRIMITIVE), byBbox: true } ], separatorAfter: true }); // byBoundingObject /** @param deletes objects that are inside an object. This uses the object from the 2nd input */ this.byBoundingObject = ParamConfig.BOOLEAN(0, { visibleIf: [ { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.POINT) }, { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.PRIMITIVE) } ] }); // by_visible // by_visible = ParamConfig.BOOLEAN(0, { // visibleIf: {class: ATTRIBUTE_CLASSES.indexOf(AttribClass.OBJECT)}, // }); /** @param keeps points */ this.keepPoints = ParamConfig.BOOLEAN(0, { visibleIf: { class: ATTRIBUTE_CLASSES.indexOf(AttribClass.OBJECT) } }); } } const ParamsConfig = new DeleteSopParamsConfig(); export class DeleteSopNode extends TypedSopNode { constructor() { super(...arguments); this.paramsConfig = ParamsConfig; this._markedForDeletionPerObjectIndex = /* @__PURE__ */ new Map(); this.entitySelectionHelper = new EntitySelectionHelper(this); this.byExpressionHelper = new ByExpressionHelper(this); this.byAttributeHelper = new ByAttributeHelper(this); this.byObjectTypeHelper = new ByObjectTypeHelper(this); this.byBboxHelper = new ByBboxHelper(this); this.byBoundingObjectHelper = new ByBoundingObjectHelper(this); } static type() { return SopType.DELETE; } initializeNode() { this.io.inputs.setCount(1, 2); this.io.inputs.initInputsClonedState(InputCloneMode.FROM_NODE); } async cook(inputCoreGroups) { const coreGroup0 = inputCoreGroups[0]; const coreGroup1 = inputCoreGroups[1]; if (!coreGroup0) { this.cookController.endCook(); return; } const attribClass = ATTRIBUTE_CLASSES_WITHOUT_CORE_GROUP[this.pv.class]; switch (attribClass) { case AttribClass.POINT: return await this._evalForPoints(coreGroup0, coreGroup1); case AttribClass.VERTEX: this.states.error.set(`vertex not supported yet`); case AttribClass.PRIMITIVE: return await this._evalForPrimitives(coreGroup0, coreGroup1); case AttribClass.OBJECT: return await this._evalForObjects(coreGroup0); case AttribClass.CORE_GROUP: this.states.error.set(`core group not supported yet`); return; } TypeAssert.unreachable(attribClass); } setAttribClass(attribClass) { this.p.class.set(ATTRIBUTE_CLASSES.indexOf(attribClass)); } attribClass() { return ATTRIBUTE_CLASSES[this.pv.class]; } setAttribType(attribType) { this.p.attribType.set(ATTRIBUTE_TYPES.indexOf(attribType)); } attribType() { return ATTRIBUTE_TYPES[this.pv.attribType]; } async _evalForPoints(coreGroup, coreGroup2) { const objects = coreGroup.allObjects(); const newObjects = []; for (const object of objects) { const entities = []; pointsFromObject(object, entities); this.entitySelectionHelper.init(entities); const initEntitiesCount = entities.length; if (isBooleanTrue(this.pv.byExpression)) { await this.byExpressionHelper.evalForEntities(entities); } if (isBooleanTrue(this.pv.byAttrib) && this.pv.attribName != "") { this.byAttributeHelper.evalForEntities(entities); } if (isBooleanTrue(this.pv.byBbox)) { this.byBboxHelper.evalForEntities(entities); } if (isBooleanTrue(this.pv.byBoundingObject)) { this.byBoundingObjectHelper.evalForEntities(entities, coreGroup2); } const keptEntities = this.entitySelectionHelper.entitiesToKeep(); if (keptEntities.length == initEntitiesCount) { newObjects.push(object); } else { if (keptEntities.length > 0) { const objectType = objectTypeFromObject(object); if (objectType) { const builder = geometryBuilder(objectType); if (builder) { const newGeo = builder.fromPoints(object, keptEntities); if (newGeo) { object.geometry = newGeo; newObjects.push(object); } } else { console.warn("no builder found for", objectType); } } else { console.warn("no object type found for", object); } } } } this.setObjects(newObjects); } async _evalForPrimitives(coreGroup, coreGroup2) { const objects = coreGroup.allObjects(); const newObjects = []; for (const object of objects) { const entities = []; primitivesFromObject(object, entities); this.entitySelectionHelper.init(entities); const initEntitiesCount = entities.length; if (isBooleanTrue(this.pv.byExpression)) { await this.byExpressionHelper.evalForEntities(entities); } if (isBooleanTrue(this.pv.byAttrib) && this.pv.attribName != "") { this.byAttributeHelper.evalForEntities(entities); } if (isBooleanTrue(this.pv.byBbox)) { this.byBboxHelper.evalForEntities(entities); } if (isBooleanTrue(this.pv.byBoundingObject)) { this.byBoundingObjectHelper.evalForEntities(entities, coreGroup2); } const keptEntities = this.entitySelectionHelper.entitiesToKeep(); if (keptEntities.length == initEntitiesCount) { newObjects.push(object); } else { if (keptEntities.length > 0) { const builder = keptEntities[0].builder(); if (builder) { const newObject = builder(object, keptEntities); if (newObject) { newObjects.push(newObject); } } else { const attribClass = ATTRIBUTE_CLASSES_WITHOUT_CORE_GROUP[this.pv.class]; console.warn(`no ${attribClass} builder for object`, object); } } } } this.setObjects(newObjects); } async _evalForObjects(coreGroup) { const coreObjects = coreGroup.allCoreObjects(); this.entitySelectionHelper.init(coreObjects); this._markedForDeletionPerObjectIndex = /* @__PURE__ */ new Map(); for (let coreObject of coreObjects) { this._markedForDeletionPerObjectIndex.set(coreObject.index(), false); } if (isBooleanTrue(this.pv.byExpression)) { await this.byExpressionHelper.evalForEntities(coreObjects); } if (isBooleanTrue(this.pv.byObjectType)) { this.byObjectTypeHelper.evalForObjects(coreObjects); } if (isBooleanTrue(this.pv.byAttrib) && this.pv.attribName != "") { this.byAttributeHelper.evalForEntities(coreObjects); } const coreObjectsToKeep = this.entitySelectionHelper.entitiesToKeep(); const objectsToKeep = coreObjectsToKeep.map((co) => co.object()); if (isBooleanTrue(this.pv.keepPoints)) { const coreObjectsToDelete = this.entitySelectionHelper.entitiesToDelete(); for (let coreObjectToDelete of coreObjectsToDelete) { const pointObject = this._pointObject(coreObjectToDelete.object()); if (pointObject) { objectsToKeep.push(pointObject); } } } this.setObjects(objectsToKeep); } _pointObject(object) { pointsFromObject(object, _points); const builder = geometryBuilder(ObjectType.POINTS); if (builder) { const geometry = builder.fromPoints(object, _points); if (geometry) return this.createObject(geometry, ObjectType.POINTS); } } }