bimatter-viewer-react 0.1.4 → 0.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/README.md CHANGED
@@ -4,10 +4,12 @@ React viewer for Bimatter `.bmt` models and `.ifc` models.
4
4
 
5
5
  All about us you can see on our website [Bimatter](https://bimatter.ru/)
6
6
 
7
- Vanila js viewer core: [bimatter-viewer](https://www.npmjs.com/package/bimatter-viewer?activeTab=code)
7
+ [Demo viewer](https://rkaeplive.github.io/bimatter-viewer-react/)
8
8
 
9
9
  [GitHub](https://github.com/rkaeplive/bimatter-viewer-react)
10
10
 
11
+ Vanila js viewer core: [bimatter-viewer](https://www.npmjs.com/package/bimatter-viewer?activeTab=code)
12
+
11
13
  Write your issuse here: [GitHub](https://github.com/rkaeplive/bimatter-viewer-react/issues)
12
14
 
13
15
  ## License
@@ -175,7 +177,7 @@ function App() {
175
177
 
176
178
  `Shift + Left Click` - Multi-select element
177
179
 
178
- `Ctrl + Left Click` - Unselect element
180
+ `Ctrl + Left Click` - Toggle element selection
179
181
 
180
182
  `Shift + Drag Right` - Select elements fully inside rectangle
181
183
 
@@ -193,10 +195,16 @@ function App() {
193
195
 
194
196
  `I` - Isolate selected elements
195
197
 
196
- # Viewer API:
198
+ ### Clipping
199
+
200
+ `P` - Create clipping plane by model intersection
201
+
202
+ ## Viewer API
197
203
 
198
204
  ```ts
199
205
  viewerRef.current?.camera.fitCamera();
206
+ viewerRef.current?.camera.getIntersection();
207
+ viewerRef.current?.camera.getIntersection(true);
200
208
 
201
209
  viewerRef.current?.geometryUtils.showAll();
202
210
  viewerRef.current?.geometryUtils.showByIds([1, 2, 3]);
@@ -212,10 +220,30 @@ viewerRef.current?.selector.addSelected(0, [30]);
212
220
  viewerRef.current?.selector.removeSelected(0, [10]);
213
221
  viewerRef.current?.selector.resetSelection();
214
222
  viewerRef.current?.selector.getSelected();
223
+ viewerRef.current?.selector.setSelectionColor("#1194bd");
224
+ viewerRef.current?.selector.getSelectionColor();
225
+ viewerRef.current?.selector.setPreselectionColor("#68c6e3");
226
+ viewerRef.current?.selector.getPreselectionColor();
227
+
228
+ viewerRef.current?.colors.setColor(0, [10, 20], "#ff3355");
229
+ viewerRef.current?.colors.clearColor(0, [10]);
230
+ viewerRef.current?.colors.clearModelColors(0);
231
+ viewerRef.current?.colors.clearAllColors();
232
+
233
+ viewerRef.current?.clipping.createPlane();
234
+ viewerRef.current?.clipping.createClippingRectangle();
235
+ viewerRef.current?.clipping.toggle();
236
+ viewerRef.current?.clipping.setActive(true);
237
+ viewerRef.current?.clipping.setEdgesActive(true);
238
+ viewerRef.current?.clipping.setHelpersActive(true);
239
+ viewerRef.current?.clipping.deleteAllPlanes();
215
240
 
216
241
  viewerRef.current?.properties.getModelProps();
217
242
  viewerRef.current?.properties.getModelStructure();
218
243
  viewerRef.current?.utils.getUserDevice();
244
+ viewerRef.current?.utils.getDefaultHotkeysEnabled();
245
+ viewerRef.current?.utils.setDefaultHotkeysEnabled(false);
246
+ viewerRef.current?.utils.toggleDefaultHotkeys();
219
247
  viewerRef.current?.utils.getShowStats();
220
248
  viewerRef.current?.utils.setShowStats(true);
221
249
  viewerRef.current?.utils.getShowNavCube();
@@ -267,6 +295,54 @@ function App() {
267
295
  }
268
296
  ```
269
297
 
298
+ ## Colorize Elements
299
+
300
+ Use `viewerRef.current.colors` to apply temporary color overrides to model elements. The color is applied by `modelID` and element ids:
301
+
302
+ ```tsx
303
+ viewerRef.current?.colors.setColor(0, [10, 20, 30], "#ff3355");
304
+ viewerRef.current?.colors.clearColor(0, [10, 20]);
305
+ viewerRef.current?.colors.clearModelColors(0);
306
+ viewerRef.current?.colors.clearAllColors();
307
+ ```
308
+
309
+ Example with current selection:
310
+
311
+ ```tsx
312
+ import { useRef, useState } from "react";
313
+ import {
314
+ Viewer,
315
+ type ViewerApi,
316
+ type ViewerSelection,
317
+ } from "bimatter-viewer-react";
318
+
319
+ function App() {
320
+ const viewerRef = useRef<ViewerApi>(null);
321
+ const [selected, setSelected] = useState<ViewerSelection>({});
322
+
323
+ function colorizeSelected() {
324
+ Object.entries(selected).forEach(([modelID, ids]) => {
325
+ viewerRef.current?.colors.setColor(Number(modelID), ids, "#ff3355");
326
+ });
327
+ }
328
+
329
+ return (
330
+ <>
331
+ <button onClick={colorizeSelected}>Colorize selected</button>
332
+ <button onClick={() => viewerRef.current?.colors.clearAllColors()}>
333
+ Clear colors
334
+ </button>
335
+ <Viewer
336
+ ref={viewerRef}
337
+ modelUrls={["/models/model.bmt"]}
338
+ selected={selected}
339
+ onSelectedChange={setSelected}
340
+ />
341
+ </>
342
+ );
343
+ }
344
+ ```
345
+
270
346
  ## Controlled Selection
271
347
 
272
348
  Selection can be controlled by your app state, including Zustand, Redux, or local React state.
@@ -0,0 +1,28 @@
1
+ import { type Intersection, type Object3D, type Plane, type Vector3 } from "three";
2
+ import type { ViewerModelRef } from "../types";
3
+ export declare const CLIPPING_PLANE_EPSILON = 0.000001;
4
+ export type CameraClippingSource = {
5
+ getActive: () => boolean;
6
+ getPlanes: () => Plane[];
7
+ };
8
+ export type CameraIntersectionOptions = {
9
+ event?: MouseEvent | PointerEvent;
10
+ filter?: (intersection: Intersection<Object3D>) => boolean;
11
+ object?: Object3D | Object3D[] | null;
12
+ recursive?: boolean;
13
+ respectClipping?: boolean;
14
+ };
15
+ export type ViewerCameraGetIntersection = {
16
+ (first: true): Intersection<Object3D> | null;
17
+ (first?: false): Intersection<Object3D>[];
18
+ };
19
+ export type CameraUtilsApi = {
20
+ getActiveClippingPlanes: () => Plane[];
21
+ getIntersection: {
22
+ (first: true, options?: CameraIntersectionOptions): Intersection<Object3D> | null;
23
+ (first?: false, options?: CameraIntersectionOptions): Intersection<Object3D>[];
24
+ };
25
+ setClippingSource: (source: CameraClippingSource | null) => void;
26
+ };
27
+ export declare function isPointVisibleByClippingPlanes(point: Vector3, planes: Plane[]): boolean;
28
+ export default function useCameraUtils(modelRef: ViewerModelRef): CameraUtilsApi;
@@ -1,5 +1,5 @@
1
1
  import pako from "pako";
2
- import type { ModelGridsData } from "../ModelGrids";
2
+ import type { ModelGridsData } from "../utils/ModelGrids";
3
3
  export type BmtIndexArray = Uint16Array | Uint32Array;
4
4
  export interface BmtMaterialData {
5
5
  r: number;
@@ -1,5 +1,5 @@
1
1
  import { IfcAPI } from "web-ifc";
2
- import type { ModelGridData } from "../../ModelGrids";
2
+ import type { ModelGridData } from "../../utils/ModelGrids";
3
3
  type IfcRawValue = boolean | null | number | string | undefined | IfcRawValue[] | {
4
4
  value: IfcRawValue;
5
5
  };
package/lib/Model.d.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  import type { BmtModelData } from "./Loaders/BmtLoader";
2
- import { Matrix4 } from "three";
2
+ import { Matrix4, type DataTexture } from "three";
3
3
  type ModelProps = {
4
+ colorPaletteTexture: DataTexture;
4
5
  coordinationMatrix?: Matrix4 | null;
5
6
  modelID: number;
6
7
  data: BmtModelData;
7
8
  };
9
+ export declare function parseModelMatrix(matrix?: string): Matrix4 | null;
8
10
  export declare function getModelCoordinationMatrix(data: BmtModelData): Matrix4 | null;
9
- declare function Model({ coordinationMatrix, modelID, data }: ModelProps): import("react/jsx-runtime").JSX.Element;
10
- export default Model;
11
+ export declare function getModelCoordinationMatrixSource(data: BmtModelData): string | undefined;
12
+ declare function Model({ colorPaletteTexture, coordinationMatrix, modelID, data, }: ModelProps): import("react/jsx-runtime").JSX.Element;
13
+ declare const _default: import("react").MemoExoticComponent<typeof Model>;
14
+ export default _default;
@@ -1,10 +1,11 @@
1
1
  import React from "react";
2
- import { Matrix4 } from "three";
2
+ import { Matrix4, type DataTexture } from "three";
3
3
  import type { BmtGeomData, BmtMaterialData } from "./Loaders/BmtLoader";
4
4
  type SelectableMeshProps = {
5
+ colorPaletteTexture: DataTexture;
5
6
  data: BmtGeomData;
6
7
  material: BmtMaterialData;
7
8
  meshMatrix: Matrix4;
8
9
  };
9
- export declare const SelectableMesh: React.MemoExoticComponent<({ material, data, meshMatrix, }: SelectableMeshProps) => import("react/jsx-runtime").JSX.Element>;
10
+ export declare const SelectableMesh: React.MemoExoticComponent<({ colorPaletteTexture, material, data, meshMatrix, }: SelectableMeshProps) => import("react/jsx-runtime").JSX.Element>;
10
11
  export {};
@@ -1,5 +1,5 @@
1
1
  import type { MutableRefObject } from "react";
2
- import { Camera, Object3D, Vector2 } from "three";
2
+ import { Camera, Object3D, Vector2, type Plane } from "three";
3
3
  export type ClientRectSelection = {
4
4
  minX: number;
5
5
  minY: number;
@@ -34,9 +34,10 @@ export type SelectionBoxProfile = {
34
34
  export declare const MIN_BOX_SIZE = 6;
35
35
  export declare function getClientSelectionRect(start: Vector2, end: Vector2): ClientRectSelection;
36
36
  export declare function getSelectionBoxMode(start: Vector2, end: Vector2): SelectionBoxMode;
37
- export declare function getBoxSelectedIds({ model, camera, domElement, rect, mode, profile, }: {
37
+ export declare function getBoxSelectedIds({ model, camera, clippingPlanes, domElement, rect, mode, profile, }: {
38
38
  model: Object3D | null;
39
39
  camera: Camera;
40
+ clippingPlanes?: Plane[];
40
41
  domElement: HTMLElement;
41
42
  rect: ClientRectSelection;
42
43
  mode: SelectionBoxMode;
@@ -1,3 +1,3 @@
1
- import type { GeometryIndexApi } from "../GeometryUtils/useGeometryIndex";
1
+ import type { CameraUtilsApi } from "../Camera/useCameraUtils";
2
2
  import type { ViewerControlsRef, ViewerModelRef } from "../types";
3
- export default function useSelector(modelRef: ViewerModelRef, controlRef: ViewerControlsRef, geometryIndex: GeometryIndexApi): void;
3
+ export default function useSelector(modelRef: ViewerModelRef, controlRef: ViewerControlsRef, cameraUtils: CameraUtilsApi): void;
@@ -1,5 +1,10 @@
1
+ import type { ColorRepresentation } from "three";
1
2
  import type { SelectedStore, UserDevice, ViewerGridAxesVisibility, ViewerGridAxisSide, ViewerStoreApi } from "../store/ViewerStore";
2
3
  import { type ViewerPropertiesApi } from "./ViewerPropertiesApi";
4
+ import type { ViewerClippingApi } from "../utils/ClippingUtils";
5
+ import type { ViewerCameraGetIntersection } from "../Camera/useCameraUtils";
6
+ export type { ViewerClippingApi } from "../utils/ClippingUtils";
7
+ export type { ViewerCameraGetIntersection } from "../Camera/useCameraUtils";
3
8
  export type ViewerSelection = Record<number, number[]>;
4
9
  export type ViewerGeometryUtilsApi = {
5
10
  getAllIds: () => number[];
@@ -13,19 +18,32 @@ export type ViewerGeometryUtilsApi = {
13
18
  };
14
19
  export type ViewerSelectorApi = {
15
20
  addSelected: (modelID: number, ids: number[]) => void;
21
+ getPreselectionColor: () => ColorRepresentation;
22
+ getSelectionColor: () => ColorRepresentation;
16
23
  getSelected: () => ViewerSelection;
17
24
  removeSelected: (modelID: number, ids: number[]) => void;
18
25
  resetSelection: (modelID?: number) => void;
26
+ setPreselectionColor: (color: ColorRepresentation) => void;
27
+ setSelectionColor: (color: ColorRepresentation) => void;
19
28
  setSelected: (modelID: number, ids: number[], reset?: boolean) => void;
20
29
  };
30
+ export type ViewerColorsApi = {
31
+ clearAllColors: () => void;
32
+ clearColor: (modelID: number, ids: number[]) => void;
33
+ clearModelColors: (modelID: number) => void;
34
+ setColor: (modelID: number, ids: number[], color: ColorRepresentation) => void;
35
+ };
21
36
  export type ViewerUtilsApi = {
37
+ getDefaultHotkeysEnabled: () => boolean;
22
38
  getGridAxesVisibility: () => ViewerGridAxesVisibility;
23
39
  getShowNavCube: () => boolean;
24
40
  getShowGridAxes: () => boolean;
25
41
  getShowStats: () => boolean;
26
42
  getUserDevice: () => UserDevice;
27
43
  setGridAxesVisibility: (gridAxesVisibility: Partial<ViewerGridAxesVisibility>) => void;
44
+ setDefaultHotkeysEnabled: (enabled: boolean) => void;
28
45
  setGridAxisVisibility: (side: ViewerGridAxisSide, visible: boolean) => void;
46
+ toggleDefaultHotkeys: () => void;
29
47
  setShowNavCube: (showNavCube: boolean) => void;
30
48
  setShowGridAxes: (showGridAxes: boolean) => void;
31
49
  setShowStats: (showStats: boolean) => void;
@@ -34,9 +52,12 @@ export type ViewerUtilsApi = {
34
52
  };
35
53
  export type ViewerCameraApi = {
36
54
  fitCamera: () => void;
55
+ getIntersection: ViewerCameraGetIntersection;
37
56
  };
38
57
  export type ViewerApi = {
39
58
  camera: ViewerCameraApi;
59
+ clipping: ViewerClippingApi;
60
+ colors: ViewerColorsApi;
40
61
  geometryUtils: ViewerGeometryUtilsApi;
41
62
  properties: ViewerPropertiesApi;
42
63
  selector: ViewerSelectorApi;
@@ -44,6 +65,8 @@ export type ViewerApi = {
44
65
  };
45
66
  export type ViewerSceneApi = {
46
67
  camera: ViewerCameraApi;
68
+ clipping: ViewerClippingApi;
69
+ colors: ViewerColorsApi;
47
70
  geometryUtils: ViewerGeometryUtilsApi;
48
71
  };
49
72
  export declare function serializeSelected(selected: SelectedStore): ViewerSelection;
@@ -5,10 +5,13 @@ declare class ViewerLoaderApi {
5
5
  coordinationMatrix: string | undefined;
6
6
  private bmtLoader;
7
7
  private ifcLoader;
8
+ private loadedModelCount;
9
+ private nextModelID;
8
10
  private initLoaders;
9
11
  private getBmtLoader;
10
12
  private getIfcLoader;
11
13
  private loadBmtModel;
14
+ private resetCoordinationMatrixState;
12
15
  resetCoordinationMatrix(): void;
13
16
  loadModel(sources: ViewerModelSource | ViewerModelSource[]): Promise<ViewerLoadedModels>;
14
17
  }
package/lib/index.d.ts CHANGED
@@ -1,16 +1,16 @@
1
1
  export { default as Viewer } from "./Viewer";
2
2
  export type { ViewerModelsData, ViewerProps } from "./Viewer";
3
- export type { ViewerApi, ViewerCameraApi, ViewerGeometryUtilsApi, ViewerSelection, ViewerSelectorApi, ViewerUtilsApi, } from "./api/ViewerApi";
3
+ export type { ViewerApi, ViewerCameraApi, ViewerCameraGetIntersection, ViewerClippingApi, ViewerColorsApi, ViewerGeometryUtilsApi, ViewerSelection, ViewerSelectorApi, ViewerUtilsApi, } from "./api/ViewerApi";
4
4
  export type { ViewerPropertiesApi } from "./api/ViewerPropertiesApi";
5
5
  export { BMTLoader } from "./Loaders/BmtLoader";
6
6
  export type { BmtModelGeometryData, BmtGeomData, BmtIndexArray, BmtMaterialData, BmtElementProps, BmtModelData, BmtModelProps, BmtModelStructure, BmtModelStructureNode, BmtPropertyRecord, BmtPropertySet, BmtPropertyValue, } from "./Loaders/BmtLoader";
7
7
  export { IFCLoader } from "./Loaders/IFCLoader/IFCLoader";
8
8
  export type { IfcLoadedModels, IfcModelSource, } from "./Loaders/IFCLoader/IFCLoader";
9
- export { ModelGrids } from "./ModelGrids";
10
- export type { ModelGridAxis, ModelGridData, ModelGridPoint, ModelGridsProps, ModelGridsData, } from "./ModelGrids";
9
+ export { ModelGrids } from "./utils/ModelGrids";
10
+ export type { ModelGridAxis, ModelGridData, ModelGridPoint, ModelGridsProps, ModelGridsData, } from "./utils/ModelGrids";
11
11
  export { loader } from "./api/loader";
12
12
  export type { ViewerLoadedModels, ViewerModelSource } from "./api/loader";
13
- export { NavigationCube } from "./NavigationCube";
13
+ export { NavigationCube } from "./utils/NavigationCube";
14
14
  export { createViewerStore } from "./store/ViewerStore";
15
15
  export { ViewerStoreProvider } from "./store/ViewerStoreProvider";
16
16
  export { useViewerStore, useViewerStoreApi } from "./store/useViewerStore";