Spaces:
Running
Running
| import { SplatData } from "./SplatData"; | |
| import { Object3D } from "../core/Object3D"; | |
| import { Vector3 } from "../math/Vector3"; | |
| import { Quaternion } from "../math/Quaternion"; | |
| import { Converter } from "../utils/Converter"; | |
| import { Matrix4 } from "../math/Matrix4"; | |
| import { Box3 } from "../math/Box3"; | |
| class Splat extends Object3D { | |
| public selectedChanged: boolean = false; | |
| public colorTransformChanged: boolean = false; | |
| private _data: SplatData; | |
| private _selected: boolean = false; | |
| private _colorTransforms: Array<Matrix4> = []; | |
| private _colorTransformsMap: Map<number, number> = new Map(); | |
| private _bounds: Box3; | |
| recalculateBounds: () => void; | |
| constructor(splat: SplatData | undefined = undefined) { | |
| super(); | |
| this._data = splat || new SplatData(); | |
| this._bounds = new Box3( | |
| new Vector3(Infinity, Infinity, Infinity), | |
| new Vector3(-Infinity, -Infinity, -Infinity), | |
| ); | |
| this.recalculateBounds = () => { | |
| this._bounds = new Box3( | |
| new Vector3(Infinity, Infinity, Infinity), | |
| new Vector3(-Infinity, -Infinity, -Infinity), | |
| ); | |
| for (let i = 0; i < this._data.vertexCount; i++) { | |
| this._bounds.expand( | |
| new Vector3( | |
| this._data.positions[3 * i], | |
| this._data.positions[3 * i + 1], | |
| this._data.positions[3 * i + 2], | |
| ), | |
| ); | |
| } | |
| }; | |
| this.applyPosition = () => { | |
| this.data.translate(this.position); | |
| this.position = new Vector3(); | |
| }; | |
| this.applyRotation = () => { | |
| this.data.rotate(this.rotation); | |
| this.rotation = new Quaternion(); | |
| }; | |
| this.applyScale = () => { | |
| this.data.scale(this.scale); | |
| this.scale = new Vector3(1, 1, 1); | |
| }; | |
| this.recalculateBounds(); | |
| } | |
| saveToFile(name: string | null = null, format: "splat" | "ply" = "splat") { | |
| if (!document) return; | |
| if (!name) { | |
| const now = new Date(); | |
| name = `splat-${now.getFullYear()}-${now.getMonth() + 1}-${now.getDate()}.${format}`; | |
| } | |
| const splatClone = this.clone(); | |
| splatClone.applyRotation(); | |
| splatClone.applyScale(); | |
| splatClone.applyPosition(); | |
| const data = splatClone.data.serialize(); | |
| let blob; | |
| if (format === "ply") { | |
| const plyData = Converter.SplatToPLY(data.buffer, splatClone.data.vertexCount); | |
| blob = new Blob([plyData], { type: "application/octet-stream" }); | |
| } else { | |
| blob = new Blob([data.buffer], { type: "application/octet-stream" }); | |
| } | |
| const link = document.createElement("a"); | |
| link.download = name; | |
| link.href = URL.createObjectURL(blob); | |
| link.click(); | |
| } | |
| get data() { | |
| return this._data; | |
| } | |
| get selected() { | |
| return this._selected; | |
| } | |
| set selected(selected: boolean) { | |
| if (this._selected !== selected) { | |
| this._selected = selected; | |
| this.selectedChanged = true; | |
| this.dispatchEvent(this._changeEvent); | |
| } | |
| } | |
| get colorTransforms() { | |
| return this._colorTransforms; | |
| } | |
| get colorTransformsMap() { | |
| return this._colorTransformsMap; | |
| } | |
| get bounds() { | |
| let center = this._bounds.center(); | |
| center = center.add(this.position); | |
| let size = this._bounds.size(); | |
| size = size.multiply(this.scale); | |
| return new Box3(center.subtract(size.divide(2)), center.add(size.divide(2))); | |
| } | |
| clone() { | |
| const splat = new Splat(this.data.clone()); | |
| splat.position = this.position.clone(); | |
| splat.rotation = this.rotation.clone(); | |
| splat.scale = this.scale.clone(); | |
| return splat; | |
| } | |
| } | |
| export { Splat }; | |