@thatopen/components 3.2.6 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +547 -29
- package/dist/index.d.ts +205 -12
- package/dist/index.min.cjs +3 -3
- package/dist/index.min.mjs +3 -3
- package/dist/index.mjs +548 -30
- package/package.json +5 -5
package/dist/index.mjs
CHANGED
|
@@ -5,7 +5,7 @@ var __publicField = (obj, key, value) => {
|
|
|
5
5
|
return value;
|
|
6
6
|
};
|
|
7
7
|
import * as FRAGS from "@thatopen/fragments";
|
|
8
|
-
import { DataMap as DataMap$1, FragmentsModels } from "@thatopen/fragments";
|
|
8
|
+
import { DataMap as DataMap$1, FragmentsModels, DataSet as DataSet$1 } from "@thatopen/fragments";
|
|
9
9
|
import * as THREE$1 from "three";
|
|
10
10
|
import { BufferAttribute, Vector3, Plane, Line3, Vector2, Triangle, Sphere, Matrix4, Box3, BackSide, DoubleSide, FrontSide, Ray, Mesh, Controls, Quaternion, Raycaster, Object3D, MeshBasicMaterial, LineBasicMaterial, CylinderGeometry, BoxGeometry, BufferGeometry, Float32BufferAttribute, OctahedronGeometry, Line, TorusGeometry, SphereGeometry, Euler, PlaneGeometry } from "three";
|
|
11
11
|
import * as WEBIFC from "web-ifc";
|
|
@@ -3078,7 +3078,7 @@ const _ConfigManager = class _ConfigManager extends Component {
|
|
|
3078
3078
|
/**
|
|
3079
3079
|
* The list of all configurations of this app.
|
|
3080
3080
|
*/
|
|
3081
|
-
__publicField(this, "list", new DataMap());
|
|
3081
|
+
__publicField(this, "list", new DataMap$1());
|
|
3082
3082
|
/** {@link Component.enabled} */
|
|
3083
3083
|
__publicField(this, "enabled", true);
|
|
3084
3084
|
components.add(_ConfigManager.uuid, this);
|
|
@@ -3897,6 +3897,7 @@ __publicField(_BoundingBoxer, "uuid", "d1444724-dba6-4cdd-a0c7-68ee1450d166");
|
|
|
3897
3897
|
let BoundingBoxer = _BoundingBoxer;
|
|
3898
3898
|
class FinderQuery {
|
|
3899
3899
|
constructor(components, queries) {
|
|
3900
|
+
__publicField(this, "name", "Query");
|
|
3900
3901
|
__publicField(this, "customData", {});
|
|
3901
3902
|
__publicField(this, "_components");
|
|
3902
3903
|
__publicField(this, "_queries", []);
|
|
@@ -4021,9 +4022,10 @@ class FinderQuery {
|
|
|
4021
4022
|
*/
|
|
4022
4023
|
toJSON() {
|
|
4023
4024
|
const manager = this._components.get(ItemsFinder);
|
|
4024
|
-
const
|
|
4025
|
+
const guid = manager.list.getKey(this) ?? UUID.create();
|
|
4025
4026
|
const result = {
|
|
4026
|
-
|
|
4027
|
+
guid,
|
|
4028
|
+
name: this.name,
|
|
4027
4029
|
customData: this.customData,
|
|
4028
4030
|
queries: this.queries.map(this.serializeQueryParameters),
|
|
4029
4031
|
aggregation: this.aggregation,
|
|
@@ -4056,6 +4058,7 @@ class FinderQuery {
|
|
|
4056
4058
|
* @returns A `FinderQuery` instance.
|
|
4057
4059
|
*/
|
|
4058
4060
|
fromJSON(data) {
|
|
4061
|
+
this.name = data.name;
|
|
4059
4062
|
this.customData = data.customData;
|
|
4060
4063
|
this.aggregation = data.aggregation;
|
|
4061
4064
|
this.cache = data.cache;
|
|
@@ -4087,7 +4090,17 @@ const _ItemsFinder = class _ItemsFinder extends Component {
|
|
|
4087
4090
|
* @returns A map of model IDs to sets of item IDs that match the query.
|
|
4088
4091
|
*/
|
|
4089
4092
|
async getItems(queries, config) {
|
|
4090
|
-
|
|
4093
|
+
let modelsToCheck;
|
|
4094
|
+
if (config) {
|
|
4095
|
+
const { modelIds, items } = config;
|
|
4096
|
+
if (items) {
|
|
4097
|
+
const itemsModels = Object.keys(items);
|
|
4098
|
+
if (itemsModels.length > 0)
|
|
4099
|
+
modelsToCheck = itemsModels.map((entry) => new RegExp(`^${entry}$`));
|
|
4100
|
+
} else if (modelIds) {
|
|
4101
|
+
modelsToCheck = modelIds;
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4091
4104
|
const aggregation = (config == null ? void 0 : config.aggregation) ?? "exclusive";
|
|
4092
4105
|
const fragments = this.components.get(FragmentsManager);
|
|
4093
4106
|
const results = await Promise.all(
|
|
@@ -4095,9 +4108,11 @@ const _ItemsFinder = class _ItemsFinder extends Component {
|
|
|
4095
4108
|
const result = {};
|
|
4096
4109
|
await Promise.all(
|
|
4097
4110
|
Array.from(fragments.list).map(async ([id, model]) => {
|
|
4098
|
-
|
|
4111
|
+
var _a2;
|
|
4112
|
+
if (modelsToCheck && !modelsToCheck.some((regex) => regex.test(id)))
|
|
4099
4113
|
return;
|
|
4100
|
-
const
|
|
4114
|
+
const localIds = (_a2 = config == null ? void 0 : config.items) == null ? void 0 : _a2[id];
|
|
4115
|
+
const items = await model.getItemsByQuery(query, { localIds: localIds ? [...localIds] : void 0 });
|
|
4101
4116
|
result[id] = new Set(items);
|
|
4102
4117
|
})
|
|
4103
4118
|
);
|
|
@@ -4156,9 +4171,8 @@ const _ItemsFinder = class _ItemsFinder extends Component {
|
|
|
4156
4171
|
if (!data)
|
|
4157
4172
|
return instances;
|
|
4158
4173
|
for (const value of data) {
|
|
4159
|
-
const
|
|
4160
|
-
|
|
4161
|
-
finderQuery.fromJSON({ customData, queries, aggregation, cache });
|
|
4174
|
+
const finderQuery = this.create(value.guid, []);
|
|
4175
|
+
finderQuery.fromJSON(value);
|
|
4162
4176
|
instances.push(finderQuery);
|
|
4163
4177
|
}
|
|
4164
4178
|
return instances;
|
|
@@ -4547,6 +4561,448 @@ const _Classifier = class _Classifier extends Component {
|
|
|
4547
4561
|
*/
|
|
4548
4562
|
__publicField(_Classifier, "uuid", "e25a7f3c-46c4-4a14-9d3d-5115f24ebeb7");
|
|
4549
4563
|
let Classifier = _Classifier;
|
|
4564
|
+
class FastModelPicker {
|
|
4565
|
+
constructor(components, world) {
|
|
4566
|
+
/** {@link Component.enabled} */
|
|
4567
|
+
__publicField(this, "enabled", true);
|
|
4568
|
+
/** The components instance to which this FastModelPicker belongs. */
|
|
4569
|
+
__publicField(this, "components");
|
|
4570
|
+
/** {@link Disposable.onDisposed} */
|
|
4571
|
+
__publicField(this, "onDisposed", new Event());
|
|
4572
|
+
/** The position of the mouse in the screen. */
|
|
4573
|
+
__publicField(this, "mouse");
|
|
4574
|
+
/**
|
|
4575
|
+
* A reference to the world instance to which this FastModelPicker belongs.
|
|
4576
|
+
* This is used to access the camera and scene.
|
|
4577
|
+
*/
|
|
4578
|
+
__publicField(this, "world");
|
|
4579
|
+
/**
|
|
4580
|
+
* Whether debug mode is enabled. When enabled, shows the color-coded canvas.
|
|
4581
|
+
*/
|
|
4582
|
+
__publicField(this, "debugMode", false);
|
|
4583
|
+
/**
|
|
4584
|
+
* Map from color (as RGB number) to model ID.
|
|
4585
|
+
* Color is encoded as: (r << 16) | (g << 8) | b
|
|
4586
|
+
*/
|
|
4587
|
+
__publicField(this, "colorToModelId", /* @__PURE__ */ new Map());
|
|
4588
|
+
/**
|
|
4589
|
+
* Map from model ID to color.
|
|
4590
|
+
*/
|
|
4591
|
+
__publicField(this, "modelIdToColor", /* @__PURE__ */ new Map());
|
|
4592
|
+
/**
|
|
4593
|
+
* Render target for the color-coded scene.
|
|
4594
|
+
*/
|
|
4595
|
+
__publicField(this, "renderTarget");
|
|
4596
|
+
/**
|
|
4597
|
+
* Size of the render target (stored separately since getSize doesn't exist).
|
|
4598
|
+
*/
|
|
4599
|
+
__publicField(this, "renderTargetSize", new THREE$1.Vector2());
|
|
4600
|
+
/**
|
|
4601
|
+
* Debug canvas element (shown when debugMode is true).
|
|
4602
|
+
*/
|
|
4603
|
+
__publicField(this, "debugCanvas");
|
|
4604
|
+
/**
|
|
4605
|
+
* Debug container element.
|
|
4606
|
+
*/
|
|
4607
|
+
__publicField(this, "debugContainer");
|
|
4608
|
+
/**
|
|
4609
|
+
* Material used for color-coding models.
|
|
4610
|
+
*/
|
|
4611
|
+
__publicField(this, "colorMaterials", /* @__PURE__ */ new Map());
|
|
4612
|
+
/**
|
|
4613
|
+
* Original materials cache (to restore after picking).
|
|
4614
|
+
*/
|
|
4615
|
+
__publicField(this, "originalMaterials", /* @__PURE__ */ new Map());
|
|
4616
|
+
__publicField(this, "originalLodColors", /* @__PURE__ */ new Map());
|
|
4617
|
+
/**
|
|
4618
|
+
* Whether colors need to be reassigned (when models change).
|
|
4619
|
+
*/
|
|
4620
|
+
__publicField(this, "colorsNeedUpdate", true);
|
|
4621
|
+
const renderer = world.renderer;
|
|
4622
|
+
if (!renderer) {
|
|
4623
|
+
throw new Error("A renderer is needed for the FastModelPicker to work!");
|
|
4624
|
+
}
|
|
4625
|
+
this.world = world;
|
|
4626
|
+
this.mouse = new Mouse(renderer.three.domElement);
|
|
4627
|
+
this.components = components;
|
|
4628
|
+
this.setupRenderTarget();
|
|
4629
|
+
this.setupFragmentListeners();
|
|
4630
|
+
}
|
|
4631
|
+
/**
|
|
4632
|
+
* Sets up listeners for fragment model changes.
|
|
4633
|
+
*/
|
|
4634
|
+
setupFragmentListeners() {
|
|
4635
|
+
const fragments = this.components.get(FragmentsManager);
|
|
4636
|
+
fragments.list.onItemSet.add(() => {
|
|
4637
|
+
this.colorsNeedUpdate = true;
|
|
4638
|
+
});
|
|
4639
|
+
fragments.list.onItemDeleted.add(() => {
|
|
4640
|
+
this.colorsNeedUpdate = true;
|
|
4641
|
+
});
|
|
4642
|
+
}
|
|
4643
|
+
/**
|
|
4644
|
+
* Sets up the render target for color-coded picking.
|
|
4645
|
+
*/
|
|
4646
|
+
setupRenderTarget() {
|
|
4647
|
+
const renderer = this.world.renderer.three;
|
|
4648
|
+
const size = renderer.getSize(new THREE$1.Vector2());
|
|
4649
|
+
this.renderTargetSize.copy(size);
|
|
4650
|
+
this.renderTarget = new THREE$1.WebGLRenderTarget(size.x, size.y);
|
|
4651
|
+
this.renderTarget.texture.format = THREE$1.RGBAFormat;
|
|
4652
|
+
this.renderTarget.texture.type = THREE$1.UnsignedByteType;
|
|
4653
|
+
if (this.debugMode) {
|
|
4654
|
+
this.setupDebugCanvas();
|
|
4655
|
+
}
|
|
4656
|
+
this.world.renderer.onResize.add((size2) => {
|
|
4657
|
+
this.renderTargetSize.copy(size2);
|
|
4658
|
+
this.renderTarget.setSize(size2.x, size2.y);
|
|
4659
|
+
if (this.debugCanvas) {
|
|
4660
|
+
this.debugCanvas.width = size2.x;
|
|
4661
|
+
this.debugCanvas.height = size2.y;
|
|
4662
|
+
}
|
|
4663
|
+
});
|
|
4664
|
+
}
|
|
4665
|
+
/**
|
|
4666
|
+
* Sets up the debug canvas for visualization.
|
|
4667
|
+
*/
|
|
4668
|
+
setupDebugCanvas() {
|
|
4669
|
+
if (this.debugCanvas)
|
|
4670
|
+
return;
|
|
4671
|
+
const size = this.world.renderer.three.getSize(new THREE$1.Vector2());
|
|
4672
|
+
this.debugContainer = document.createElement("div");
|
|
4673
|
+
this.debugContainer.style.position = "fixed";
|
|
4674
|
+
this.debugContainer.style.top = "10px";
|
|
4675
|
+
this.debugContainer.style.right = "10px";
|
|
4676
|
+
this.debugContainer.style.width = "300px";
|
|
4677
|
+
this.debugContainer.style.height = "300px";
|
|
4678
|
+
this.debugContainer.style.border = "2px solid #fff";
|
|
4679
|
+
this.debugContainer.style.backgroundColor = "#000";
|
|
4680
|
+
this.debugContainer.style.zIndex = "10000";
|
|
4681
|
+
this.debugContainer.style.pointerEvents = "none";
|
|
4682
|
+
this.debugCanvas = document.createElement("canvas");
|
|
4683
|
+
this.debugCanvas.width = size.x;
|
|
4684
|
+
this.debugCanvas.height = size.y;
|
|
4685
|
+
this.debugCanvas.style.width = "100%";
|
|
4686
|
+
this.debugCanvas.style.height = "100%";
|
|
4687
|
+
this.debugCanvas.style.imageRendering = "pixelated";
|
|
4688
|
+
this.debugContainer.appendChild(this.debugCanvas);
|
|
4689
|
+
document.body.appendChild(this.debugContainer);
|
|
4690
|
+
}
|
|
4691
|
+
/**
|
|
4692
|
+
* Generates a deterministic color for a model based on its ID.
|
|
4693
|
+
* This ensures the same model always gets the same color.
|
|
4694
|
+
*/
|
|
4695
|
+
generateColorForModel(modelId) {
|
|
4696
|
+
let hash = 0;
|
|
4697
|
+
for (let i = 0; i < modelId.length; i++) {
|
|
4698
|
+
hash = (hash << 5) - hash + modelId.charCodeAt(i);
|
|
4699
|
+
hash &= hash;
|
|
4700
|
+
}
|
|
4701
|
+
let colorId = Math.abs(hash) % 16777215;
|
|
4702
|
+
if (colorId === 0) {
|
|
4703
|
+
colorId = 1;
|
|
4704
|
+
}
|
|
4705
|
+
const r = colorId >> 16 & 255 || 1;
|
|
4706
|
+
const g = colorId >> 8 & 255 || 1;
|
|
4707
|
+
const b = colorId & 255 || 1;
|
|
4708
|
+
return new THREE$1.Color(r / 255, g / 255, b / 255);
|
|
4709
|
+
}
|
|
4710
|
+
/**
|
|
4711
|
+
* Converts a color to a numeric ID.
|
|
4712
|
+
*/
|
|
4713
|
+
colorToId(color) {
|
|
4714
|
+
const r = Math.round(color.r * 255);
|
|
4715
|
+
const g = Math.round(color.g * 255);
|
|
4716
|
+
const b = Math.round(color.b * 255);
|
|
4717
|
+
return r << 16 | g << 8 | b;
|
|
4718
|
+
}
|
|
4719
|
+
/**
|
|
4720
|
+
* Assigns unique colors to all fragment models.
|
|
4721
|
+
* Colors are deterministic based on model ID, so the same model always gets the same color.
|
|
4722
|
+
*/
|
|
4723
|
+
assignColors() {
|
|
4724
|
+
const fragments = this.components.get(FragmentsManager);
|
|
4725
|
+
if (!fragments.initialized) {
|
|
4726
|
+
return;
|
|
4727
|
+
}
|
|
4728
|
+
if (!this.colorsNeedUpdate) {
|
|
4729
|
+
const currentModelIds = new Set(fragments.list.keys());
|
|
4730
|
+
const cachedModelIds = new Set(this.modelIdToColor.keys());
|
|
4731
|
+
if (currentModelIds.size !== cachedModelIds.size || [...currentModelIds].some((id) => !cachedModelIds.has(id))) {
|
|
4732
|
+
this.colorsNeedUpdate = true;
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
if (!this.colorsNeedUpdate) {
|
|
4736
|
+
return;
|
|
4737
|
+
}
|
|
4738
|
+
this.colorToModelId.clear();
|
|
4739
|
+
this.modelIdToColor.clear();
|
|
4740
|
+
for (const material of this.colorMaterials.values()) {
|
|
4741
|
+
material.dispose();
|
|
4742
|
+
}
|
|
4743
|
+
this.colorMaterials.clear();
|
|
4744
|
+
for (const [modelId] of fragments.list) {
|
|
4745
|
+
const color = this.generateColorForModel(modelId);
|
|
4746
|
+
const colorId = this.colorToId(color);
|
|
4747
|
+
this.colorToModelId.set(colorId, modelId);
|
|
4748
|
+
this.modelIdToColor.set(modelId, color);
|
|
4749
|
+
const material = new THREE$1.MeshBasicMaterial({
|
|
4750
|
+
color,
|
|
4751
|
+
depthTest: true,
|
|
4752
|
+
depthWrite: true
|
|
4753
|
+
});
|
|
4754
|
+
this.colorMaterials.set(modelId, material);
|
|
4755
|
+
}
|
|
4756
|
+
this.colorsNeedUpdate = false;
|
|
4757
|
+
}
|
|
4758
|
+
/**
|
|
4759
|
+
* Applies color materials to fragment models.
|
|
4760
|
+
*/
|
|
4761
|
+
applyColorMaterials() {
|
|
4762
|
+
const fragments = this.components.get(FragmentsManager);
|
|
4763
|
+
if (!fragments.initialized) {
|
|
4764
|
+
return;
|
|
4765
|
+
}
|
|
4766
|
+
for (const [modelId, model] of fragments.list) {
|
|
4767
|
+
const modelMaterial = this.colorMaterials.get(modelId);
|
|
4768
|
+
if (!modelMaterial)
|
|
4769
|
+
continue;
|
|
4770
|
+
model.object.traverse((child) => {
|
|
4771
|
+
if (child instanceof THREE$1.Mesh) {
|
|
4772
|
+
if ("isLODGeometry" in child.geometry) {
|
|
4773
|
+
const originalLodMaterial = child.material[0];
|
|
4774
|
+
const lodColor = originalLodMaterial.uniforms.lodColor;
|
|
4775
|
+
if (!this.originalLodColors.has(lodColor)) {
|
|
4776
|
+
this.originalLodColors.set(lodColor, lodColor.value);
|
|
4777
|
+
}
|
|
4778
|
+
lodColor.value = modelMaterial.color;
|
|
4779
|
+
return;
|
|
4780
|
+
}
|
|
4781
|
+
if (!this.originalMaterials.has(child)) {
|
|
4782
|
+
this.originalMaterials.set(child, child.material);
|
|
4783
|
+
}
|
|
4784
|
+
child.material = modelMaterial;
|
|
4785
|
+
}
|
|
4786
|
+
});
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
/**
|
|
4790
|
+
* Restores original materials to fragment models.
|
|
4791
|
+
*/
|
|
4792
|
+
restoreOriginalMaterials() {
|
|
4793
|
+
for (const [object, material] of this.originalMaterials) {
|
|
4794
|
+
object.material = material;
|
|
4795
|
+
}
|
|
4796
|
+
for (const [lodColor, color] of this.originalLodColors) {
|
|
4797
|
+
lodColor.value = color;
|
|
4798
|
+
}
|
|
4799
|
+
this.originalMaterials.clear();
|
|
4800
|
+
}
|
|
4801
|
+
/**
|
|
4802
|
+
* Renders the scene with color-coded models.
|
|
4803
|
+
*/
|
|
4804
|
+
renderColorCoded() {
|
|
4805
|
+
if (!this.renderTarget || !this.world.renderer) {
|
|
4806
|
+
throw new Error("Render target not initialized!");
|
|
4807
|
+
}
|
|
4808
|
+
const renderer = this.world.renderer.three;
|
|
4809
|
+
const scene = this.world.scene.three;
|
|
4810
|
+
const camera = this.world.camera.three;
|
|
4811
|
+
const currentRenderTarget = renderer.getRenderTarget();
|
|
4812
|
+
const currentAutoClear = renderer.autoClear;
|
|
4813
|
+
const currentClearColor = new THREE$1.Color();
|
|
4814
|
+
const currentClearAlpha = renderer.getClearAlpha();
|
|
4815
|
+
renderer.getClearColor(currentClearColor);
|
|
4816
|
+
this.applyColorMaterials();
|
|
4817
|
+
renderer.setRenderTarget(this.renderTarget);
|
|
4818
|
+
renderer.autoClear = true;
|
|
4819
|
+
renderer.setClearColor(0, 1);
|
|
4820
|
+
renderer.clear(true, true, false);
|
|
4821
|
+
renderer.render(scene, camera);
|
|
4822
|
+
renderer.setRenderTarget(currentRenderTarget);
|
|
4823
|
+
renderer.autoClear = currentAutoClear;
|
|
4824
|
+
renderer.setClearColor(currentClearColor, currentClearAlpha);
|
|
4825
|
+
this.restoreOriginalMaterials();
|
|
4826
|
+
if (this.debugMode && this.debugCanvas) {
|
|
4827
|
+
this.updateDebugCanvas();
|
|
4828
|
+
}
|
|
4829
|
+
}
|
|
4830
|
+
/**
|
|
4831
|
+
* Updates the debug canvas with the color-coded render.
|
|
4832
|
+
*/
|
|
4833
|
+
updateDebugCanvas() {
|
|
4834
|
+
if (!this.debugCanvas || !this.renderTarget || !this.world.renderer)
|
|
4835
|
+
return;
|
|
4836
|
+
const renderer = this.world.renderer.three;
|
|
4837
|
+
const size = this.renderTargetSize;
|
|
4838
|
+
const pixels = new Uint8Array(size.x * size.y * 4);
|
|
4839
|
+
renderer.readRenderTargetPixels(
|
|
4840
|
+
this.renderTarget,
|
|
4841
|
+
0,
|
|
4842
|
+
0,
|
|
4843
|
+
size.x,
|
|
4844
|
+
size.y,
|
|
4845
|
+
pixels
|
|
4846
|
+
);
|
|
4847
|
+
const ctx = this.debugCanvas.getContext("2d");
|
|
4848
|
+
if (!ctx)
|
|
4849
|
+
return;
|
|
4850
|
+
const imageData = ctx.createImageData(size.x, size.y);
|
|
4851
|
+
const rowSize = size.x * 4;
|
|
4852
|
+
for (let y = 0; y < size.y; y++) {
|
|
4853
|
+
const srcRow = y;
|
|
4854
|
+
const dstRow = size.y - 1 - y;
|
|
4855
|
+
const srcOffset = srcRow * rowSize;
|
|
4856
|
+
const dstOffset = dstRow * rowSize;
|
|
4857
|
+
imageData.data.set(
|
|
4858
|
+
pixels.subarray(srcOffset, srcOffset + rowSize),
|
|
4859
|
+
dstOffset
|
|
4860
|
+
);
|
|
4861
|
+
}
|
|
4862
|
+
ctx.putImageData(imageData, 0, 0);
|
|
4863
|
+
}
|
|
4864
|
+
/**
|
|
4865
|
+
* Gets the model ID at the given screen position.
|
|
4866
|
+
*
|
|
4867
|
+
* @param position - Optional screen position. If not provided, uses current mouse position.
|
|
4868
|
+
* @returns The model ID at the position, or null if no model is found.
|
|
4869
|
+
*/
|
|
4870
|
+
async getModelAt(position) {
|
|
4871
|
+
if (!this.renderTarget || !this.world.renderer) {
|
|
4872
|
+
throw new Error("Render target not initialized!");
|
|
4873
|
+
}
|
|
4874
|
+
const fragments = this.components.get(FragmentsManager);
|
|
4875
|
+
if (!fragments.initialized || fragments.list.size === 0) {
|
|
4876
|
+
return null;
|
|
4877
|
+
}
|
|
4878
|
+
this.assignColors();
|
|
4879
|
+
this.renderColorCoded();
|
|
4880
|
+
const pos = position || this.mouse.position;
|
|
4881
|
+
const size = this.renderTargetSize;
|
|
4882
|
+
const x = Math.floor((pos.x + 1) * 0.5 * size.x);
|
|
4883
|
+
const y = Math.floor((pos.y + 1) * 0.5 * (size.y - 1));
|
|
4884
|
+
const clampedX = Math.max(0, Math.min(size.x - 1, x));
|
|
4885
|
+
const clampedY = Math.max(0, Math.min(size.y - 1, y));
|
|
4886
|
+
const renderer = this.world.renderer.three;
|
|
4887
|
+
const pixels = new Uint8Array(4);
|
|
4888
|
+
renderer.readRenderTargetPixels(
|
|
4889
|
+
this.renderTarget,
|
|
4890
|
+
clampedX,
|
|
4891
|
+
clampedY,
|
|
4892
|
+
1,
|
|
4893
|
+
1,
|
|
4894
|
+
pixels
|
|
4895
|
+
);
|
|
4896
|
+
const r = pixels[0];
|
|
4897
|
+
const g = pixels[1];
|
|
4898
|
+
const b = pixels[2];
|
|
4899
|
+
const colorId = r << 16 | g << 8 | b;
|
|
4900
|
+
const modelId = this.colorToModelId.get(colorId);
|
|
4901
|
+
return modelId || null;
|
|
4902
|
+
}
|
|
4903
|
+
/**
|
|
4904
|
+
* Enables or disables debug mode.
|
|
4905
|
+
* When enabled, shows a canvas with the color-coded render.
|
|
4906
|
+
*/
|
|
4907
|
+
setDebugMode(enabled) {
|
|
4908
|
+
this.debugMode = enabled;
|
|
4909
|
+
if (enabled) {
|
|
4910
|
+
this.setupDebugCanvas();
|
|
4911
|
+
} else {
|
|
4912
|
+
this.removeDebugCanvas();
|
|
4913
|
+
}
|
|
4914
|
+
}
|
|
4915
|
+
/**
|
|
4916
|
+
* Removes the debug canvas.
|
|
4917
|
+
*/
|
|
4918
|
+
removeDebugCanvas() {
|
|
4919
|
+
if (this.debugContainer) {
|
|
4920
|
+
this.debugContainer.remove();
|
|
4921
|
+
this.debugContainer = void 0;
|
|
4922
|
+
this.debugCanvas = void 0;
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
/** {@link Disposable.dispose} */
|
|
4926
|
+
dispose() {
|
|
4927
|
+
this.mouse.dispose();
|
|
4928
|
+
this.removeDebugCanvas();
|
|
4929
|
+
for (const material of this.colorMaterials.values()) {
|
|
4930
|
+
material.dispose();
|
|
4931
|
+
}
|
|
4932
|
+
this.colorMaterials.clear();
|
|
4933
|
+
if (this.renderTarget) {
|
|
4934
|
+
this.renderTarget.dispose();
|
|
4935
|
+
}
|
|
4936
|
+
this.colorToModelId.clear();
|
|
4937
|
+
this.modelIdToColor.clear();
|
|
4938
|
+
this.originalMaterials.clear();
|
|
4939
|
+
this.originalLodColors.clear();
|
|
4940
|
+
this.onDisposed.trigger();
|
|
4941
|
+
this.onDisposed.reset();
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4944
|
+
const _FastModelPickers = class _FastModelPickers extends Component {
|
|
4945
|
+
constructor(components) {
|
|
4946
|
+
super(components);
|
|
4947
|
+
/** {@link Component.enabled} */
|
|
4948
|
+
__publicField(this, "enabled", true);
|
|
4949
|
+
/**
|
|
4950
|
+
* A Map that stores FastModelPicker instances for each world.
|
|
4951
|
+
* The key is the world's UUID, and the value is the corresponding FastModelPicker instance.
|
|
4952
|
+
*/
|
|
4953
|
+
__publicField(this, "list", /* @__PURE__ */ new Map());
|
|
4954
|
+
/** {@link Disposable.onDisposed} */
|
|
4955
|
+
__publicField(this, "onDisposed", new Event());
|
|
4956
|
+
components.add(_FastModelPickers.uuid, this);
|
|
4957
|
+
}
|
|
4958
|
+
/**
|
|
4959
|
+
* Retrieves a FastModelPicker instance for the given world.
|
|
4960
|
+
* If a FastModelPicker instance already exists for the world, it will be returned.
|
|
4961
|
+
* Otherwise, a new FastModelPicker instance will be created and added to the list.
|
|
4962
|
+
*
|
|
4963
|
+
* @param world - The world for which to retrieve or create a FastModelPicker instance.
|
|
4964
|
+
* @returns The FastModelPicker instance for the given world.
|
|
4965
|
+
*/
|
|
4966
|
+
get(world) {
|
|
4967
|
+
if (this.list.has(world.uuid)) {
|
|
4968
|
+
return this.list.get(world.uuid);
|
|
4969
|
+
}
|
|
4970
|
+
const picker = new FastModelPicker(this.components, world);
|
|
4971
|
+
this.list.set(world.uuid, picker);
|
|
4972
|
+
world.onDisposed.add(() => {
|
|
4973
|
+
this.delete(world);
|
|
4974
|
+
});
|
|
4975
|
+
return picker;
|
|
4976
|
+
}
|
|
4977
|
+
/**
|
|
4978
|
+
* Deletes the FastModelPicker instance associated with the given world.
|
|
4979
|
+
* If a FastModelPicker instance exists for the given world, it will be disposed and removed from the list.
|
|
4980
|
+
*
|
|
4981
|
+
* @param world - The world for which to delete the FastModelPicker instance.
|
|
4982
|
+
* @returns {void}
|
|
4983
|
+
*/
|
|
4984
|
+
delete(world) {
|
|
4985
|
+
const picker = this.list.get(world.uuid);
|
|
4986
|
+
if (picker) {
|
|
4987
|
+
picker.dispose();
|
|
4988
|
+
}
|
|
4989
|
+
this.list.delete(world.uuid);
|
|
4990
|
+
}
|
|
4991
|
+
/** {@link Disposable.dispose} */
|
|
4992
|
+
dispose() {
|
|
4993
|
+
for (const [_id, picker] of this.list) {
|
|
4994
|
+
picker.dispose();
|
|
4995
|
+
}
|
|
4996
|
+
this.list.clear();
|
|
4997
|
+
this.onDisposed.trigger();
|
|
4998
|
+
}
|
|
4999
|
+
};
|
|
5000
|
+
/**
|
|
5001
|
+
* A unique identifier for the component.
|
|
5002
|
+
* This UUID is used to register the component within the Components system.
|
|
5003
|
+
*/
|
|
5004
|
+
__publicField(_FastModelPickers, "uuid", "4a82430c-7ff2-49ea-9401-60807502dad6");
|
|
5005
|
+
let FastModelPickers = _FastModelPickers;
|
|
4550
5006
|
class SimpleRaycaster {
|
|
4551
5007
|
constructor(components, world) {
|
|
4552
5008
|
/** {@link Component.enabled} */
|
|
@@ -4567,6 +5023,13 @@ class SimpleRaycaster {
|
|
|
4567
5023
|
* This is used to access the camera and meshes.
|
|
4568
5024
|
*/
|
|
4569
5025
|
__publicField(this, "world");
|
|
5026
|
+
/**
|
|
5027
|
+
* Whether to use fast model picking to optimize raycasting.
|
|
5028
|
+
* When enabled, the raycaster will first use FastModelPicker to identify
|
|
5029
|
+
* which model is under the mouse, then only raycast that specific model.
|
|
5030
|
+
* This can significantly improve performance when there are many models.
|
|
5031
|
+
*/
|
|
5032
|
+
__publicField(this, "useFastModelPicking", false);
|
|
4570
5033
|
const renderer = world.renderer;
|
|
4571
5034
|
if (!renderer) {
|
|
4572
5035
|
throw new Error("A renderer is needed for the raycaster to work!");
|
|
@@ -4613,12 +5076,46 @@ class SimpleRaycaster {
|
|
|
4613
5076
|
const mouse = this.mouse.rawPosition;
|
|
4614
5077
|
let fragResult = null;
|
|
4615
5078
|
if (fragments.initialized) {
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
5079
|
+
if (this.useFastModelPicking) {
|
|
5080
|
+
const fastPickers = this.components.get(FastModelPickers);
|
|
5081
|
+
const fastPicker = fastPickers.get(this.world);
|
|
5082
|
+
const modelId = await fastPicker.getModelAt(position);
|
|
5083
|
+
if (modelId) {
|
|
5084
|
+
const model = fragments.list.get(modelId);
|
|
5085
|
+
if (model) {
|
|
5086
|
+
if (snappingClasses && snappingClasses.length > 0) {
|
|
5087
|
+
const snappingRaycast = await model.raycastWithSnapping({
|
|
5088
|
+
camera,
|
|
5089
|
+
dom,
|
|
5090
|
+
mouse,
|
|
5091
|
+
snappingClasses
|
|
5092
|
+
});
|
|
5093
|
+
if (snappingRaycast && snappingRaycast.length > 0) {
|
|
5094
|
+
fragResult = snappingRaycast[0];
|
|
5095
|
+
} else {
|
|
5096
|
+
fragResult = await model.raycast({
|
|
5097
|
+
camera,
|
|
5098
|
+
dom,
|
|
5099
|
+
mouse
|
|
5100
|
+
});
|
|
5101
|
+
}
|
|
5102
|
+
} else {
|
|
5103
|
+
fragResult = await model.raycast({
|
|
5104
|
+
camera,
|
|
5105
|
+
dom,
|
|
5106
|
+
mouse
|
|
5107
|
+
});
|
|
5108
|
+
}
|
|
5109
|
+
}
|
|
5110
|
+
}
|
|
5111
|
+
} else {
|
|
5112
|
+
fragResult = await fragments.raycast({
|
|
5113
|
+
camera,
|
|
5114
|
+
dom,
|
|
5115
|
+
mouse,
|
|
5116
|
+
snappingClasses
|
|
5117
|
+
});
|
|
5118
|
+
}
|
|
4622
5119
|
if (items.length === 0) {
|
|
4623
5120
|
return fragResult;
|
|
4624
5121
|
}
|
|
@@ -7644,7 +8141,7 @@ const _Worlds = class _Worlds extends Component {
|
|
|
7644
8141
|
* A collection of worlds managed by this component.
|
|
7645
8142
|
* The key is the unique identifier (UUID) of the world, and the value is the World instance.
|
|
7646
8143
|
*/
|
|
7647
|
-
__publicField(this, "list", new DataMap());
|
|
8144
|
+
__publicField(this, "list", new DataMap$1());
|
|
7648
8145
|
/** {@link Component.enabled} */
|
|
7649
8146
|
__publicField(this, "enabled", true);
|
|
7650
8147
|
components.add(_Worlds.uuid, this);
|
|
@@ -11516,10 +12013,11 @@ const _Components = class _Components {
|
|
|
11516
12013
|
* @throws Will throw an error if a component with the same UUID already exists.
|
|
11517
12014
|
*/
|
|
11518
12015
|
get(Component2) {
|
|
12016
|
+
var _a2;
|
|
11519
12017
|
const uuid = Component2.uuid;
|
|
11520
12018
|
if (!this.list.has(uuid)) {
|
|
11521
12019
|
const toolInstance = new Component2(this);
|
|
11522
|
-
if (toolInstance.isDisposeable()) {
|
|
12020
|
+
if ((_a2 = toolInstance.isDisposeable) == null ? void 0 : _a2.call(toolInstance)) {
|
|
11523
12021
|
toolInstance.onDisposed.add(() => this.list.delete(uuid));
|
|
11524
12022
|
}
|
|
11525
12023
|
if (!this.list.has(uuid)) {
|
|
@@ -11969,6 +12467,14 @@ class OrthoPerspectiveCamera extends SimpleCamera {
|
|
|
11969
12467
|
this.disableUserInput();
|
|
11970
12468
|
}
|
|
11971
12469
|
}
|
|
12470
|
+
/**
|
|
12471
|
+
* Adds a custom {@link NavigationMode} to the camera that can be used using the {@link OrthoPerspectiveCamera.set} method.
|
|
12472
|
+
*
|
|
12473
|
+
* @param mode - The custom {@link NavigationMode} to add.
|
|
12474
|
+
*/
|
|
12475
|
+
addCustomNavigationMode(mode) {
|
|
12476
|
+
this._navigationModes.set(mode.id, mode);
|
|
12477
|
+
}
|
|
11972
12478
|
disableUserInput() {
|
|
11973
12479
|
this._userInputButtons.left = this.controls.mouseButtons.left;
|
|
11974
12480
|
this._userInputButtons.right = this.controls.mouseButtons.right;
|
|
@@ -14751,13 +15257,13 @@ const _Topic = class _Topic {
|
|
|
14751
15257
|
__publicField(this, "creationDate", /* @__PURE__ */ new Date());
|
|
14752
15258
|
__publicField(this, "creationAuthor", "");
|
|
14753
15259
|
// Store viewpoint guids instead of the actual Viewpoint to prevent a possible memory leak
|
|
14754
|
-
__publicField(this, "viewpoints", new DataSet());
|
|
15260
|
+
__publicField(this, "viewpoints", new DataSet$1());
|
|
14755
15261
|
// Store topic guids instead of the actual Topic to prevent a possible memory leak
|
|
14756
|
-
__publicField(this, "relatedTopics", new DataSet());
|
|
15262
|
+
__publicField(this, "relatedTopics", new DataSet$1());
|
|
14757
15263
|
// There is no problem to store the comment it-self as it is not referenced anywhere else
|
|
14758
|
-
__publicField(this, "comments", new DataMap());
|
|
15264
|
+
__publicField(this, "comments", new DataMap$1());
|
|
14759
15265
|
// Store document reference guids instead of the actual thing to prevent a possible memory leak
|
|
14760
|
-
__publicField(this, "documentReferences", new DataSet());
|
|
15266
|
+
__publicField(this, "documentReferences", new DataSet$1());
|
|
14761
15267
|
__publicField(this, "customData", {});
|
|
14762
15268
|
__publicField(this, "description");
|
|
14763
15269
|
__publicField(this, "serverAssignedId");
|
|
@@ -15367,8 +15873,8 @@ const _BCFTopics = class _BCFTopics extends Component {
|
|
|
15367
15873
|
"BCF Topics",
|
|
15368
15874
|
_BCFTopics.uuid
|
|
15369
15875
|
));
|
|
15370
|
-
__publicField(this, "list", new DataMap());
|
|
15371
|
-
__publicField(this, "documents", new DataMap());
|
|
15876
|
+
__publicField(this, "list", new DataMap$1());
|
|
15877
|
+
__publicField(this, "documents", new DataMap$1());
|
|
15372
15878
|
__publicField(this, "onSetup", new Event());
|
|
15373
15879
|
__publicField(this, "isSetup", false);
|
|
15374
15880
|
__publicField(this, "onBCFImported", new Event());
|
|
@@ -17302,6 +17808,15 @@ class SimplePlane {
|
|
|
17302
17808
|
get helper() {
|
|
17303
17809
|
return this._helper;
|
|
17304
17810
|
}
|
|
17811
|
+
/**
|
|
17812
|
+
* Getter for the transform controls of the clipping plane.
|
|
17813
|
+
* The controls allow interactive manipulation (translation, rotation, etc.) of the clipping plane.
|
|
17814
|
+
*
|
|
17815
|
+
* @returns {TransformControls} The transform controls of the clipping plane.
|
|
17816
|
+
*/
|
|
17817
|
+
get controls() {
|
|
17818
|
+
return this._controls;
|
|
17819
|
+
}
|
|
17305
17820
|
/**
|
|
17306
17821
|
* Sets the clipping plane's normal and origin from the given normal and point.
|
|
17307
17822
|
* This method resets the clipping plane's state, updates the normal and origin,
|
|
@@ -17566,6 +18081,7 @@ const _Clipper = class _Clipper extends Component {
|
|
|
17566
18081
|
__publicField(this, "_size", 5);
|
|
17567
18082
|
__publicField(this, "_enabled", false);
|
|
17568
18083
|
__publicField(this, "_visible", true);
|
|
18084
|
+
__publicField(this, "onStateChanged", new Event());
|
|
17569
18085
|
__publicField(this, "_onStartDragging", () => {
|
|
17570
18086
|
this.onBeforeDrag.trigger();
|
|
17571
18087
|
});
|
|
@@ -17582,6 +18098,7 @@ const _Clipper = class _Clipper extends Component {
|
|
|
17582
18098
|
/** {@link Component.enabled} */
|
|
17583
18099
|
set enabled(state) {
|
|
17584
18100
|
this._enabled = state;
|
|
18101
|
+
this.onStateChanged.trigger(["enabled"]);
|
|
17585
18102
|
}
|
|
17586
18103
|
/** {@link Hideable.visible } */
|
|
17587
18104
|
get visible() {
|
|
@@ -17593,6 +18110,7 @@ const _Clipper = class _Clipper extends Component {
|
|
|
17593
18110
|
for (const [_, plane] of this.list) {
|
|
17594
18111
|
plane.visible = state;
|
|
17595
18112
|
}
|
|
18113
|
+
this.onStateChanged.trigger(["visibility"]);
|
|
17596
18114
|
}
|
|
17597
18115
|
/** The material of the clipping plane representation. */
|
|
17598
18116
|
get material() {
|
|
@@ -17604,6 +18122,7 @@ const _Clipper = class _Clipper extends Component {
|
|
|
17604
18122
|
for (const [_, plane] of this.list) {
|
|
17605
18123
|
plane.planeMaterial = material;
|
|
17606
18124
|
}
|
|
18125
|
+
this.onStateChanged.trigger(["material"]);
|
|
17607
18126
|
}
|
|
17608
18127
|
/** The size of the geometric representation of the clippings planes. */
|
|
17609
18128
|
get size() {
|
|
@@ -17615,6 +18134,7 @@ const _Clipper = class _Clipper extends Component {
|
|
|
17615
18134
|
for (const [_, plane] of this.list) {
|
|
17616
18135
|
plane.size = size;
|
|
17617
18136
|
}
|
|
18137
|
+
this.onStateChanged.trigger(["size"]);
|
|
17618
18138
|
}
|
|
17619
18139
|
setEvents() {
|
|
17620
18140
|
this.list.onBeforeDelete.add(({ value: plane }) => {
|
|
@@ -17848,6 +18368,7 @@ class Viewpoint {
|
|
|
17848
18368
|
camera_view_point: { x: 0, y: 0, z: 0 },
|
|
17849
18369
|
camera_up_vector: { x: 0, y: 1, z: 0 }
|
|
17850
18370
|
});
|
|
18371
|
+
__publicField(this, "customData", {});
|
|
17851
18372
|
/**
|
|
17852
18373
|
* A list of components GUIDs to hide when defaultVisibility = true or to show when defaultVisibility = false
|
|
17853
18374
|
*/
|
|
@@ -20992,7 +21513,7 @@ const _IDSSpecifications = class _IDSSpecifications extends Component {
|
|
|
20992
21513
|
super(components);
|
|
20993
21514
|
__publicField(this, "enabled", true);
|
|
20994
21515
|
__publicField(this, "IDSInfo");
|
|
20995
|
-
__publicField(this, "list", new DataMap());
|
|
21516
|
+
__publicField(this, "list", new DataMap$1());
|
|
20996
21517
|
components.add(_IDSSpecifications.uuid, this);
|
|
20997
21518
|
}
|
|
20998
21519
|
/**
|
|
@@ -21519,11 +22040,6 @@ const _MeasurementUtils = class _MeasurementUtils extends Component {
|
|
|
21519
22040
|
throw new Error("Precision must be an integer between 0 and 5.");
|
|
21520
22041
|
}
|
|
21521
22042
|
let factor = unitFactors[fromUnit] / unitFactors[toUnit];
|
|
21522
|
-
if (fromUnit.endsWith("2") && toUnit.endsWith("2")) {
|
|
21523
|
-
factor **= 2;
|
|
21524
|
-
} else if (fromUnit.endsWith("3") && toUnit.endsWith("3")) {
|
|
21525
|
-
factor **= 3;
|
|
21526
|
-
}
|
|
21527
22043
|
const convertedValue = value * factor;
|
|
21528
22044
|
const roundingFactor = 10 ** precision;
|
|
21529
22045
|
return Math.round(convertedValue * roundingFactor) / roundingFactor;
|
|
@@ -21558,6 +22074,8 @@ export {
|
|
|
21558
22074
|
Disposer,
|
|
21559
22075
|
Event,
|
|
21560
22076
|
EventManager,
|
|
22077
|
+
FastModelPicker,
|
|
22078
|
+
FastModelPickers,
|
|
21561
22079
|
FinderQuery,
|
|
21562
22080
|
FirstPersonMode,
|
|
21563
22081
|
FragmentsManager,
|