/** Copyright Stewart Allen -- All Rights Reserved */ import { THREE } from '../ext/three.js'; const { Group, Box3 } = THREE; import { license as motoLicense } from '../moto/license.js'; import { broker as motoBroker } from '../moto/broker.js'; import { client as motoClient } from '../moto/client.js'; import { space as motoSpace } from '../moto/space.js'; import { object as meshObject } from './object.js'; import { api as meshApi } from './api.js'; import { model as meshModel } from './model.js'; const call = motoBroker.send; const worker = motoClient.fn; class MeshGroup extends meshObject { // @param group {MeshModel[]} constructor(models = [], id, name) { super(id); this.group3 = new Group(); this.models = []; this.name = name; for (let model of models) { this.add(model); } } get type() { return "group"; } get object() { return this.group3; } get bounds() { let box3 = new Box3(); for (let model of this.models) { box3.union(model.bounds); } return box3; } // @param model {MeshModel} add(model) { model.group = this; this.models.addOnce(model); this.group3.add(model.mesh); motoSpace.update(); call.model_add({model, group:this}); worker.group_add({id: this.id, model:model.id}); // update data store meshApi.db.space.put(this.id, this.models.map(m => m.id)); return this; } // @param model {MeshModel} // @param free {boolean} prevent cleanup of model so it can be re-used remove(model, opt = { free: true }) { // remove all models and group if (arguments.length === 0) { for (let m of this.models.slice()) { this.remove(m); } return; } this.models.remove(model); this.group3.remove(model.mesh); // create message for listeners call.model_remove({model, group:this}); // trigger sync with worker worker.group_remove({id: this.id, model: model.id}); // ensure worker cleanup of model if (opt.free) model.remove(true); // auto-remove group when empty if (this.group3.children.length === 0) { meshApi.group.remove(this); // manage lifecycle with worker, mesh app caches, etc this.destroy(); } else { // update data store meshApi.db.space.put(this.id, this.models.map(m => m.id)); } motoSpace.update(); return this; } promote() { let { dim, mid } = this.bounds; let { x, y, z } = dim; let max = Math.max(x, y, z); if (max < 2) { meshApi.log.emit(`auto-scaling import from ${max.round(5)}`); this.scale(1000, 1000, 1000); } let { center, floor } = meshApi.prefs.map.space; if (center !== false) this.centerXY(); if (floor !== false) this.floor(); return this; } rotate(x = 0, y = 0, z = 0) { this.log('group-rotate', ...arguments); for (let model of this.models) { model.rotate(...arguments); } return this; } qrotate(quaternion) { this.log('group-rotate', quaternion.toArray()); for (let model of this.models) { model.qrotate(quaternion); } return this; } scale(x = 1, y = 1, z = 1) { this.log('group-scale', ...arguments); for (let m of this.models) { m.scale(x, y, z); } return this; } move(x = 0, y = 0, z = 0) { this.log('group-move', ...arguments); if (!(x || y || z)) return; for (let model of this.models) { model.move(x, y, z); } return this; } center() { let b = this.bounds; return this.move(-b.mid.x, -b.mid.y, -b.mid.z); } centerXY() { let b = this.bounds; return this.move(-b.mid.x, -b.mid.y, 0); } opacity() { for (let model of this.models) { model.opacity(...arguments); } } wireframe() { for (let model of this.models) { model.wireframe(...arguments); } } normals() { for (let model of this.models) { model.normals(...arguments); } } select() { for (let model of this.models) { model.select(...arguments); } } } export { MeshGroup as group };