UNPKG

@polygonjs/polygonjs

Version:

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

169 lines (158 loc) 5.14 kB
import { CoreEntitySelectionState, selectedIndicesFromSelectionStates, } from '../../engine/nodes/sop/utils/group/GroupCommon'; import {TypeAssert} from '../../engine/poly/Assert'; import {arrayToSet} from '../ArrayUtils'; import {setToArray, setDifference, setIntersection, setUnion} from '../SetUtils'; import {CoreObjectType, ObjectContent} from './ObjectContent'; const _currentIndicesSet: Set<number> = new Set(); const _newIndicesSet: Set<number> = new Set(); export enum GroupOperation { SET = 'replace existing', UNION = 'add to existing', SUBTRACT = 'subtract from existing', INTERSECT = 'intersect with existing', } export const GROUP_OPERATIONS: GroupOperation[] = [ GroupOperation.SET, GroupOperation.UNION, GroupOperation.SUBTRACT, GroupOperation.INTERSECT, ]; export interface GroupData { name: string; entitiesCount: number; } type GroupsDataForType = GroupData[]; export type GroupCollectionData = Record<string, GroupsDataForType>; export enum EntityGroupType { POINT = 'point', OBJECT = 'object', EDGE = 'edge', FACE = 'face', } export interface UpdateGroupOptions { type: EntityGroupType; groupName: string; operation: GroupOperation; invert: boolean; } const USER_DATA_KEY_GROUPS = 'groups'; export type GroupsDictionary = Record<string, Record<string, number[]>>; export class EntityGroupCollection { // private _groupsByNameByType: Map<GroupType, Map<string, EntityGroup>> = new Map(); constructor(private _object: ObjectContent<CoreObjectType>) {} attributesDictionary() { return EntityGroupCollection.attributesDictionary(this._object); } static attributesDictionary<T extends CoreObjectType>(object: ObjectContent<T>) { return ( (object.userData[USER_DATA_KEY_GROUPS] as GroupsDictionary) || this._createAttributesDictionaryIfNone(object) ); } private static _createAttributesDictionaryIfNone<T extends CoreObjectType>(object: ObjectContent<T>) { if (!object.userData[USER_DATA_KEY_GROUPS]) { return (object.userData[USER_DATA_KEY_GROUPS] = {}); } } findOrCreateGroup(type: EntityGroupType, groupName: string) { const dict = this.attributesDictionary(); let groupsByName = dict[type]; if (!groupsByName) { groupsByName = {}; dict[type] = groupsByName; } let group = groupsByName[groupName]; if (!group) { group = []; groupsByName[groupName] = group; } return group; } deleteGroup(type: EntityGroupType, groupName: string) { const dict = this.attributesDictionary(); const groupsByName = dict[type]; if (groupsByName) { delete groupsByName[groupName]; // clean if possible if (Object.keys(groupsByName).length == 0) { delete dict[type]; } } } static data<T extends CoreObjectType>(object: ObjectContent<T>): GroupCollectionData { const dict = this.attributesDictionary(object); const types = Object.keys(dict); const data: GroupCollectionData = {}; for (const type of types) { const dataForType: GroupsDataForType = []; data[type] = dataForType; const groupsForType = dict[type]; const groupNames = Object.keys(groupsForType); for (const groupName of groupNames) { const indices = groupsForType[groupName]; const groupData: GroupData = { name: groupName, entitiesCount: indices.length, }; dataForType.push(groupData); } } return data; } indicesSet(type: EntityGroupType, groupName: string, target: Set<number>) { const dict = this.attributesDictionary(); const groupsByName = dict[type]; target.clear(); if (groupsByName) { const indices = groupsByName[groupName]; if (indices) { arrayToSet(indices, target); } } } private selectedIndices: Set<number> = new Set(); updateGroup(options: UpdateGroupOptions, selectionStates: CoreEntitySelectionState) { const {type, groupName, operation, invert} = options; const currentIndices = this.findOrCreateGroup(type, groupName); const _updateGroup = (newIndicesSet: Set<number>) => { const dict = this.attributesDictionary(); let groupsByName = dict[type]; if (!groupsByName) { groupsByName = {}; dict[type] = groupsByName; } const newIndices: number[] = []; groupsByName[groupName] = setToArray(newIndicesSet, newIndices); }; this.selectedIndices.clear(); selectedIndicesFromSelectionStates(selectionStates, this.selectedIndices, invert); switch (operation) { case GroupOperation.SET: { _updateGroup(this.selectedIndices); return; } case GroupOperation.UNION: { arrayToSet(currentIndices, _currentIndicesSet); setUnion(_currentIndicesSet, this.selectedIndices, _newIndicesSet); _updateGroup(_newIndicesSet); return; } case GroupOperation.SUBTRACT: { arrayToSet(currentIndices, _currentIndicesSet); setDifference(_currentIndicesSet, this.selectedIndices, _newIndicesSet); _updateGroup(_newIndicesSet); return; } case GroupOperation.INTERSECT: { arrayToSet(currentIndices, _currentIndicesSet); setIntersection(_currentIndicesSet, this.selectedIndices, _newIndicesSet); _updateGroup(_newIndicesSet); return; } } TypeAssert.unreachable(operation); } }