@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
302 lines (301 loc) • 10.2 kB
JavaScript
;
import { CoreMath } from "./../../../core/math/_Module";
import { TypeAssert } from "./../../poly/Assert";
import { AttribClass } from "./../../../core/geometry/Constant";
import { BaseSopOperation } from "./_Base";
import { InputCloneMode } from "../../../engine/poly/InputCloneMode";
import { Vector3 } from "three";
import { pushOnArrayAtEntry } from "../../../core/MapUtils";
import { isBooleanTrue } from "../../../core/Type";
import { setToArray } from "../../../core/SetUtils";
import { isNumber } from "../../../core/Type";
import { pointsFromObject } from "../../../core/geometry/entities/point/CorePointUtils";
import { corePointClassFactory } from "../../../core/geometry/CoreObjectFactory";
const tmpPos = new Vector3();
export var SortMode = /* @__PURE__ */ ((SortMode2) => {
SortMode2["RANDOM"] = "random";
SortMode2["AXIS"] = "axis";
SortMode2["ATTRIBUTE"] = "attribute";
return SortMode2;
})(SortMode || {});
export const SORT_MODES = ["axis" /* AXIS */, "random" /* RANDOM */, "attribute" /* ATTRIBUTE */];
export const SORT_TARGET_TYPES = [AttribClass.POINT, AttribClass.OBJECT];
export var Axis = /* @__PURE__ */ ((Axis2) => {
Axis2["X"] = "x";
Axis2["Y"] = "y";
Axis2["Z"] = "z";
return Axis2;
})(Axis || {});
export const AXISES = ["x" /* X */, "y" /* Y */, "z" /* Z */];
const _points = [];
export class SortSopOperation extends BaseSopOperation {
constructor() {
super(...arguments);
this._pointPos = new Vector3();
this._positions = [];
this._indicesByPos = /* @__PURE__ */ new Map();
this._indexDest = /* @__PURE__ */ new Map();
this._debugActive = false;
}
static type() {
return "sort";
}
cook(inputCoreGroups, params) {
const coreGroup = inputCoreGroups[0];
this._sort(coreGroup, params);
return coreGroup;
}
_sort(coreGroup, params) {
const targetType = SORT_TARGET_TYPES[params.targetType];
switch (targetType) {
case AttribClass.POINT:
return this._sortPoints(coreGroup, params);
case AttribClass.OBJECT:
return this._sortObjects(coreGroup, params);
}
}
_sortObjects(coreGroup, params) {
const sortMode = SORT_MODES[params.mode];
switch (sortMode) {
case "axis" /* AXIS */:
return this._sortObjectsByAxis(coreGroup, params);
case "random" /* RANDOM */:
return this._sortObjectsByRandom(coreGroup, params);
case "attribute" /* ATTRIBUTE */:
return this._sortObjectsByAttribute(coreGroup, params);
}
TypeAssert.unreachable(sortMode);
}
_sortObjectsByAxis(coreGroup, params) {
const coreObjects = coreGroup.allCoreObjects();
const objectsByPos = /* @__PURE__ */ new Map();
const positions = /* @__PURE__ */ new Set();
const axis = AXISES[params.axis];
let axisValue = 0;
for (let coreObject of coreObjects) {
coreObject.position(tmpPos);
switch (axis) {
case "x" /* X */: {
axisValue = tmpPos.x;
break;
}
case "y" /* Y */: {
axisValue = tmpPos.y;
break;
}
case "z" /* Z */: {
axisValue = tmpPos.z;
break;
}
}
positions.add(axisValue);
pushOnArrayAtEntry(objectsByPos, axisValue, coreObject);
}
let sortedPositions = setToArray(positions, []).sort((a, b) => a - b);
if (isBooleanTrue(params.invert)) {
sortedPositions.reverse();
}
const sortedObjects = [];
for (let position of sortedPositions) {
const coreObjectsForPosition = objectsByPos.get(position);
if (coreObjectsForPosition) {
for (let coreObjectForPosition of coreObjectsForPosition) {
const object = coreObjectForPosition.object();
if (object) {
sortedObjects.push(object);
}
}
}
}
coreGroup.setAllObjects(sortedObjects);
}
_sortObjectsByRandom(coreGroup, params) {
const coreObjects = coreGroup.allCoreObjects();
const objectsByPos = /* @__PURE__ */ new Map();
const positions = [];
let sortValue = 0;
let i = 0;
for (let coreObject of coreObjects) {
sortValue = CoreMath.randFloat(params.seed, i);
positions[i] = sortValue;
pushOnArrayAtEntry(objectsByPos, sortValue, coreObject);
i++;
}
let sortedPositions = positions.sort((a, b) => a - b);
if (params.invert) {
sortedPositions.reverse();
}
const sortedObjects = [];
for (let position of sortedPositions) {
const coreObjectsForPosition = objectsByPos.get(position);
if (coreObjectsForPosition) {
for (let coreObjectForPosition of coreObjectsForPosition) {
const object = coreObjectForPosition.object();
if (object) {
sortedObjects.push(object);
}
}
}
}
coreGroup.setAllObjects(sortedObjects);
}
_sortObjectsByAttribute(coreGroup, params) {
const coreObjects = coreGroup.allCoreObjects();
const objectsByAttribValue = /* @__PURE__ */ new Map();
const attribValues = [];
let i = 0;
for (let coreObject of coreObjects) {
const attribValue = coreObject.attribValue(params.attribute);
const sortValue = isNumber(attribValue) ? attribValue : 0;
attribValues[i] = sortValue;
pushOnArrayAtEntry(objectsByAttribValue, sortValue, coreObject);
i++;
}
let sortedValues = attribValues.sort((a, b) => a - b);
if (params.invert) {
sortedValues.reverse();
}
const sortedObjects = [];
for (let sortedValue of sortedValues) {
const coreObjectsForPosition = objectsByAttribValue.get(sortedValue);
if (coreObjectsForPosition) {
for (let coreObjectForPosition of coreObjectsForPosition) {
const object = coreObjectForPosition.object();
if (object) {
sortedObjects.push(object);
}
}
}
}
coreGroup.setAllObjects(sortedObjects);
}
_sortPoints(coreGroup, params) {
const sortMode = SORT_MODES[params.mode];
switch (sortMode) {
case "axis" /* AXIS */:
return this._sortPointsByAxis(coreGroup, params);
case "random" /* RANDOM */:
return this._sortPointsByRandom(coreGroup, params);
case "attribute" /* ATTRIBUTE */:
return this._sortPointsByAttribute(coreGroup, params);
}
TypeAssert.unreachable(sortMode);
}
_sortPointsByAxis(coreGroup, params) {
const objects = coreGroup.threejsObjectsWithGeo();
for (let object of objects) {
this._sortPointsForObject(object, params);
}
}
_sortPointsByRandom(coreGroup, params) {
var _a;
(_a = this.states) == null ? void 0 : _a.error.set("sorting points in random mode is not yet implemented");
}
_sortPointsByAttribute(coreGroup, params) {
var _a;
(_a = this.states) == null ? void 0 : _a.error.set("sorting points by attribute is not yet implemented");
}
_debug(a) {
if (!this._debugActive) {
return;
}
}
_sortPointsForObject(object, params) {
pointsFromObject(object, _points);
const oldIndexAttribute = object.geometry.getIndex();
if (!oldIndexAttribute) {
console.warn("geometry cannot be sorted since it has no index");
return;
}
const oldIndices = oldIndexAttribute.array;
this._positions = new Array(_points.length);
this._indicesByPos.clear();
this._indexDest.clear();
const axis = AXISES[params.axis];
let axisValue = 0;
let i = 0;
for (let point of _points) {
point.position(this._pointPos);
switch (axis) {
case "x" /* X */: {
axisValue = this._pointPos.x;
break;
}
case "y" /* Y */: {
axisValue = this._pointPos.y;
break;
}
case "z" /* Z */: {
axisValue = this._pointPos.z;
break;
}
}
this._positions[i] = axisValue;
pushOnArrayAtEntry(this._indicesByPos, axisValue, point.index());
i++;
}
let sortedPositions = this._positions.sort((a, b) => a - b);
if (params.invert) {
sortedPositions.reverse();
}
const newIndices = new Array(_points.length);
i = 0;
for (let position of sortedPositions) {
const indices = this._indicesByPos.get(position);
if (indices) {
this._indicesByPos.delete(position);
for (let index of indices) {
newIndices[i] = index;
this._indexDest.set(index, i);
i++;
}
}
}
const newIndexAttrib = new Array(oldIndices.length);
for (let i2 = 0; i2 < oldIndices.length; i2++) {
const oldIndex = oldIndices[i2];
const newI = this._indexDest.get(oldIndex);
newIndexAttrib[i2] = newI;
}
object.geometry.setIndex(newIndexAttrib);
const corePointClass = corePointClassFactory(object);
const attributeNames = corePointClass.attributeNames(object);
for (let attributeName of attributeNames) {
if (attributeName == "id") {
this._debugActive = true;
}
const attribute = object.geometry.getAttribute(attributeName);
this._updateAttribute(attribute, newIndices);
this._debugActive = false;
}
}
_updateAttribute(attribute, newIndices) {
const clonedAttribute = attribute.clone();
const srcArray = attribute.array;
const clonedArray = clonedAttribute.array;
const itemSize = clonedAttribute.itemSize;
this._debug(newIndices);
for (let newIndex of newIndices) {
const oldIndex = this._indexDest.get(newIndex);
this._debug(`${newIndex} -> ${oldIndex}`);
if (oldIndex != null) {
for (let i = 0; i < itemSize; i++) {
clonedArray[oldIndex * itemSize + i] = srcArray[newIndex * itemSize + i];
}
} else {
console.warn("no old index found");
}
}
attribute.array = clonedArray;
attribute.needsUpdate = true;
}
}
SortSopOperation.DEFAULT_PARAMS = {
mode: SORT_MODES.indexOf("axis" /* AXIS */),
targetType: SORT_TARGET_TYPES.indexOf(AttribClass.POINT),
seed: 0,
axis: AXISES.indexOf("x" /* X */),
attribute: "",
invert: false
};
SortSopOperation.INPUT_CLONED_STATE = InputCloneMode.FROM_NODE;