@reearth/core 0.0.7-alpha.22 → 0.0.7-alpha.24

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.d.ts CHANGED
@@ -548,7 +548,7 @@ export declare type EngineRef = {
548
548
  isPositionVisible: (position: [x: number, y: number, z: number]) => boolean;
549
549
  setView: (camera: CameraPosition) => void;
550
550
  toWindowPosition: (position: [x: number, y: number, z: number]) => [x: number, y: number] | undefined;
551
- getExtrudedHeight: (position: [x: number, y: number, z: number], windowPosition: [x: number, y: number]) => number | undefined;
551
+ getExtrudedHeight: (position: [x: number, y: number, z: number], windowPosition: [x: number, y: number], allowNegative?: boolean) => number | undefined;
552
552
  getExtrudedPoint: (position: [x: number, y: number, z: number], extrutedHeight: number) => Position3d | undefined;
553
553
  getSurfaceDistance: (point1: Cartesian3, point2: Cartesian3) => number | undefined;
554
554
  equalsEpsilon2d: (point1: Position2d, point2: Position2d, relativeEpsilon: number | undefined, absoluteEpsilon: number | undefined) => boolean;
@@ -859,7 +859,7 @@ declare type InfoboxProperty = {
859
859
 
860
860
  export declare const INTERACTION_MODES: Record<InteractionModeType, number>;
861
861
 
862
- export declare type InteractionModeType = "default" | "move" | "selection" | "sketch";
862
+ export declare type InteractionModeType = "default" | "move" | "selection" | "sketch" | "spatialId";
863
863
 
864
864
  export declare function isSketchType(value: unknown): value is SketchType;
865
865
 
@@ -1102,6 +1102,7 @@ export declare type MapRef = {
1102
1102
  engine: WrappedRef<EngineRef>;
1103
1103
  layers: WrappedRef<LayersRef>;
1104
1104
  sketch: WrappedRef<SketchRef>;
1105
+ spatialId?: WrappedRef<SpatialIdRef>;
1105
1106
  timeline?: TimelineManagerRef;
1106
1107
  };
1107
1108
 
@@ -1291,6 +1292,7 @@ export declare type PolygonAppearance = {
1291
1292
  stroke?: boolean;
1292
1293
  strokeColor?: string;
1293
1294
  strokeWidth?: number;
1295
+ height?: number;
1294
1296
  heightReference?: "none" | "clamp" | "relative";
1295
1297
  shadows?: "disabled" | "enabled" | "cast_only" | "receive_only";
1296
1298
  lineJoin?: CanvasLineJoin;
@@ -1595,6 +1597,42 @@ export declare type Spacing = {
1595
1597
  top: number;
1596
1598
  };
1597
1599
 
1600
+ declare type SpatialIdPickSpaceOptions = {
1601
+ zoom?: number;
1602
+ maxHeight?: number;
1603
+ color?: string;
1604
+ dataOnly?: boolean;
1605
+ rightClickToExit?: boolean;
1606
+ };
1607
+
1608
+ declare type SpatialIdRef = {
1609
+ pickSpace: (options?: SpatialIdPickSpaceOptions) => void;
1610
+ exitPickSpace: () => void;
1611
+ onSpacePick: (cb: (space: SpatialIdSpaceData) => void) => void;
1612
+ };
1613
+
1614
+ declare type SpatialIdSpaceData = {
1615
+ id: string;
1616
+ center: {
1617
+ lat: number;
1618
+ lng: number;
1619
+ alt?: number;
1620
+ };
1621
+ alt: number;
1622
+ zoom: number;
1623
+ zfxy: {
1624
+ z: number;
1625
+ f: number;
1626
+ x: number;
1627
+ y: number;
1628
+ };
1629
+ zfxyStr: string;
1630
+ tilehash: string;
1631
+ hilbertTilehash: string;
1632
+ hilbertIndex: string;
1633
+ vertices: [number, number, number][];
1634
+ };
1635
+
1598
1636
  export declare type StyleExpression = ConditionsExpression | string;
1599
1637
 
1600
1638
  export declare type SunProperty = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reearth/core",
3
- "version": "0.0.7-alpha.22",
3
+ "version": "0.0.7-alpha.24",
4
4
  "author": "Re:Earth contributors <community@reearth.io>",
5
5
  "license": "Apache-2.0",
6
6
  "description": "A library that abstracts a map engine as one common API.",
@@ -38,12 +38,14 @@
38
38
  "@radix-ui/react-icons": "1.3.0",
39
39
  "@radix-ui/react-select": "2.1.1",
40
40
  "@radix-ui/react-separator": "1.1.0",
41
+ "@radix-ui/react-slider": "1.2.2",
41
42
  "@radix-ui/react-slot": "1.1.0",
42
43
  "@radix-ui/react-switch": "1.1.0",
43
44
  "@radix-ui/react-toggle": "1.1.0",
44
45
  "@reearth/cesium-mvt-imagery-provider": "1.5.4",
45
46
  "@rot1024/use-transition": "1.0.0",
46
47
  "@seznam/compose-react-refs": "1.0.6",
48
+ "@spatial-id/javascript-sdk": "https://github.com/spatial-id/javascript-sdk",
47
49
  "@turf/invariant": "6.5.0",
48
50
  "@turf/turf": "6.5.0",
49
51
  "@types/proj4": "2.5.5",
@@ -71,6 +71,7 @@ export default function ({
71
71
  ref,
72
72
  engineRef,
73
73
  layersRef,
74
+ interactionMode,
74
75
  selectedFeature,
75
76
  overrideInteractionMode,
76
77
  onSketchTypeChange,
@@ -333,6 +334,7 @@ export default function ({
333
334
  useWindowEvent("keydown", event => {
334
335
  if (type === undefined) return;
335
336
  if (event.code === "Space") {
337
+ tempSwitchToMoveMode.current = true;
336
338
  setDisableInteraction(true);
337
339
  overrideInteractionMode?.("move");
338
340
  } else {
@@ -360,6 +362,9 @@ export default function ({
360
362
  if (event.code === "Space") {
361
363
  overrideInteractionMode?.("sketch");
362
364
  setDisableInteraction(false);
365
+ if (tempSwitchToMoveMode.current) {
366
+ tempSwitchToMoveMode.current = false;
367
+ }
363
368
  }
364
369
  });
365
370
 
@@ -376,9 +381,17 @@ export default function ({
376
381
  overrideInteractionModeRef.current = overrideInteractionMode;
377
382
  const onSketchTypeChangeRef = useRef(onSketchTypeChange);
378
383
  onSketchTypeChangeRef.current = onSketchTypeChange;
384
+ const interactionModeRef = useRef(interactionMode);
385
+ interactionModeRef.current = interactionMode;
379
386
 
380
387
  useEffect(() => {
381
- overrideInteractionModeRef.current?.(type || sketchEditingFeature ? "sketch" : "default");
388
+ overrideInteractionModeRef.current?.(
389
+ type || sketchEditingFeature
390
+ ? "sketch"
391
+ : interactionModeRef.current === "sketch"
392
+ ? "default"
393
+ : interactionModeRef.current,
394
+ );
382
395
  }, [type, sketchEditingFeature]);
383
396
 
384
397
  const isEditingRef = useRef(isEditing);
@@ -393,6 +406,19 @@ export default function ({
393
406
  }
394
407
  }, [type]);
395
408
 
409
+ const typeRef = useRef(type);
410
+ typeRef.current = type;
411
+ useEffect(() => {
412
+ if (tempSwitchToMoveMode.current) return;
413
+ if (interactionMode !== "sketch") {
414
+ if (isEditingRef.current) {
415
+ cancelEditRef.current();
416
+ } else if (typeRef.current !== undefined) {
417
+ updateType(undefined);
418
+ }
419
+ }
420
+ }, [interactionMode, updateType]);
421
+
396
422
  // Edit
397
423
  const onEditFeatureChangeCbs = useRef<SketchEditFeatureChangeCb[]>([]);
398
424
  const onEditFeatureChange = useCallback((cb: SketchEditFeatureChangeCb) => {
@@ -569,8 +595,8 @@ export default function ({
569
595
  useEffect(() => {
570
596
  return window.addEventListener("keydown", event => {
571
597
  if (event.code === "Space" && stateRef.current.matches("editing")) {
572
- overrideInteractionMode?.("move");
573
598
  tempSwitchToMoveMode.current = true;
599
+ overrideInteractionMode?.("move");
574
600
  } else if (event.code === "Delete" && stateRef.current.matches("editing")) {
575
601
  handleDeleteControlPointRef.current();
576
602
  }
@@ -0,0 +1,293 @@
1
+ import {
2
+ ForwardedRef,
3
+ useCallback,
4
+ useEffect,
5
+ useImperativeHandle,
6
+ useMemo,
7
+ useRef,
8
+ useState,
9
+ } from "react";
10
+ import { RefObject } from "use-callback-ref/dist/es5/types";
11
+
12
+ import { InteractionModeType } from "../../Visualizer";
13
+ import { EngineRef, MouseEventProps } from "../types";
14
+
15
+ import {
16
+ SpatialIdRef,
17
+ SpatialIdSpacePickingState,
18
+ SpatialIdSpaceType,
19
+ SpatialIdSpaceData,
20
+ SpatialIdPickSpaceOptions,
21
+ } from "./types";
22
+ import { createSpatialIdFloorSpaces, createSpatialIdSpace, getSpaceData } from "./utils";
23
+
24
+ type Props = {
25
+ ref: ForwardedRef<SpatialIdRef>;
26
+ engineRef: RefObject<EngineRef>;
27
+ terrainEnabled?: boolean;
28
+ interactionMode?: InteractionModeType;
29
+ overrideInteractionMode?: (mode: InteractionModeType) => void;
30
+ onMount?: () => void;
31
+ };
32
+
33
+ export const SPATIALID_DEFAULT_ZOOM = 20;
34
+ export const SPATIALID_DEFAULT_MAX_HEIGHT = 1000;
35
+ export const SPATIALID_DEFAULT_COLOR = "#00bebe";
36
+ export const SPATIALID_DEFAULT_DATA_ONLY = false;
37
+ export const SPATIALID_DEFAULT_RIGHT_CLICK_TO_EXIT = true;
38
+
39
+ export default ({
40
+ ref,
41
+ engineRef,
42
+ terrainEnabled,
43
+ interactionMode,
44
+ overrideInteractionMode,
45
+ onMount,
46
+ }: Props) => {
47
+ const [state, setState] = useState<SpatialIdSpacePickingState>("idle");
48
+
49
+ const [spatialIdSpaces, setSpatialIdSpaces] = useState<SpatialIdSpaceType[]>([]);
50
+ const [floorSpaces, setFloorSpaces] = useState<SpatialIdSpaceType[]>([]);
51
+ const [selectorSpace, setSelectorSpace] = useState<SpatialIdSpaceType | null>(null);
52
+
53
+ const spaces = useMemo(() => {
54
+ return [...spatialIdSpaces, ...floorSpaces, ...(selectorSpace ? [selectorSpace] : [])];
55
+ }, [spatialIdSpaces, floorSpaces, selectorSpace]);
56
+
57
+ const [basePosition, setBasePosition] = useState<[number, number, number] | null>(null);
58
+ const [baseCoordinate, setBaseCoordinate] = useState<[number, number, number] | null>(null);
59
+
60
+ const [pickOptions, setPickOptions] = useState<Required<SpatialIdPickSpaceOptions>>({
61
+ zoom: SPATIALID_DEFAULT_ZOOM,
62
+ maxHeight: SPATIALID_DEFAULT_MAX_HEIGHT,
63
+ color: SPATIALID_DEFAULT_COLOR,
64
+ dataOnly: SPATIALID_DEFAULT_DATA_ONLY,
65
+ rightClickToExit: SPATIALID_DEFAULT_RIGHT_CLICK_TO_EXIT,
66
+ });
67
+
68
+ const pickSpace = useCallback(
69
+ (options?: SpatialIdPickSpaceOptions) => {
70
+ setState("coordinate");
71
+ setPickOptions(prev => ({ ...prev, ...options }));
72
+ overrideInteractionMode?.("spatialId");
73
+ },
74
+ [overrideInteractionMode],
75
+ );
76
+
77
+ const interactionModeRef = useRef(interactionMode);
78
+ interactionModeRef.current = interactionMode;
79
+
80
+ const finishPicking = useCallback(() => {
81
+ setState("idle");
82
+ setSelectorSpace(null);
83
+ setBasePosition(null);
84
+ setBaseCoordinate(null);
85
+ setFloorSpaces([]);
86
+ overrideInteractionMode?.(
87
+ interactionModeRef.current === "spatialId"
88
+ ? "default"
89
+ : interactionModeRef.current ?? "default",
90
+ );
91
+ engineRef.current?.requestRender();
92
+ }, [overrideInteractionMode, engineRef]);
93
+
94
+ // handle events
95
+ const handleMouseUp = useCallback(
96
+ (props: MouseEventProps) => {
97
+ if (state === "idle") return;
98
+ if (tempSwitchToMoveMode.current) return;
99
+
100
+ if (state === "coordinate") {
101
+ if (!selectorSpace || props.lat === undefined || props.lng === undefined) return;
102
+ setState("floor");
103
+ setBaseCoordinate([props.lng, props.lat, terrainEnabled ? props.height ?? 0 : 0]);
104
+ setBasePosition(
105
+ engineRef.current?.toXYZ(props.lng, props.lat, props.height ?? 0, {
106
+ useGlobeEllipsoid: !terrainEnabled,
107
+ }) ?? null,
108
+ );
109
+
110
+ setSelectorSpace(prev =>
111
+ prev ? { ...prev, type: "selector", color: pickOptions.color } : null,
112
+ );
113
+
114
+ const floorSpaces = createSpatialIdFloorSpaces(
115
+ selectorSpace.space,
116
+ pickOptions.maxHeight,
117
+ pickOptions.color,
118
+ );
119
+ setFloorSpaces(floorSpaces);
120
+ } else if (state === "floor") {
121
+ if (!selectorSpace) return;
122
+
123
+ const confirmedSpace: SpatialIdSpaceType = {
124
+ ...selectorSpace,
125
+ type: "confirmed",
126
+ color: pickOptions.color,
127
+ };
128
+
129
+ if (!pickOptions.dataOnly) {
130
+ setSpatialIdSpaces(prev => [...prev, confirmedSpace]);
131
+ }
132
+
133
+ finishPicking();
134
+
135
+ const spaceData = getSpaceData(confirmedSpace.space);
136
+ onSpacePickEvents.current.forEach(cb => cb(spaceData));
137
+ }
138
+ },
139
+ [state, terrainEnabled, engineRef, selectorSpace, pickOptions, finishPicking],
140
+ );
141
+
142
+ const handleMouseMove = useCallback(
143
+ (props: MouseEventProps) => {
144
+ if (state === "idle") return;
145
+ if (tempSwitchToMoveMode.current) return;
146
+
147
+ if (state === "coordinate") {
148
+ if (props.lat === undefined || props.lng === undefined) return;
149
+
150
+ const newSpace = createSpatialIdSpace(
151
+ props.lng,
152
+ props.lat,
153
+ terrainEnabled ? props.height ?? 0 : 0,
154
+ pickOptions.zoom,
155
+ );
156
+
157
+ if (newSpace.space.id === selectorSpace?.space.id) return;
158
+
159
+ setSelectorSpace({ ...newSpace, type: "coordinate", color: pickOptions.color });
160
+ } else if (state === "floor") {
161
+ if (
162
+ props.x === undefined ||
163
+ props.y === undefined ||
164
+ basePosition === null ||
165
+ baseCoordinate === null
166
+ )
167
+ return;
168
+
169
+ const height =
170
+ engineRef.current?.getExtrudedHeight(basePosition, [props.x, props.y], true) ?? 0;
171
+
172
+ if (baseCoordinate[2] + height > pickOptions.maxHeight) return;
173
+
174
+ const newSpace = createSpatialIdSpace(
175
+ baseCoordinate[0],
176
+ baseCoordinate[1],
177
+ baseCoordinate[2] + height,
178
+ pickOptions.zoom,
179
+ );
180
+
181
+ if (newSpace.space.id === selectorSpace?.space.id || newSpace.space.zfxy.f < 0) return;
182
+
183
+ setSelectorSpace({ ...newSpace, type: "selector", color: pickOptions.color });
184
+ }
185
+ },
186
+ [state, selectorSpace, basePosition, baseCoordinate, engineRef, terrainEnabled, pickOptions],
187
+ );
188
+
189
+ const handleMouseRightClick = useCallback(() => {
190
+ if (state === "idle") return;
191
+ if (state === "coordinate" && pickOptions.rightClickToExit) {
192
+ finishPicking();
193
+ } else if (state === "floor") {
194
+ setSelectorSpace(null);
195
+ setBasePosition(null);
196
+ setBaseCoordinate(null);
197
+ setFloorSpaces([]);
198
+ setState("coordinate");
199
+ }
200
+ engineRef.current?.requestRender();
201
+ }, [state, pickOptions, engineRef, finishPicking]);
202
+
203
+ // bind mouse events
204
+ const eventsBinded = useRef(false);
205
+
206
+ const handleMouseUpRef = useRef(handleMouseUp);
207
+ handleMouseUpRef.current = handleMouseUp;
208
+ const handleMouseUpForRef = useCallback((props: MouseEventProps) => {
209
+ handleMouseUpRef.current(props);
210
+ }, []);
211
+
212
+ const handleMouseMoveRef = useRef(handleMouseMove);
213
+ handleMouseMoveRef.current = handleMouseMove;
214
+ const handleMouseMoveForRef = useCallback((props: MouseEventProps) => {
215
+ handleMouseMoveRef.current(props);
216
+ }, []);
217
+
218
+ const handleMouseRightClickRef = useRef(handleMouseRightClick);
219
+ handleMouseRightClickRef.current = handleMouseRightClick;
220
+ const handleMouseRightClickForRef = useCallback(() => {
221
+ handleMouseRightClickRef.current();
222
+ }, []);
223
+
224
+ useEffect(() => {
225
+ if (eventsBinded.current || !engineRef.current) return;
226
+ eventsBinded.current = true;
227
+ engineRef.current.onMouseUp(handleMouseUpForRef);
228
+ engineRef.current.onMouseMove(handleMouseMoveForRef);
229
+ engineRef.current.onRightClick(handleMouseRightClickForRef);
230
+ }, [engineRef, handleMouseUpForRef, handleMouseMoveForRef, handleMouseRightClickForRef]);
231
+
232
+ // cancel picking when interaction mode changes
233
+ const stateRef = useRef(state);
234
+ stateRef.current = state;
235
+ const finishPickingRef = useRef(finishPicking);
236
+ finishPickingRef.current = finishPicking;
237
+ useEffect(() => {
238
+ if (tempSwitchToMoveMode.current) return;
239
+ if (interactionMode !== "spatialId" && stateRef.current !== "idle") {
240
+ finishPickingRef.current();
241
+ }
242
+ }, [interactionMode]);
243
+
244
+ // events
245
+ const onSpacePickEvents = useRef<((space: SpatialIdSpaceData) => void)[]>([]);
246
+
247
+ const bindEventOnSpacePick = useCallback((cb: (space: SpatialIdSpaceData) => void) => {
248
+ onSpacePickEvents.current.push(cb);
249
+ }, []);
250
+
251
+ // ref
252
+ useImperativeHandle(
253
+ ref,
254
+ () => ({
255
+ pickSpace,
256
+ onSpacePick: bindEventOnSpacePick,
257
+ exitPickSpace: finishPicking,
258
+ }),
259
+ [pickSpace, bindEventOnSpacePick, finishPicking],
260
+ );
261
+
262
+ // press space to move
263
+ const tempSwitchToMoveMode = useRef(false);
264
+ useEffect(() => {
265
+ const handleKeydown = (e: KeyboardEvent) => {
266
+ if (e.code === "Space" && stateRef.current !== "idle") {
267
+ tempSwitchToMoveMode.current = true;
268
+ overrideInteractionMode?.("move");
269
+ }
270
+ };
271
+ window.addEventListener("keydown", handleKeydown);
272
+ return () => {
273
+ window.removeEventListener("keydown", handleKeydown);
274
+ };
275
+ }, [overrideInteractionMode]);
276
+
277
+ useEffect(() => {
278
+ return window.addEventListener("keyup", e => {
279
+ if (e.code === "Space" && tempSwitchToMoveMode.current) {
280
+ tempSwitchToMoveMode.current = false;
281
+ overrideInteractionMode?.("spatialId");
282
+ }
283
+ });
284
+ }, [overrideInteractionMode]);
285
+
286
+ useEffect(() => {
287
+ onMount?.();
288
+ }, [onMount]);
289
+
290
+ return {
291
+ spaces,
292
+ };
293
+ };
@@ -0,0 +1,36 @@
1
+ import { forwardRef, ForwardRefRenderFunction } from "react";
2
+ import { RefObject } from "use-callback-ref/dist/es5/types";
3
+
4
+ import SpatialIdSpace from "../../engines/Cesium/SpatialId";
5
+ import { InteractionModeType } from "../../Visualizer";
6
+ import { EngineRef } from "../types";
7
+
8
+ import useHooks from "./hooks";
9
+ import { SpatialIdRef } from "./types";
10
+
11
+ type SpatialIdProps = {
12
+ engineRef: RefObject<EngineRef>;
13
+ terrainEnabled?: boolean;
14
+ interactionMode?: InteractionModeType;
15
+ overrideInteractionMode?: (mode: InteractionModeType) => void;
16
+ onMount?: () => void;
17
+ };
18
+
19
+ const SpatialId: ForwardRefRenderFunction<SpatialIdRef, SpatialIdProps> = (
20
+ { engineRef, terrainEnabled, interactionMode, overrideInteractionMode, onMount },
21
+ ref,
22
+ ) => {
23
+ const { spaces } = useHooks({
24
+ ref,
25
+ engineRef,
26
+ terrainEnabled,
27
+ interactionMode,
28
+ overrideInteractionMode,
29
+ onMount,
30
+ });
31
+ return spaces.length > 0
32
+ ? spaces.map(space => <SpatialIdSpace key={space.id} space={space} />)
33
+ : null;
34
+ };
35
+
36
+ export default forwardRef(SpatialId);
@@ -0,0 +1,45 @@
1
+ import { Space } from "@spatial-id/javascript-sdk";
2
+
3
+ export type SpatialIdSpaceType = {
4
+ id: string;
5
+ space: Space;
6
+ wsen: [number, number, number, number];
7
+ height: number;
8
+ extrudedHeight: number;
9
+ type?: "selector" | "floor" | "coordinate" | "confirmed";
10
+ color?: string;
11
+ };
12
+
13
+ export type SpatialIdPickSpaceOptions = {
14
+ zoom?: number;
15
+ maxHeight?: number;
16
+ color?: string;
17
+ dataOnly?: boolean;
18
+ rightClickToExit?: boolean;
19
+ };
20
+
21
+ export type SpatialIdRef = {
22
+ pickSpace: (options?: SpatialIdPickSpaceOptions) => void;
23
+ exitPickSpace: () => void;
24
+ onSpacePick: (cb: (space: SpatialIdSpaceData) => void) => void;
25
+ };
26
+
27
+ export type SpatialIdSpacePickingState = "idle" | "coordinate" | "floor";
28
+
29
+ export type SpatialIdSpaceData = {
30
+ id: string;
31
+ center: { lat: number; lng: number; alt?: number };
32
+ alt: number;
33
+ zoom: number;
34
+ zfxy: {
35
+ z: number;
36
+ f: number;
37
+ x: number;
38
+ y: number;
39
+ };
40
+ zfxyStr: string;
41
+ tilehash: string;
42
+ hilbertTilehash: string;
43
+ hilbertIndex: string;
44
+ vertices: [number, number, number][];
45
+ };
@@ -0,0 +1,79 @@
1
+ import { Space } from "@spatial-id/javascript-sdk";
2
+ import { v4 as uuid } from "uuid";
3
+
4
+ import { SPATIALID_DEFAULT_COLOR, SPATIALID_DEFAULT_MAX_HEIGHT } from "./hooks";
5
+ import { SpatialIdSpaceType, SpatialIdSpaceData } from "./types";
6
+
7
+ const getRectangeParamsFromSpace = (space: Space) => {
8
+ const vertices = space.vertices3d();
9
+ const wsen: [number, number, number, number] = [
10
+ vertices[0][0],
11
+ vertices[1][1],
12
+ vertices[2][0],
13
+ vertices[3][1],
14
+ ];
15
+ const height = vertices[0][2];
16
+ const extrudedHeight = vertices[4][2];
17
+ return { wsen, height, extrudedHeight };
18
+ };
19
+
20
+ export const createSpatialIdSpace = (
21
+ lng: number,
22
+ lat: number,
23
+ alt: number,
24
+ zoom: number,
25
+ ): SpatialIdSpaceType => {
26
+ const space = new Space({ lat, lng, alt }, zoom);
27
+ const { wsen, height, extrudedHeight } = getRectangeParamsFromSpace(space);
28
+
29
+ return {
30
+ id: uuid(),
31
+ space,
32
+ wsen,
33
+ height,
34
+ extrudedHeight,
35
+ };
36
+ };
37
+
38
+ export const createSpatialIdFloorSpaces = (
39
+ space: Space,
40
+ maxHeight = SPATIALID_DEFAULT_MAX_HEIGHT,
41
+ color = SPATIALID_DEFAULT_COLOR,
42
+ ) => {
43
+ const floorSpaces: SpatialIdSpaceType[] = [];
44
+ const { height, extrudedHeight } = getRectangeParamsFromSpace(space);
45
+ const heightStep = extrudedHeight - height;
46
+ for (let h = 0; h < maxHeight; h += heightStep) {
47
+ const fSpace = new Space({ lat: space.center.lat, lng: space.center.lng, alt: h }, space.zoom);
48
+ const {
49
+ wsen: fWsen,
50
+ height: fHeight,
51
+ extrudedHeight: fExtrudedHeight,
52
+ } = getRectangeParamsFromSpace(fSpace);
53
+ floorSpaces.push({
54
+ id: uuid(),
55
+ space: fSpace,
56
+ wsen: fWsen,
57
+ height: fHeight,
58
+ extrudedHeight: fExtrudedHeight,
59
+ type: "floor",
60
+ color,
61
+ });
62
+ }
63
+ return floorSpaces;
64
+ };
65
+
66
+ export const getSpaceData = (space: Space): SpatialIdSpaceData => {
67
+ return {
68
+ id: space.id,
69
+ center: space.center,
70
+ alt: space.alt,
71
+ zoom: space.zoom,
72
+ zfxy: space.zfxy,
73
+ zfxyStr: space.zfxyStr,
74
+ tilehash: space.tilehash,
75
+ hilbertTilehash: space.hilbertTilehash,
76
+ hilbertIndex: space.hilbertIndex.toString(),
77
+ vertices: space.vertices3d(),
78
+ };
79
+ };
package/src/Map/hooks.ts CHANGED
@@ -3,6 +3,7 @@ import { useImperativeHandle, useRef, type Ref, useState, useCallback, useEffect
3
3
  import { SelectedFeatureInfo } from "../mantle";
4
4
 
5
5
  import { type MapRef, mapRef } from "./ref";
6
+ import { SpatialIdRef } from "./SpatialId/types";
6
7
  import type {
7
8
  EngineRef,
8
9
  LayersRef,
@@ -42,10 +43,16 @@ export default function ({
42
43
  onMount?: () => void;
43
44
  onAPIReady?: () => void;
44
45
  }) {
45
- const [mapAPIReady, setMapAPIReady] = useState({ engine: false, layers: false, sketch: false });
46
+ const [mapAPIReady, setMapAPIReady] = useState({
47
+ engine: false,
48
+ layers: false,
49
+ sketch: false,
50
+ spatialId: false,
51
+ });
46
52
  const engineRef = useRef<EngineRef>(null);
47
53
  const layersRef = useRef<LayersRef>(null);
48
54
  const sketchRef = useRef<SketchRef>(null);
55
+ const spatialIdRef = useRef<SpatialIdRef>(null);
49
56
  const requestingRenderMode = useRef<RequestingRenderMode>(NO_REQUEST_RENDER);
50
57
 
51
58
  useImperativeHandle(
@@ -55,13 +62,20 @@ export default function ({
55
62
  engineRef,
56
63
  layersRef,
57
64
  sketchRef,
65
+ spatialIdRef,
58
66
  timelineManagerRef,
59
67
  }),
60
68
  [timelineManagerRef],
61
69
  );
62
70
 
63
71
  useEffect(() => {
64
- if (onAPIReady && mapAPIReady.engine && mapAPIReady.layers && mapAPIReady.sketch) {
72
+ if (
73
+ onAPIReady &&
74
+ mapAPIReady.engine &&
75
+ mapAPIReady.layers &&
76
+ mapAPIReady.sketch &&
77
+ mapAPIReady.spatialId
78
+ ) {
65
79
  onAPIReady?.();
66
80
  }
67
81
  }, [onAPIReady, mapAPIReady]);
@@ -136,11 +150,15 @@ export default function ({
136
150
  const handleSketchMount = useCallback(() => {
137
151
  setMapAPIReady(s => ({ ...s, sketch: true }));
138
152
  }, []);
153
+ const handleSpatialIdMount = useCallback(() => {
154
+ setMapAPIReady(s => ({ ...s, spatialId: true }));
155
+ }, []);
139
156
 
140
157
  return {
141
158
  engineRef,
142
159
  layersRef,
143
160
  sketchRef,
161
+ spatialIdRef,
144
162
  selectedLayer,
145
163
  requestingRenderMode,
146
164
  handleLayerSelect,
@@ -150,5 +168,6 @@ export default function ({
150
168
  handleEngineMount,
151
169
  handleLayersMount,
152
170
  handleSketchMount,
171
+ handleSpatialIdMount,
153
172
  };
154
173
  }