@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
367 lines (366 loc) • 13.9 kB
JavaScript
"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);
}
}
}