diff --git a/src/components/molecules/Visualizer/Engine/Cesium/common.ts b/src/components/molecules/Visualizer/Engine/Cesium/common.ts index 4f2aab6b6..ff51fe65e 100644 --- a/src/components/molecules/Visualizer/Engine/Cesium/common.ts +++ b/src/components/molecules/Visualizer/Engine/Cesium/common.ts @@ -151,7 +151,7 @@ export const vo = ( [""]: undefined, }[o || ""]); -export const getLocationFromScreenXY = ( +export const getLocationFromScreen = ( scene: Scene | undefined | null, x: number, y: number, diff --git a/src/components/molecules/Visualizer/Engine/Cesium/hooks.ts b/src/components/molecules/Visualizer/Engine/Cesium/hooks.ts index c769cb9ba..910f7fd5f 100644 --- a/src/components/molecules/Visualizer/Engine/Cesium/hooks.ts +++ b/src/components/molecules/Visualizer/Engine/Cesium/hooks.ts @@ -19,7 +19,7 @@ import { isDraggable, isSelectable, layerIdField, - getLocationFromScreenXY, + getLocationFromScreen, getClock, } from "./common"; import terrain from "./terrain"; @@ -214,7 +214,7 @@ export default ({ x: position?.x, y: position?.y, ...(position - ? getLocationFromScreenXY(viewer.scene, position.x, position.y, true) ?? {} + ? getLocationFromScreen(viewer.scene, position.x, position.y, true) ?? {} : {}), }; const layerId = getLayerId(target); diff --git a/src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.test.tsx b/src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.test.tsx index e47e21792..c0e63303b 100644 --- a/src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.test.tsx +++ b/src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.test.tsx @@ -510,3 +510,42 @@ test("look", () => { expect(mockLook).toHaveBeenCalledTimes(2); expect(mockLook).toHaveBeenLastCalledWith(new Cartesian3(0, 1, 0), 90); }); + +test("get location from screen xy", () => { + const mockGetPickRay = vi.fn(() => true); + const mockPickEllipsoid = vi.fn(() => + Cartesian3.fromDegrees(137, 40, 0, new Globe(Ellipsoid.WGS84).ellipsoid), + ); + const mockPick = vi.fn(() => + Cartesian3.fromDegrees(110, 20, 10000, new Globe(Ellipsoid.WGS84).ellipsoid), + ); + const { result } = renderHook(() => { + const cesium = useRef>({ + cesiumElement: { + isDestroyed: () => false, + scene: { + camera: { + getPickRay: mockGetPickRay, + pickEllipsoid: mockPickEllipsoid, + }, + globe: { + ellipsoid: new Globe(Ellipsoid.WGS84).ellipsoid, + pick: mockPick, + }, + }, + } as any, + }); + const engineRef = useRef(null); + useEngineRef(engineRef, cesium); + return engineRef; + }); + + const location = result.current.current?.getLocationFromScreen(0, 0); + expect(location?.lng).toBeCloseTo(137, 0); + expect(location?.lat).toBeCloseTo(40, 0); + expect(location?.height).toBeCloseTo(0, 0); + const location2 = result.current.current?.getLocationFromScreen(0, 0, true); + expect(location2?.lng).toBeCloseTo(110, 0); + expect(location2?.lat).toBeCloseTo(20, 0); + expect(location2?.height).toBeCloseTo(10000, 0); +}); diff --git a/src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.ts b/src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.ts index fe12d7eab..581b4ebee 100644 --- a/src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.ts +++ b/src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.ts @@ -9,7 +9,7 @@ import type { MouseEvents, MouseEvent } from "../ref"; import builtinPrimitives from "./builtin"; import Cluster from "./Cluster"; import { - getLocationFromScreenXY, + getLocationFromScreen, flyTo, lookAt, getCamera, @@ -62,10 +62,10 @@ export default function useEngineRef( if (!viewer || viewer.isDestroyed()) return; return getCamera(viewer); }, - getLocationFromScreenXY: (x, y) => { + getLocationFromScreen: (x, y, withTerrain) => { const viewer = cesium.current?.cesiumElement; if (!viewer || viewer.isDestroyed()) return; - return getLocationFromScreenXY(viewer.scene, x, y); + return getLocationFromScreen(viewer.scene, x, y, withTerrain); }, flyTo: (camera, options) => { const viewer = cesium.current?.cesiumElement; diff --git a/src/components/molecules/Visualizer/Engine/ref.ts b/src/components/molecules/Visualizer/Engine/ref.ts index c009d7aad..47e929a81 100644 --- a/src/components/molecules/Visualizer/Engine/ref.ts +++ b/src/components/molecules/Visualizer/Engine/ref.ts @@ -56,7 +56,7 @@ export type EngineRef = { requestRender: () => void; getViewport: () => Rect | undefined; getCamera: () => Camera | undefined; - getLocationFromScreenXY: (x: number, y: number) => LatLngHeight | undefined; + getLocationFromScreen: (x: number, y: number, withTerrain?: boolean) => LatLngHeight | undefined; flyTo: (destination: FlyToDestination, options?: CameraOptions) => void; lookAt: (destination: LookAtDestination, options?: CameraOptions) => void; lookAtLayer: (layerId: string) => void; diff --git a/src/components/molecules/Visualizer/Plugin/api.ts b/src/components/molecules/Visualizer/Plugin/api.ts index de654920b..b7305eae0 100644 --- a/src/components/molecules/Visualizer/Plugin/api.ts +++ b/src/components/molecules/Visualizer/Plugin/api.ts @@ -219,6 +219,7 @@ export function commonReearth({ orbit, rotateRight, captureScreen, + getLocationFromScreen, enableScreenSpaceCameraController, lookHorizontal, lookVertical, @@ -258,6 +259,7 @@ export function commonReearth({ orbit: GlobalThis["reearth"]["visualizer"]["camera"]["orbit"]; cameraViewport: () => GlobalThis["reearth"]["visualizer"]["camera"]["viewport"]; captureScreen: GlobalThis["reearth"]["scene"]["captureScreen"]; + getLocationFromScreen: GlobalThis["reearth"]["scene"]["getLocationFromScreen"]; enableScreenSpaceCameraController: GlobalThis["reearth"]["camera"]["enableScreenSpaceController"]; lookHorizontal: GlobalThis["reearth"]["camera"]["lookHorizontal"]; lookVertical: GlobalThis["reearth"]["camera"]["lookVertical"]; @@ -314,6 +316,7 @@ export function commonReearth({ }, overrideProperty: overrideSceneProperty, captureScreen, + getLocationFromScreen, }, get viewport() { return viewport?.(); diff --git a/src/components/molecules/Visualizer/Plugin/context.tsx b/src/components/molecules/Visualizer/Plugin/context.tsx index 6b3d9a03f..78809ed17 100644 --- a/src/components/molecules/Visualizer/Plugin/context.tsx +++ b/src/components/molecules/Visualizer/Plugin/context.tsx @@ -30,6 +30,7 @@ import type { MouseEvent, Clock, Viewport, + LatLngHeight, } from "./types"; export type EngineContext = { @@ -67,6 +68,7 @@ export type Props = { cameraViewport: () => Rect | undefined; onMouseEvent: (type: keyof MouseEventHandles, fn: any) => void; captureScreen: (type?: string, encoderOptions?: number) => string | undefined; + getLocationFromScreen: (x: number, y: number, withTerrain?: boolean) => LatLngHeight | undefined; enableScreenSpaceCameraController: (enabled: boolean) => void; lookHorizontal: (amount: number) => void; lookVertical: (amount: number) => void; @@ -123,6 +125,7 @@ export function Provider({ orbit, cameraViewport, captureScreen, + getLocationFromScreen, onMouseEvent, enableScreenSpaceCameraController, lookHorizontal, @@ -197,6 +200,7 @@ export function Provider({ rotateRight, orbit, captureScreen, + getLocationFromScreen, enableScreenSpaceCameraController, lookHorizontal, lookVertical, @@ -241,6 +245,7 @@ export function Provider({ rotateRight, orbit, captureScreen, + getLocationFromScreen, enableScreenSpaceCameraController, lookHorizontal, lookVertical, diff --git a/src/components/molecules/Visualizer/Plugin/types.ts b/src/components/molecules/Visualizer/Plugin/types.ts index 3b51138cf..beb2ddb64 100644 --- a/src/components/molecules/Visualizer/Plugin/types.ts +++ b/src/components/molecules/Visualizer/Plugin/types.ts @@ -82,11 +82,22 @@ export type Plugin = { readonly property?: any; }; +export type LatLngHeight = { + lat: number; + lng: number; + height: number; +}; + export type Scene = { /** Current scene property */ readonly property?: any; readonly overrideProperty: (property: any) => void; readonly captureScreen: (type?: string, encoderOptions?: number) => string | undefined; + readonly getLocationFromScreen: ( + x: number, + y: number, + withTerrain?: boolean, + ) => LatLngHeight | undefined; }; /** You can operate and get data about layers. */ diff --git a/src/components/molecules/Visualizer/hooks.ts b/src/components/molecules/Visualizer/hooks.ts index e932d0f7c..c0000d462 100644 --- a/src/components/molecules/Visualizer/hooks.ts +++ b/src/components/molecules/Visualizer/hooks.ts @@ -96,7 +96,7 @@ export default ({ drop(_item, context) { if (!rootLayerId || !isEditable) return; const loc = context.position - ? engineRef.current?.getLocationFromScreenXY(context.position.x, context.position.y) + ? engineRef.current?.getLocationFromScreen(context.position.x, context.position.y) : undefined; return { type: "earth", @@ -512,6 +512,7 @@ function useProviderProps( | "cameraViewport" | "onMouseEvent" | "captureScreen" + | "getLocationFromScreen" | "enableScreenSpaceCameraController" | "lookHorizontal" | "lookVertical" @@ -631,6 +632,13 @@ function useProviderProps( [engineRef], ); + const getLocationFromScreen = useCallback( + (x: number, y: number, withTerrain?: boolean) => { + return engineRef.current?.getLocationFromScreen(x, y, withTerrain); + }, + [engineRef], + ); + const enableScreenSpaceCameraController = useCallback( (enabled: boolean) => engineRef?.current?.enableScreenSpaceCameraController(enabled), [engineRef], @@ -720,6 +728,7 @@ function useProviderProps( cameraViewport, onMouseEvent, captureScreen, + getLocationFromScreen, enableScreenSpaceCameraController, lookHorizontal, lookVertical, diff --git a/src/components/molecules/Visualizer/storybook.tsx b/src/components/molecules/Visualizer/storybook.tsx index 9a9f6d8da..ced77b856 100644 --- a/src/components/molecules/Visualizer/storybook.tsx +++ b/src/components/molecules/Visualizer/storybook.tsx @@ -100,6 +100,7 @@ export const context: ProviderProps = { cameraViewport: act("cameraViewport"), onMouseEvent: act("onMouseEvent"), captureScreen: act("captureScreen"), + getLocationFromScreen: act("getLocationFromScreen"), enableScreenSpaceCameraController: act("enableScreenSpaceCameraController"), lookHorizontal: act("lookHorizontal"), lookVertical: act("lookVertical"),