UNPKG

@polygonjs/polygonjs

Version:

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

139 lines (125 loc) 4.23 kB
import {pushOnArrayAtEntry} from './../../../core/MapUtils'; import {Vector2, Vector3, Box3, Object3D} from 'three'; import {BaseSopOperation} from './_Base'; import {CoreGroup} from '../../../core/geometry/Group'; import {InputCloneMode} from '../../../engine/poly/InputCloneMode'; import {DefaultOperationParams} from '../../../core/operations/_Base'; import {isBooleanTrue} from '../../../core/Type'; import {coreObjectClassFactory} from '../../../core/geometry/CoreObjectFactory'; interface ObjectsLayoutSopParams extends DefaultOperationParams { maxLayoutWidth: number; rowHeight: number; padding: Vector2; addAttribs: boolean; addRowAttrib: boolean; addRowWidthInner: boolean; addRowWidthOuter: boolean; } const currentPos = new Vector2(0, 0); const maxPos = new Vector2(0, 0); const box = new Box3(); const boxSize = new Vector3(0, 0); const objectsByRow: Map<number, Object3D[]> = new Map(); export class ObjectsLayoutSopOperation extends BaseSopOperation { static override readonly DEFAULT_PARAMS: ObjectsLayoutSopParams = { maxLayoutWidth: 10, rowHeight: 1, padding: new Vector2(0, 0), addAttribs: false, addRowAttrib: false, addRowWidthInner: false, addRowWidthOuter: false, }; static override readonly INPUT_CLONED_STATE = InputCloneMode.FROM_NODE; static override type(): Readonly<'objectsLayout'> { return 'objectsLayout'; } override cook(inputCoreGroups: CoreGroup[], params: ObjectsLayoutSopParams) { const objects = inputCoreGroups[0].threejsObjects(); currentPos.set(0, 0); maxPos.set(0, 0); objectsByRow.clear(); let rowIndex = 0; const addRowWidth = isBooleanTrue(params.addRowWidthInner) || isBooleanTrue(params.addRowWidthOuter); for (let object of objects) { // get size before scale adjustment object.updateMatrix(); box.setFromObject(object); box.getSize(boxSize); // scale adjustment const scaleFactor = params.rowHeight / boxSize.y; object.scale.multiplyScalar(scaleFactor); object.updateMatrix(); // get size after scale adjustment box.setFromObject(object); box.getSize(boxSize); // apply padding boxSize.x += params.padding.x; boxSize.y += params.padding.y; // move currentPos.x += boxSize.x; // change row if needed if (currentPos.x > params.maxLayoutWidth) { currentPos.x = boxSize.x; currentPos.y -= boxSize.y; rowIndex++; } // move current object object.position.x = currentPos.x - boxSize.x * 0.5; object.position.y = currentPos.y - boxSize.y * 0.5; if (isBooleanTrue(params.addAttribs)) { if (addRowWidth) { pushOnArrayAtEntry(objectsByRow, rowIndex, object); } if (isBooleanTrue(params.addRowAttrib)) { coreObjectClassFactory(object).addAttribute(object, 'row', rowIndex); } } maxPos.x = Math.max(maxPos.x, object.position.x + boxSize.x * 0.5); maxPos.y = Math.min(maxPos.y, object.position.y - boxSize.y * 0.5); } // center all objects together for (let object of objects) { object.position.x -= maxPos.x * 0.5; object.position.y -= maxPos.y * 0.5; object.updateMatrix(); } // add attribs if (isBooleanTrue(params.addAttribs)) { if (addRowWidth) { objectsByRow.forEach((objects, _) => { if (isBooleanTrue(params.addRowWidthInner)) { const xs = objects.map((o) => o.position.x); const minX = Math.min(...xs); const maxX = Math.max(...xs); const width = maxX - minX; for (let object of objects) { coreObjectClassFactory(object).addAttribute(object, 'rowWidthInner', width); } } if (isBooleanTrue(params.addRowWidthOuter)) { const minX = Math.min( ...objects.map((o) => { box.setFromObject(o); box.getSize(boxSize); return o.position.x - boxSize.x * 0.5; }) ); const maxX = Math.max( ...objects.map((o) => { box.setFromObject(o); box.getSize(boxSize); return o.position.x + boxSize.x * 0.5; }) ); const width = maxX - minX; for (let object of objects) { coreObjectClassFactory(object).addAttribute(object, 'rowWidthOuter', width); } } }); } } return this.createCoreGroupFromObjects(objects); } }