UNPKG

polygonjs-engine

Version:

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

154 lines (140 loc) 5.23 kB
import {BaseSopOperation} from './_Base'; import {DefaultOperationParams} from '../_Base'; import {CoreGroup} from '../../../core/geometry/Group'; import {InputCloneMode} from '../../../engine/poly/InputCloneMode'; import {AttribClass} from '../../geometry/Constant'; import {CoreObject} from '../../geometry/Object'; import {CorePoint} from '../../geometry/Point'; import {CoreString} from '../../String'; import {ArrayUtils} from '../../ArrayUtils'; import {NumericAttribValue, PolyDictionary} from '../../../types/GlobalTypes'; import {CoreAttribute} from '../../geometry/Attribute'; interface AttribPromoteSopParams extends DefaultOperationParams { classFrom: number; classTo: number; mode: number; name: string; } export enum AttribPromoteMode { MIN = 0, MAX = 1, FIRST_FOUND = 2, } export class AttribPromoteSopOperation extends BaseSopOperation { static readonly DEFAULT_PARAMS: AttribPromoteSopParams = { classFrom: AttribClass.VERTEX, classTo: AttribClass.OBJECT, mode: AttribPromoteMode.FIRST_FOUND, name: '', }; static readonly INPUT_CLONED_STATE = InputCloneMode.FROM_NODE; static type(): Readonly<'attribPromote'> { return 'attribPromote'; } private _core_group: CoreGroup | undefined; private _core_object: CoreObject | undefined; private _values_per_attrib_name: PolyDictionary<NumericAttribValue[]> = {}; private _filtered_values_per_attrib_name: PolyDictionary<NumericAttribValue | undefined> = {}; cook(input_contents: CoreGroup[], params: AttribPromoteSopParams) { this._core_group = input_contents[0]; this._values_per_attrib_name = {}; this._filtered_values_per_attrib_name = {}; for (let core_object of this._core_group.coreObjects()) { this._core_object = core_object; this.find_values(params); this.filter_values(params); this.set_values(params); } return this._core_group; } private find_values(params: AttribPromoteSopParams) { const attrib_names = CoreString.attribNames(params.name); for (let attrib_name of attrib_names) { this._find_values_for_attrib_name(attrib_name, params); } } private _find_values_for_attrib_name(attrib_name: string, params: AttribPromoteSopParams) { switch (params.classFrom) { case AttribClass.VERTEX: return this.find_values_from_points(attrib_name, params); case AttribClass.OBJECT: return this.find_values_from_object(attrib_name, params); } } private find_values_from_points(attrib_name: string, params: AttribPromoteSopParams) { if (this._core_object) { const points = this._core_object.points(); const first_point = points[0]; if (first_point) { if (!first_point.isAttribIndexed(attrib_name)) { const values: NumericAttribValue[] = new Array(points.length); let point: CorePoint; for (let i = 0; i < points.length; i++) { point = points[i]; values[i] = point.attribValue(attrib_name) as NumericAttribValue; } this._values_per_attrib_name[attrib_name] = values; } } } } private find_values_from_object(attrib_name: string, params: AttribPromoteSopParams) { this._values_per_attrib_name[attrib_name] = []; if (this._core_object) { this._values_per_attrib_name[attrib_name].push(this._core_object.attribValue(attrib_name) as number); } } private filter_values(params: AttribPromoteSopParams) { const attrib_names = Object.keys(this._values_per_attrib_name); for (let attrib_name of attrib_names) { const values = this._values_per_attrib_name[attrib_name]; switch (params.mode) { case AttribPromoteMode.MIN: this._filtered_values_per_attrib_name[attrib_name] = ArrayUtils.min(values); break; case AttribPromoteMode.MAX: this._filtered_values_per_attrib_name[attrib_name] = ArrayUtils.max(values); break; case AttribPromoteMode.FIRST_FOUND: this._filtered_values_per_attrib_name[attrib_name] = values[0]; break; default: break; } } } private set_values(params: AttribPromoteSopParams) { const attrib_names = Object.keys(this._filtered_values_per_attrib_name); for (let attrib_name of attrib_names) { const new_value = this._filtered_values_per_attrib_name[attrib_name]; if (new_value != null) { switch (params.classTo) { case AttribClass.VERTEX: this.set_values_to_points(attrib_name, new_value, params); break; case AttribClass.OBJECT: this.set_values_to_object(attrib_name, new_value, params); break; } } } } private set_values_to_points(attrib_name: string, new_value: NumericAttribValue, params: AttribPromoteSopParams) { if (this._core_group && this._core_object) { const attribute_exists = this._core_group.hasAttrib(attrib_name); if (!attribute_exists) { const attribSize = CoreAttribute.attribSizeFromValue(new_value); if (attribSize) { this._core_group.addNumericVertexAttrib(attrib_name, attribSize, new_value); } } const points = this._core_object.points(); for (let point of points) { point.setAttribValue(attrib_name, new_value); } } } private set_values_to_object(attrib_name: string, new_value: NumericAttribValue, params: AttribPromoteSopParams) { this._core_object?.setAttribValue(attrib_name, new_value); } }