@reearth/core 0.0.7-alpha.32 → 0.0.7-alpha.34

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
@@ -374,7 +374,7 @@ export declare type Credit = {
374
374
  html?: string;
375
375
  };
376
376
 
377
- declare type CursorType = "default" | "auto" | "help" | "pointer" | "grab" | "crosshair";
377
+ declare type CursorType = "default" | "auto" | "help" | "pointer" | "grab" | "crosshair" | "wait";
378
378
 
379
379
  export declare type Data = {
380
380
  type: DataType;
@@ -763,6 +763,17 @@ export declare type FrustumAppearance = {
763
763
  length?: number;
764
764
  };
765
765
 
766
+ export declare type GeoidProperty = {
767
+ server: {
768
+ url: string;
769
+ geoidProperty: string;
770
+ };
771
+ };
772
+
773
+ declare type GeoidRef = {
774
+ getGeoidHeight: (lat?: number, lng?: number) => Promise<number | undefined>;
775
+ };
776
+
766
777
  export declare type Geometry = Point | LineString | Polygon_2 | MultiPoint | MultiLineString | MultiPolygon;
767
778
 
768
779
  export declare type GeometryOptionsXYZ = {
@@ -1099,6 +1110,7 @@ export declare type MapRef = {
1099
1110
  layers: WrappedRef<LayersRef>;
1100
1111
  sketch: WrappedRef<SketchRef>;
1101
1112
  spatialId?: WrappedRef<SpatialIdRef>;
1113
+ geoid: WrappedRef<GeoidRef>;
1102
1114
  timeline?: TimelineManagerRef;
1103
1115
  };
1104
1116
 
@@ -1794,6 +1806,7 @@ export declare type ValueTypes = {
1794
1806
 
1795
1807
  export declare type ViewerProperty = {
1796
1808
  globe?: GlobeProperty;
1809
+ geoid?: GeoidProperty;
1797
1810
  terrain?: TerrainProperty;
1798
1811
  scene?: SceneProperty;
1799
1812
  tiles?: TileProperty[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reearth/core",
3
- "version": "0.0.7-alpha.32",
3
+ "version": "0.0.7-alpha.34",
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.",
@@ -0,0 +1,68 @@
1
+ import {
2
+ forwardRef,
3
+ ForwardRefRenderFunction,
4
+ useCallback,
5
+ useImperativeHandle,
6
+ useRef,
7
+ } from "react";
8
+
9
+ import { GeoidServer, GeoidRef } from "./types";
10
+
11
+ export type GeoidProps = {
12
+ geoidServer?: GeoidServer;
13
+ };
14
+
15
+ const MAX_GEOID_CACHE_SIZE = 1000;
16
+
17
+ const Geoid: ForwardRefRenderFunction<GeoidRef, GeoidProps> = ({ geoidServer }, ref) => {
18
+ const geoidCache = useRef<Map<string, number>>(new Map());
19
+
20
+ const getGeoidHeight = useCallback(
21
+ async (lng?: number, lat?: number): Promise<number | undefined> => {
22
+ if (!geoidServer?.url || !geoidServer?.geoidProperty) {
23
+ console.error("Geoid: Server is not set properly");
24
+ return Promise.resolve(undefined);
25
+ }
26
+
27
+ if (lat === undefined || lng === undefined) {
28
+ console.error("Geoid: Invalid lat or lng");
29
+ return Promise.resolve(undefined);
30
+ }
31
+
32
+ const cache = geoidCache.current.get(`${lng},${lat}`);
33
+ if (cache) return Promise.resolve(cache);
34
+
35
+ return fetch(
36
+ geoidServer.url.replace("${lng}", lng.toString()).replace("${lat}", lat.toString()),
37
+ )
38
+ .then(res => {
39
+ return res.json().then((result: any) => {
40
+ if (!result) return undefined;
41
+ const geoid = Number(result[geoidServer?.geoidProperty]);
42
+ if (!isNaN(geoid)) {
43
+ const cache = geoidCache.current;
44
+ if (cache.size > MAX_GEOID_CACHE_SIZE) {
45
+ const firstKey = cache.keys().next().value;
46
+ if (firstKey) cache.delete(firstKey);
47
+ }
48
+ cache.set(`${lng},${lat}`, geoid);
49
+ return geoid;
50
+ }
51
+ return undefined;
52
+ });
53
+ })
54
+ .catch(e => {
55
+ console.error("Failed to fetch geoid height", e);
56
+ return undefined;
57
+ });
58
+ },
59
+ [geoidServer?.url, geoidServer?.geoidProperty],
60
+ );
61
+
62
+ useImperativeHandle(ref, () => ({
63
+ getGeoidHeight,
64
+ }));
65
+ return null;
66
+ };
67
+
68
+ export default forwardRef(Geoid);
@@ -0,0 +1,8 @@
1
+ export type GeoidServer = {
2
+ url: string; // URL of the geoid server. use ${lat} ${lng} for lat/lng placeholders. Example: "https://mock.com/api/altitude?lat=${lat}&lng=${lng}"
3
+ geoidProperty: string; // TODO: support json path
4
+ };
5
+
6
+ export type GeoidRef = {
7
+ getGeoidHeight: (lat?: number, lng?: number) => Promise<number | undefined>;
8
+ };
@@ -14,3 +14,8 @@ export const SPATIALID_DEFAULT_OPTIONS: Required<SpatialIdPickSpaceOptions> = {
14
14
  verticalSpaceIndicatorColor: "#ffffff33",
15
15
  verticalSpaceIndicatorOutlineColor: "#ffffff55",
16
16
  };
17
+
18
+ export const SPATIALID_LATITUDE_RANGE = {
19
+ min: -85.0511,
20
+ max: 85.0511,
21
+ };
@@ -12,9 +12,10 @@ import { v4 as uuid } from "uuid";
12
12
 
13
13
  import { useWindowEvent } from "../../utils/use-window-event";
14
14
  import { InteractionModeType } from "../../Visualizer";
15
+ import { GeoidRef } from "../Geoid/types";
15
16
  import { EngineRef, MouseEventProps } from "../types";
16
17
 
17
- import { SPATIALID_DEFAULT_OPTIONS } from "./constants";
18
+ import { SPATIALID_DEFAULT_OPTIONS, SPATIALID_LATITUDE_RANGE } from "./constants";
18
19
  import {
19
20
  SpatialIdRef,
20
21
  SpatialIdSpacePickingState,
@@ -29,6 +30,7 @@ import { createSpatialIdSpace, getSpaceData, getVerticalLimits } from "./utils";
29
30
  type Props = {
30
31
  ref: ForwardedRef<SpatialIdRef>;
31
32
  engineRef: RefObject<EngineRef>;
33
+ geoidRef: RefObject<GeoidRef>;
32
34
  terrainEnabled?: boolean;
33
35
  interactionMode?: InteractionModeType;
34
36
  overrideInteractionMode?: (mode: InteractionModeType) => void;
@@ -38,6 +40,7 @@ type Props = {
38
40
  export default ({
39
41
  ref,
40
42
  engineRef,
43
+ geoidRef,
41
44
  terrainEnabled,
42
45
  interactionMode,
43
46
  overrideInteractionMode,
@@ -51,9 +54,12 @@ export default ({
51
54
  const [coordinateSelector, setCoordinateSelector] = useState<CoordinateSelectorType | null>(null);
52
55
  const lastCoordinateSelector = useRef<CoordinateSelectorType | null>(null);
53
56
  const [spaceSelector, setSpaceSelector] = useState<SpatialIdSpaceType | null>(null);
57
+ const centerGeoidHeightRef = useRef<number | null>(null);
54
58
 
55
59
  const [basePosition, setBasePosition] = useState<[number, number, number] | null>(null);
56
- const [baseCoordinate, setBaseCoordinate] = useState<[number, number, number] | null>(null);
60
+ const [baseCoordinateGeoid, setBaseCoordinateGeoid] = useState<[number, number, number] | null>(
61
+ null,
62
+ );
57
63
 
58
64
  const [pickOptions, setPickOptions] =
59
65
  useState<Required<SpatialIdPickSpaceOptions>>(SPATIALID_DEFAULT_OPTIONS);
@@ -67,7 +73,7 @@ export default ({
67
73
  const allSpaces = [...(spatialIdSpaces ?? []), ...(spaceSelector ? [spaceSelector] : [])];
68
74
 
69
75
  if (!allSpaces) return null;
70
- // find unique spaces by space.space.zfxy.z, space.space.zfxy.x, space.space.zfxy.y
76
+
71
77
  const uniqueSpaces = allSpaces.reduce((acc, space) => {
72
78
  if (
73
79
  !acc.find(
@@ -113,10 +119,11 @@ export default ({
113
119
  const finishPicking = useCallback(() => {
114
120
  setState("idle");
115
121
  setBasePosition(null);
116
- setBaseCoordinate(null);
122
+ setBaseCoordinateGeoid(null);
117
123
  setSpaceSelector(null);
118
124
  setCoordinateSelector(null);
119
125
  lastCoordinateSelector.current = null;
126
+ centerGeoidHeightRef.current = null;
120
127
  setVerticalSpaceIndicator(null);
121
128
  overrideInteractionMode?.(
122
129
  interactionModeRef.current === "spatialId"
@@ -128,30 +135,79 @@ export default ({
128
135
  }, [overrideInteractionMode, engineRef]);
129
136
 
130
137
  const handleMouseUp = useCallback(
131
- (props: MouseEventProps) => {
138
+ async (props: MouseEventProps) => {
132
139
  if (state === "idle") return;
133
140
  if (tempSwitchToMoveMode.current) return;
134
141
 
135
142
  // handle coordinate picking
136
143
  if (state === "coordinate") {
137
- if (!coordinateSelector || props.lat === undefined || props.lng === undefined) return;
144
+ if (
145
+ !coordinateSelector ||
146
+ props.lat === undefined ||
147
+ props.lng === undefined ||
148
+ props.lat > SPATIALID_LATITUDE_RANGE.max ||
149
+ props.lat < SPATIALID_LATITUDE_RANGE.min
150
+ )
151
+ return;
138
152
 
139
- setState("floor");
140
- setBaseCoordinate([props.lng, props.lat, terrainEnabled ? props.height ?? 0 : 0]);
141
- setBasePosition(
142
- engineRef.current?.toXYZ(props.lng, props.lat, props.height ?? 0, {
143
- useGlobeEllipsoid: !terrainEnabled,
144
- }) ?? null,
153
+ setState("fetchingGeoid");
154
+
155
+ const { id, wsen, space } = createSpatialIdSpace(
156
+ props.lng,
157
+ props.lat,
158
+ 0,
159
+ pickOptions.zoom,
160
+ 0,
145
161
  );
146
162
 
147
- lastCoordinateSelector.current = coordinateSelector;
148
- setCoordinateSelector(null);
163
+ requestAnimationFrame(() => {
164
+ engineRef.current?.setCursor("wait");
165
+ });
166
+
167
+ const [geoidHeight, centerGeoidHeight] = await Promise.all([
168
+ geoidRef.current?.getGeoidHeight(props.lng, props.lat),
169
+ geoidRef.current?.getGeoidHeight(space.center.lng, space.center.lat),
170
+ ]);
171
+
172
+ setTimeout(() => {
173
+ engineRef.current?.setCursor("crosshair");
174
+ }, 100);
175
+
176
+ if (geoidHeight === undefined && centerGeoidHeight === undefined) {
177
+ setState("coordinate");
178
+ return;
179
+ }
180
+
181
+ // In most case the geoidHeight difference between click point and center is small
182
+ // The API is not that stable, it has NaN for some points for unknown reason
183
+ // Therefore we try use one another if one is NaN
184
+ const appliedGeoidHeight = geoidHeight ?? centerGeoidHeight ?? 0;
185
+ const appliedCenterGeoidHeight = centerGeoidHeight ?? geoidHeight ?? 0;
186
+ centerGeoidHeightRef.current = appliedCenterGeoidHeight;
187
+
188
+ setVerticalSpaceIndicator({
189
+ id,
190
+ wsen,
191
+ height: verticalLimits.top + appliedCenterGeoidHeight,
192
+ extrudedHeight: verticalLimits.bottom + appliedCenterGeoidHeight,
193
+ color: pickOptions.verticalSpaceIndicatorColor,
194
+ outlineColor: pickOptions.verticalSpaceIndicatorOutlineColor,
195
+ });
196
+
197
+ setBaseCoordinateGeoid([
198
+ props.lng,
199
+ props.lat,
200
+ (terrainEnabled ? props.height ?? 0 : 0) - appliedGeoidHeight,
201
+ ]);
202
+
203
+ setBasePosition(engineRef.current?.toXYZ(props.lng, props.lat, props.height ?? 0) ?? null);
149
204
 
150
205
  const initialSpaceSelectorSpace = createSpatialIdSpace(
151
206
  props.lng,
152
207
  props.lat,
153
- terrainEnabled ? props.height ?? 0 : 0,
208
+ (terrainEnabled ? props.height ?? 0 : 0) - appliedGeoidHeight,
154
209
  pickOptions.zoom,
210
+ appliedCenterGeoidHeight,
155
211
  );
156
212
  setSpaceSelector({
157
213
  ...initialSpaceSelectorSpace,
@@ -159,21 +215,11 @@ export default ({
159
215
  outlineColor: pickOptions.outlineColor,
160
216
  });
161
217
 
162
- const { id, wsen } = createSpatialIdSpace(
163
- props.lng,
164
- props.lat,
165
- terrainEnabled ? props.height ?? 0 : 0,
166
- pickOptions.zoom,
167
- );
168
- setVerticalSpaceIndicator({
169
- id,
170
- wsen,
171
- height: verticalLimits.top,
172
- extrudedHeight: verticalLimits.bottom,
173
- color: pickOptions.verticalSpaceIndicatorColor,
174
- outlineColor: pickOptions.verticalSpaceIndicatorOutlineColor,
175
- });
218
+ lastCoordinateSelector.current = coordinateSelector;
219
+ setCoordinateSelector(null);
220
+
176
221
  engineRef.current?.requestRender();
222
+ setState("floor");
177
223
  } else if (state === "floor") {
178
224
  if (!spaceSelector) return;
179
225
 
@@ -198,6 +244,7 @@ export default ({
198
244
  state,
199
245
  terrainEnabled,
200
246
  engineRef,
247
+ geoidRef,
201
248
  spaceSelector,
202
249
  pickOptions,
203
250
  verticalLimits,
@@ -212,19 +259,22 @@ export default ({
212
259
  if (tempSwitchToMoveMode.current) return;
213
260
 
214
261
  if (state === "coordinate") {
215
- if (props.lat === undefined || props.lng === undefined) return;
262
+ if (
263
+ props.lat === undefined ||
264
+ props.lng === undefined ||
265
+ props.lat > SPATIALID_LATITUDE_RANGE.max ||
266
+ props.lat < SPATIALID_LATITUDE_RANGE.min
267
+ )
268
+ return;
216
269
 
217
- const newSpace = createSpatialIdSpace(
218
- props.lng,
219
- props.lat,
220
- terrainEnabled ? props.height ?? 0 : 0,
221
- pickOptions.zoom,
222
- );
270
+ // Coordinate Selector is clamp to ground, we can ignore height
271
+ // The space id is used to identify the selector only
272
+ const newSpace = createSpatialIdSpace(props.lng, props.lat, 0, pickOptions.zoom, 0);
223
273
 
224
- if (newSpace.space.id === coordinateSelector?.spaceId) return;
274
+ if (newSpace.space.id === coordinateSelector?.uid) return;
225
275
  setCoordinateSelector({
226
276
  id: uuid(),
227
- spaceId: newSpace.space.id,
277
+ uid: newSpace.space.id,
228
278
  wsen: newSpace.wsen,
229
279
  color: pickOptions.selectorColor,
230
280
  });
@@ -233,7 +283,7 @@ export default ({
233
283
  props.x === undefined ||
234
284
  props.y === undefined ||
235
285
  basePosition === null ||
236
- baseCoordinate === null
286
+ baseCoordinateGeoid === null
237
287
  )
238
288
  return;
239
289
 
@@ -241,16 +291,17 @@ export default ({
241
291
  engineRef.current?.getExtrudedHeight(basePosition, [props.x, props.y], true) ?? 0;
242
292
 
243
293
  if (
244
- baseCoordinate[2] + offset > verticalLimits.top ||
245
- baseCoordinate[2] + offset < verticalLimits.bottom
294
+ baseCoordinateGeoid[2] + offset > verticalLimits.top ||
295
+ baseCoordinateGeoid[2] + offset < verticalLimits.bottom
246
296
  )
247
297
  return;
248
298
 
249
299
  const newSpace = createSpatialIdSpace(
250
- baseCoordinate[0],
251
- baseCoordinate[1],
252
- baseCoordinate[2] + offset,
300
+ baseCoordinateGeoid[0],
301
+ baseCoordinateGeoid[1],
302
+ baseCoordinateGeoid[2] + offset,
253
303
  pickOptions.zoom,
304
+ centerGeoidHeightRef.current ?? 0,
254
305
  );
255
306
 
256
307
  if (newSpace.space.id === spaceSelector?.space.id) return;
@@ -266,12 +317,11 @@ export default ({
266
317
  state,
267
318
  spaceSelector,
268
319
  basePosition,
269
- baseCoordinate,
320
+ baseCoordinateGeoid,
270
321
  engineRef,
271
- terrainEnabled,
272
322
  pickOptions,
273
323
  verticalLimits,
274
- coordinateSelector?.spaceId,
324
+ coordinateSelector?.uid,
275
325
  ],
276
326
  );
277
327
 
@@ -282,10 +332,11 @@ export default ({
282
332
  } else if (state === "floor") {
283
333
  setSpaceSelector(null);
284
334
  setBasePosition(null);
285
- setBaseCoordinate(null);
335
+ setBaseCoordinateGeoid(null);
286
336
  setVerticalSpaceIndicator(null);
287
337
  setCoordinateSelector(lastCoordinateSelector.current);
288
338
  setState("coordinate");
339
+ centerGeoidHeightRef.current = null;
289
340
  }
290
341
  engineRef.current?.requestRender();
291
342
  }, [state, pickOptions, engineRef, finishPicking]);
@@ -6,6 +6,7 @@ import {
6
6
  VerticalSpaceIndicator,
7
7
  } from "../../engines/Cesium/SpatialId";
8
8
  import { InteractionModeType } from "../../Visualizer";
9
+ import { GeoidRef } from "../Geoid/types";
9
10
  import { EngineRef } from "../types";
10
11
 
11
12
  import useHooks from "./hooks";
@@ -13,6 +14,7 @@ import { SpatialIdRef } from "./types";
13
14
 
14
15
  type SpatialIdProps = {
15
16
  engineRef: RefObject<EngineRef>;
17
+ geoidRef: RefObject<GeoidRef>;
16
18
  terrainEnabled?: boolean;
17
19
  interactionMode?: InteractionModeType;
18
20
  overrideInteractionMode?: (mode: InteractionModeType) => void;
@@ -20,7 +22,7 @@ type SpatialIdProps = {
20
22
  };
21
23
 
22
24
  const SpatialId: ForwardRefRenderFunction<SpatialIdRef, SpatialIdProps> = (
23
- { engineRef, terrainEnabled, interactionMode, overrideInteractionMode, onMount },
25
+ { engineRef, geoidRef, terrainEnabled, interactionMode, overrideInteractionMode, onMount },
24
26
  ref,
25
27
  ) => {
26
28
  const {
@@ -32,6 +34,7 @@ const SpatialId: ForwardRefRenderFunction<SpatialIdRef, SpatialIdProps> = (
32
34
  } = useHooks({
33
35
  ref,
34
36
  engineRef,
37
+ geoidRef,
35
38
  terrainEnabled,
36
39
  interactionMode,
37
40
  overrideInteractionMode,
@@ -21,7 +21,7 @@ export type VerticalSpaceIndicatorType = {
21
21
 
22
22
  export type CoordinateSelectorType = {
23
23
  id: string;
24
- spaceId: string;
24
+ uid: string;
25
25
  wsen: [number, number, number, number];
26
26
  color: string;
27
27
  };
@@ -47,7 +47,7 @@ export type SpatialIdRef = {
47
47
  onSpacePick: (cb: (space: SpatialIdSpaceData) => void) => void;
48
48
  };
49
49
 
50
- export type SpatialIdSpacePickingState = "idle" | "coordinate" | "floor";
50
+ export type SpatialIdSpacePickingState = "idle" | "coordinate" | "fetchingGeoid" | "floor";
51
51
 
52
52
  export type SpatialIdSpaceData = {
53
53
  id: string;
@@ -22,6 +22,7 @@ export const createSpatialIdSpace = (
22
22
  lat: number,
23
23
  alt: number,
24
24
  zoom: number,
25
+ geoidHeight: number,
25
26
  ): SpatialIdSpaceType => {
26
27
  const space = new Space({ lat, lng, alt }, zoom);
27
28
  const { wsen, height, extrudedHeight } = getRectangeParamsFromSpace(space);
@@ -30,8 +31,8 @@ export const createSpatialIdSpace = (
30
31
  id: uuid(),
31
32
  space,
32
33
  wsen,
33
- height,
34
- extrudedHeight,
34
+ height: height + geoidHeight,
35
+ extrudedHeight: extrudedHeight + geoidHeight,
35
36
  };
36
37
  };
37
38
 
package/src/Map/hooks.ts CHANGED
@@ -2,6 +2,7 @@ import { useImperativeHandle, useRef, type Ref, useState, useCallback, useEffect
2
2
 
3
3
  import { SelectedFeatureInfo } from "../mantle";
4
4
 
5
+ import { GeoidRef } from "./Geoid/types";
5
6
  import { type MapRef, mapRef } from "./ref";
6
7
  import { SpatialIdRef } from "./SpatialId/types";
7
8
  import type {
@@ -51,6 +52,7 @@ export default function ({
51
52
  const layersRef = useRef<LayersRef>(null);
52
53
  const sketchRef = useRef<SketchRef>(null);
53
54
  const spatialIdRef = useRef<SpatialIdRef>(null);
55
+ const geoidRef = useRef<GeoidRef>(null);
54
56
  const requestingRenderMode = useRef<RequestingRenderMode>(NO_REQUEST_RENDER);
55
57
 
56
58
  useImperativeHandle(
@@ -61,6 +63,7 @@ export default function ({
61
63
  layersRef,
62
64
  sketchRef,
63
65
  spatialIdRef,
66
+ geoidRef,
64
67
  timelineManagerRef,
65
68
  }),
66
69
  [timelineManagerRef],
@@ -151,6 +154,7 @@ export default function ({
151
154
  layersRef,
152
155
  sketchRef,
153
156
  spatialIdRef,
157
+ geoidRef,
154
158
  selectedLayer,
155
159
  requestingRenderMode,
156
160
  handleLayerSelect,
package/src/Map/index.tsx CHANGED
@@ -2,6 +2,7 @@ import { forwardRef, useMemo, type Ref } from "react";
2
2
 
3
3
  import { INTERACTION_MODES } from "../Visualizer/interactionMode";
4
4
 
5
+ import Geoid from "./Geoid";
5
6
  import useHooks, { MapRef } from "./hooks";
6
7
  import Layers, { type Props as LayersProps } from "./Layers";
7
8
  import Sketch, { SketchProps } from "./Sketch";
@@ -82,6 +83,7 @@ function MapFn(
82
83
  layersRef,
83
84
  sketchRef,
84
85
  spatialIdRef,
86
+ geoidRef,
85
87
  selectedLayer,
86
88
  requestingRenderMode,
87
89
  handleLayerSelect,
@@ -167,11 +169,13 @@ function MapFn(
167
169
  <SpatialId
168
170
  ref={spatialIdRef}
169
171
  engineRef={engineRef}
172
+ geoidRef={geoidRef}
170
173
  interactionMode={interactionMode}
171
174
  terrainEnabled={!!props.property?.terrain?.enabled}
172
175
  overrideInteractionMode={overrideInteractionMode}
173
176
  onMount={handleSpatialIdMount}
174
177
  />
178
+ <Geoid ref={geoidRef} geoidServer={props.property?.geoid?.server} />
175
179
  </Engine>
176
180
  ) : null;
177
181
  }
package/src/Map/ref.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { RefObject } from "react";
2
2
 
3
+ import { GeoidRef } from "./Geoid/types";
3
4
  import { SpatialIdRef } from "./SpatialId/types";
4
5
  import type { EngineRef, LayersRef, SketchRef } from "./types";
5
6
  import { TimelineManagerRef } from "./useTimelineManager";
@@ -10,6 +11,7 @@ export type MapRef = {
10
11
  layers: WrappedRef<LayersRef>;
11
12
  sketch: WrappedRef<SketchRef>;
12
13
  spatialId?: WrappedRef<SpatialIdRef>;
14
+ geoid: WrappedRef<GeoidRef>;
13
15
  timeline?: TimelineManagerRef;
14
16
  };
15
17
 
@@ -141,17 +143,23 @@ const spatialIdRefKeys: FunctionKeys<SpatialIdRef> = {
141
143
  onSpacePick: 1,
142
144
  };
143
145
 
146
+ const geoidRefKeys: FunctionKeys<GeoidRef> = {
147
+ getGeoidHeight: 1,
148
+ };
149
+
144
150
  export function mapRef({
145
151
  engineRef,
146
152
  layersRef,
147
153
  sketchRef,
148
154
  spatialIdRef,
155
+ geoidRef,
149
156
  timelineManagerRef,
150
157
  }: {
151
158
  engineRef: RefObject<EngineRef>;
152
159
  layersRef: RefObject<LayersRef>;
153
160
  sketchRef: RefObject<SketchRef>;
154
161
  spatialIdRef: RefObject<SpatialIdRef>;
162
+ geoidRef: RefObject<GeoidRef>;
155
163
  timelineManagerRef?: TimelineManagerRef;
156
164
  }): MapRef {
157
165
  return {
@@ -159,6 +167,7 @@ export function mapRef({
159
167
  layers: wrapRef(layersRef, layersRefKeys),
160
168
  sketch: wrapRef(sketchRef, sketchRefKeys),
161
169
  spatialId: wrapRef(spatialIdRef, spatialIdRefKeys),
170
+ geoid: wrapRef(geoidRef, geoidRefKeys),
162
171
  timeline: timelineManagerRef,
163
172
  };
164
173
  }
@@ -37,6 +37,7 @@ export type SceneMode = "3d" | "2d" | "columbus";
37
37
 
38
38
  export type ViewerProperty = {
39
39
  globe?: GlobeProperty;
40
+ geoid?: GeoidProperty;
40
41
  terrain?: TerrainProperty;
41
42
  scene?: SceneProperty;
42
43
  tiles?: TileProperty[];
@@ -56,6 +57,13 @@ export type GlobeProperty = {
56
57
  depthTestAgainstTerrain?: boolean;
57
58
  };
58
59
 
60
+ export type GeoidProperty = {
61
+ server: {
62
+ url: string;
63
+ geoidProperty: string;
64
+ };
65
+ };
66
+
59
67
  export type GlobeAtmosphereProperty = {
60
68
  enabled?: boolean;
61
69
  lightIntensity?: number;
@@ -92,15 +92,14 @@ const makeFeatureId = (
92
92
  }
93
93
  const featureId = getBuiltinFeatureId(tileFeature);
94
94
  return generateIDWithMD5(
95
- `${coordinates.x}-${coordinates.y}-${coordinates.z}-${featureId}-${
96
- !(tileFeature instanceof Model)
97
- ? JSON.stringify(
98
- // Read only root properties.
99
- Object.entries(convertCesium3DTileFeatureProperties(tileFeature))
100
- .filter((_k, v) => typeof v === "string" || typeof v === "number")
101
- .map(([k, v]) => `${k}${v}`),
102
- )
103
- : ""
95
+ `${coordinates.x}-${coordinates.y}-${coordinates.z}-${featureId}-${!(tileFeature instanceof Model)
96
+ ? JSON.stringify(
97
+ // Read only root properties.
98
+ Object.entries(convertCesium3DTileFeatureProperties(tileFeature))
99
+ .filter((_k, v) => typeof v === "string" || typeof v === "number")
100
+ .map(([k, v]) => `${k}${v}`),
101
+ )
102
+ : ""
104
103
  }`,
105
104
  );
106
105
  };
@@ -732,8 +731,15 @@ export const useHooks = ({
732
731
 
733
732
  const loadTileset = async () => {
734
733
  try {
735
- const tileset = await createGooglePhotorealistic3DTileset(googleMapApiKey);
736
- return tileset.resource;
734
+ if (googleMapApiKey) {
735
+ const tileset = await createGooglePhotorealistic3DTileset(googleMapApiKey);
736
+ return tileset.resource;
737
+ } else {
738
+ const resource = IonResource.fromAssetId(2275207, {
739
+ accessToken: meta?.cesiumIonAccessToken as string | undefined,
740
+ });
741
+ return resource;
742
+ }
737
743
  } catch (error) {
738
744
  console.error(`Error loading Photorealistic 3D Tiles tileset: ${error}`);
739
745
  throw error;
@@ -741,13 +747,13 @@ export const useHooks = ({
741
747
  };
742
748
 
743
749
  return loadTileset();
744
- }, [type, isVisible, googleMapApiKey]);
750
+ }, [type, isVisible, googleMapApiKey, meta?.cesiumIonAccessToken]);
745
751
 
746
752
  const tilesetUrl = useMemo(() => {
747
753
  return type === "osm-buildings" && isVisible
748
754
  ? IonResource.fromAssetId(96188, {
749
- accessToken: meta?.cesiumIonAccessToken as string | undefined,
750
- }) // https://github.com/CesiumGS/cesium/blob/main/packages/engine/Source/Scene/createOsmBuildings.js#L53
755
+ accessToken: meta?.cesiumIonAccessToken as string | undefined,
756
+ }) // https://github.com/CesiumGS/cesium/blob/main/packages/engine/Source/Scene/createOsmBuildings.js#L53
751
757
  : googleMapPhotorealisticResource && isVisible
752
758
  ? googleMapPhotorealisticResource
753
759
  : type === "3dtiles" && isVisible
@@ -772,7 +778,7 @@ export const useHooks = ({
772
778
  property?.imageBasedLightIntensity ?? viewerProperty?.scene?.imageBasedLighting?.intensity;
773
779
  const sphericalHarmonicCoefficients = arrayToCartecian3(
774
780
  property?.sphericalHarmonicCoefficients ??
775
- viewerProperty?.scene?.imageBasedLighting?.sphericalHarmonicCoefficients,
781
+ viewerProperty?.scene?.imageBasedLighting?.sphericalHarmonicCoefficients,
776
782
  imageBasedLightIntensity,
777
783
  );
778
784