@zendir/ui 0.2.21 → 0.3.1
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/CHANGELOG.md +183 -1
- package/README.md +70 -28
- package/dist/index.d.ts +1 -1
- package/dist/index.js +73 -64
- package/dist/index.js.map +1 -1
- package/dist/react/3d/CesiumCaptureSource.d.ts +1 -1
- package/dist/react/3d/CesiumCaptureSource.js +1 -1
- package/dist/react/3d/CesiumCaptureSource.js.map +1 -1
- package/dist/react/3d/ZenSpace3D.js +1254 -0
- package/dist/react/3d/ZenSpace3D.js.map +1 -0
- package/dist/react/3d/ZenSpace3DCesium.js +579 -0
- package/dist/react/3d/ZenSpace3DCesium.js.map +1 -0
- package/dist/react/3d/ZenSpace3DShaders.js +478 -0
- package/dist/react/3d/ZenSpace3DShaders.js.map +1 -0
- package/dist/react/3d/ZenSpace3DTypes.d.ts +28 -1
- package/dist/react/3d/ZenSpace3DUtils.d.ts +17 -173
- package/dist/react/3d/ZenSpace3DUtils.js +20 -1
- package/dist/react/3d/ZenSpace3DUtils.js.map +1 -1
- package/dist/react/3d/capturePngAnalysis.js +42 -0
- package/dist/react/3d/capturePngAnalysis.js.map +1 -0
- package/dist/react/3d/index.d.ts +6 -12
- package/dist/react/3d/index.js +57 -0
- package/dist/react/3d/index.js.map +1 -0
- package/dist/react/3d/threeLoader.js +22 -0
- package/dist/react/3d/threeLoader.js.map +1 -0
- package/dist/react/astro/ClassificationBanner.js +1 -1
- package/dist/react/astro/GlobalStatusBar.js +1 -1
- package/dist/react/astro/MissionClock.js +8 -5
- package/dist/react/astro/MissionClock.js.map +1 -1
- package/dist/react/astro/MonitoringIcon.js +2 -2
- package/dist/react/astro/MonitoringIcon.js.map +1 -1
- package/dist/react/astro/Notification.js +1 -1
- package/dist/react/astro/Progress.js +1 -1
- package/dist/react/astro/SimulationControls.js +3 -3
- package/dist/react/astro/SimulationControls.js.map +1 -1
- package/dist/react/astro/StatusIndicator.js +1 -1
- package/dist/react/astro/UnifiedTimeline.js +5 -5
- package/dist/react/astro/UnifiedTimeline.js.map +1 -1
- package/dist/react/astro/index.js +34 -0
- package/dist/react/astro/index.js.map +1 -0
- package/dist/react/cards/AccessCard.js +410 -0
- package/dist/react/cards/AccessCard.js.map +1 -0
- package/dist/react/cards/OrbitCard.js +372 -0
- package/dist/react/cards/OrbitCard.js.map +1 -0
- package/dist/react/cards/SpacecraftCard.js +941 -0
- package/dist/react/cards/SpacecraftCard.js.map +1 -0
- package/dist/react/cards/TelemetryCard.js +742 -0
- package/dist/react/cards/TelemetryCard.js.map +1 -0
- package/dist/react/cards/TelemetryStreamCard.js +309 -0
- package/dist/react/cards/TelemetryStreamCard.js.map +1 -0
- package/dist/react/cards/index.js +13 -0
- package/dist/react/cards/index.js.map +1 -0
- package/dist/react/charts/GroundTrackMap.d.ts +2 -15
- package/dist/react/charts/GroundTrackMap.js +1 -1
- package/dist/react/charts/GroundTrackMap.js.map +1 -1
- package/dist/react/charts/GroundTrackMapLeaflet.js +1 -1
- package/dist/react/charts/index.js +104 -0
- package/dist/react/charts/index.js.map +1 -0
- package/dist/react/charts/unified/AstroChart.js +35 -14
- package/dist/react/charts/unified/AstroChart.js.map +1 -1
- package/dist/react/charts/unified/PowerOverviewChart.js +488 -0
- package/dist/react/charts/unified/PowerOverviewChart.js.map +1 -0
- package/dist/react/charts/unified/domain.js +3168 -0
- package/dist/react/charts/unified/domain.js.map +1 -0
- package/dist/react/charts/unified/generators.js +518 -0
- package/dist/react/charts/unified/generators.js.map +1 -0
- package/dist/react/charts/unified/presets.js +1000 -0
- package/dist/react/charts/unified/presets.js.map +1 -0
- package/dist/react/charts/unified/sync.js +219 -0
- package/dist/react/charts/unified/sync.js.map +1 -0
- package/dist/react/charts/unified/theme.js +331 -4
- package/dist/react/charts/unified/theme.js.map +1 -1
- package/dist/react/charts/unified/useChartStream.js +226 -0
- package/dist/react/charts/unified/useChartStream.js.map +1 -0
- package/dist/react/chatgpt/AppCard.d.ts +0 -4
- package/dist/react/chatgpt/index.d.ts +0 -19
- package/dist/react/chatgpt/index.js +163 -0
- package/dist/react/chatgpt/index.js.map +1 -0
- package/dist/react/context/SpatialSelectionContext.d.ts +40 -0
- package/dist/react/context/SpatialSelectionContext.js +10 -0
- package/dist/react/context/SpatialSelectionContext.js.map +1 -0
- package/dist/react/context/index.d.ts +2 -0
- package/dist/react/core/{DataTable.d.ts → data/DataTable.d.ts} +1 -1
- package/dist/react/core/{DataTable.js → data/DataTable.js} +4 -4
- package/dist/react/core/data/DataTable.js.map +1 -0
- package/dist/react/core/{DataValue.d.ts → data/DataValue.d.ts} +2 -2
- package/dist/react/core/{DataValue.js → data/DataValue.js} +2 -2
- package/dist/react/core/data/DataValue.js.map +1 -0
- package/dist/react/core/{propertyConfig.d.ts → data/propertyConfig.d.ts} +2 -2
- package/dist/react/core/data/propertyConfig.js.map +1 -0
- package/dist/react/core/{AstroIcon.js → display/AstroIcon.js} +1 -1
- package/dist/react/core/display/AstroIcon.js.map +1 -0
- package/dist/react/core/{Badge.d.ts → display/Badge.d.ts} +1 -1
- package/dist/react/core/{Badge.js → display/Badge.js} +2 -2
- package/dist/react/core/display/Badge.js.map +1 -0
- package/dist/react/core/{CardHeader.d.ts → display/CardHeader.d.ts} +1 -1
- package/dist/react/core/{CardHeader.js → display/CardHeader.js} +2 -2
- package/dist/react/core/display/CardHeader.js.map +1 -0
- package/dist/react/core/{Container.d.ts → display/Container.d.ts} +1 -1
- package/dist/react/core/{Container.js → display/Container.js} +3 -3
- package/dist/react/core/display/Container.js.map +1 -0
- package/dist/react/core/{CopyButton.js → display/CopyButton.js} +1 -1
- package/dist/react/core/display/CopyButton.js.map +1 -0
- package/dist/react/core/{GlassCard.d.ts → display/GlassCard.d.ts} +1 -1
- package/dist/react/core/{GlassCard.js → display/GlassCard.js} +2 -2
- package/dist/react/core/display/GlassCard.js.map +1 -0
- package/dist/react/core/{HeaderIconWithStatus.d.ts → display/HeaderIconWithStatus.d.ts} +1 -1
- package/dist/react/core/{HeaderIconWithStatus.js → display/HeaderIconWithStatus.js} +1 -1
- package/dist/react/core/display/HeaderIconWithStatus.js.map +1 -0
- package/dist/react/core/{Icon.d.ts → display/Icon.d.ts} +1 -1
- package/dist/react/core/{Icon.js → display/Icon.js} +1 -1
- package/dist/react/core/display/Icon.js.map +1 -0
- package/dist/react/core/{Typography.d.ts → display/Typography.d.ts} +13 -4
- package/dist/react/core/{Typography.js → display/Typography.js} +1 -1
- package/dist/react/core/display/Typography.js.map +1 -0
- package/dist/react/core/{ConfirmDialog.js → feedback/ConfirmDialog.js} +1 -1
- package/dist/react/core/feedback/ConfirmDialog.js.map +1 -0
- package/dist/react/core/{Dialog.js → feedback/Dialog.js} +2 -2
- package/dist/react/core/feedback/Dialog.js.map +1 -0
- package/dist/react/core/{Toast.js → feedback/Toast.js} +3 -3
- package/dist/react/core/feedback/Toast.js.map +1 -0
- package/dist/react/core/index.d.ts +85 -85
- package/dist/react/core/index.js +161 -0
- package/dist/react/core/index.js.map +1 -0
- package/dist/react/core/{Button.js → inputs/Button.js} +2 -2
- package/dist/react/core/inputs/Button.js.map +1 -0
- package/dist/react/core/{Checkbox.js → inputs/Checkbox.js} +2 -2
- package/dist/react/core/inputs/Checkbox.js.map +1 -0
- package/dist/react/core/{Input.d.ts → inputs/Input.d.ts} +1 -1
- package/dist/react/core/{Input.js → inputs/Input.js} +3 -3
- package/dist/react/core/inputs/Input.js.map +1 -0
- package/dist/react/core/{LimitsBar.js → inputs/LimitsBar.js} +1 -1
- package/dist/react/core/inputs/LimitsBar.js.map +1 -0
- package/dist/react/core/{NumberInput.d.ts → inputs/NumberInput.d.ts} +2 -2
- package/dist/react/core/{NumberInput.js → inputs/NumberInput.js} +3 -3
- package/dist/react/core/inputs/NumberInput.js.map +1 -0
- package/dist/react/core/{PinInput.js → inputs/PinInput.js} +2 -2
- package/dist/react/core/inputs/PinInput.js.map +1 -0
- package/dist/react/core/{Select.js → inputs/Select.js} +3 -3
- package/dist/react/core/inputs/Select.js.map +1 -0
- package/dist/react/core/{Toggle.js → inputs/Toggle.js} +2 -2
- package/dist/react/core/inputs/Toggle.js.map +1 -0
- package/dist/react/core/layout/Box.js +1 -1
- package/dist/react/core/layout/Flex.js +1 -1
- package/dist/react/core/layout/Grid.js +1 -1
- package/dist/react/core/layout/Stack.js +1 -1
- package/dist/react/core/{AppBar.d.ts → navigation/AppBar.d.ts} +1 -1
- package/dist/react/core/{AppBar.js → navigation/AppBar.js} +7 -7
- package/dist/react/core/navigation/AppBar.js.map +1 -0
- package/dist/react/core/{Pagination.js → navigation/Pagination.js} +2 -2
- package/dist/react/core/navigation/Pagination.js.map +1 -0
- package/dist/react/core/{SideNav.d.ts → navigation/SideNav.d.ts} +1 -1
- package/dist/react/core/{SideNav.js → navigation/SideNav.js} +3 -3
- package/dist/react/core/navigation/SideNav.js.map +1 -0
- package/dist/react/core/{Tabs.js → navigation/Tabs.js} +2 -2
- package/dist/react/core/navigation/Tabs.js.map +1 -0
- package/dist/react/core/{Popover.js → overlays/Popover.js} +1 -1
- package/dist/react/core/overlays/Popover.js.map +1 -0
- package/dist/react/core/{SidePanel.js → overlays/SidePanel.js} +3 -3
- package/dist/react/core/overlays/SidePanel.js.map +1 -0
- package/dist/react/core/{Tooltip.js → overlays/Tooltip.js} +2 -2
- package/dist/react/core/overlays/Tooltip.js.map +1 -0
- package/dist/react/core/{ActivityPlanner.js → widgets/ActivityPlanner.js} +1 -1
- package/dist/react/core/widgets/ActivityPlanner.js.map +1 -0
- package/dist/react/core/{Capture.js → widgets/Capture.js} +3 -3
- package/dist/react/core/widgets/Capture.js.map +1 -0
- package/dist/react/core/{ChatPanel.d.ts → widgets/ChatPanel.d.ts} +1 -1
- package/dist/react/core/{ChatPanel.js → widgets/ChatPanel.js} +2 -2
- package/dist/react/core/widgets/ChatPanel.js.map +1 -0
- package/dist/react/core/{ColorPickerPanel.d.ts → widgets/ColorPickerPanel.d.ts} +1 -1
- package/dist/react/core/{ColorPickerPanel.js → widgets/ColorPickerPanel.js} +3 -3
- package/dist/react/core/widgets/ColorPickerPanel.js.map +1 -0
- package/dist/react/core/{CommandBuilder.js → widgets/CommandBuilder.js} +1 -1
- package/dist/react/core/widgets/CommandBuilder.js.map +1 -0
- package/dist/react/core/{ConnectionForm.d.ts → widgets/ConnectionForm.d.ts} +1 -1
- package/dist/react/core/{ConnectionForm.js → widgets/ConnectionForm.js} +2 -2
- package/dist/react/core/widgets/ConnectionForm.js.map +1 -0
- package/dist/react/core/{FileExplorer.js → widgets/FileExplorer.js} +2 -2
- package/dist/react/core/widgets/FileExplorer.js.map +1 -0
- package/dist/react/core/{HexViewer.js → widgets/HexViewer.js} +1 -1
- package/dist/react/core/widgets/HexViewer.js.map +1 -0
- package/dist/react/core/{ImageGallery.d.ts → widgets/ImageGallery.d.ts} +1 -1
- package/dist/react/core/{ImageGallery.js → widgets/ImageGallery.js} +3 -3
- package/dist/react/core/widgets/ImageGallery.js.map +1 -0
- package/dist/react/core/{LogViewer.d.ts → widgets/LogViewer.d.ts} +13 -3
- package/dist/react/core/{LogViewer.js → widgets/LogViewer.js} +28 -8
- package/dist/react/core/widgets/LogViewer.js.map +1 -0
- package/dist/react/core/{MessageStream.d.ts → widgets/MessageStream.d.ts} +2 -2
- package/dist/react/core/{MessageStream.js → widgets/MessageStream.js} +4 -4
- package/dist/react/core/widgets/MessageStream.js.map +1 -0
- package/dist/react/core/{MissionCalendar.js → widgets/MissionCalendar.js} +2 -2
- package/dist/react/core/widgets/MissionCalendar.js.map +1 -0
- package/dist/react/core/{PacketViewer.js → widgets/PacketViewer.js} +1 -1
- package/dist/react/core/widgets/PacketViewer.js.map +1 -0
- package/dist/react/core/widgets/capture-placeholder.png.js.map +1 -0
- package/dist/react/hooks/index.d.ts +9 -11
- package/dist/react/hooks/useAccessWindows.d.ts +15 -19
- package/dist/react/hooks/useCompactMode.js +1 -1
- package/dist/react/hooks/useGroundTrackHistory.d.ts +34 -0
- package/dist/react/hooks/useSimulationScene.d.ts +141 -0
- package/dist/react/hooks/useSimulationScene.js +401 -0
- package/dist/react/hooks/useSimulationScene.js.map +1 -0
- package/dist/react/hooks/useZendirSession.d.ts +44 -69
- package/dist/react/index.d.ts +7 -3
- package/dist/react/panels/LayerControlPanel.d.ts +54 -0
- package/dist/react/panels/LayerControlPanel.js +184 -0
- package/dist/react/panels/LayerControlPanel.js.map +1 -0
- package/dist/react/panels/ObjectInventoryPanel.d.ts +57 -0
- package/dist/react/panels/ObjectInventoryPanel.js +261 -0
- package/dist/react/panels/ObjectInventoryPanel.js.map +1 -0
- package/dist/react/panels/index.d.ts +15 -0
- package/dist/react/panels/index.js +8 -0
- package/dist/react/panels/index.js.map +1 -0
- package/dist/react/theme/ThemeProvider.d.ts +2 -0
- package/dist/react/theme/ThemeProvider.js +50 -72
- package/dist/react/theme/ThemeProvider.js.map +1 -1
- package/dist/react/theme/config.js +30 -0
- package/dist/react/theme/config.js.map +1 -0
- package/dist/react/theme/index.js +19 -0
- package/dist/react/theme/index.js.map +1 -0
- package/dist/react/types.d.ts +32 -3
- package/dist/react/types.js.map +1 -1
- package/dist/react/utils/index.js +8 -0
- package/dist/react/utils/index.js.map +1 -1
- package/dist/react.js +73 -64
- package/dist/react.js.map +1 -1
- package/dist/shaders/atmosphere.frag.js +5 -0
- package/dist/shaders/atmosphere.frag.js.map +1 -0
- package/dist/shaders/atmosphere.vert.js +5 -0
- package/dist/shaders/atmosphere.vert.js.map +1 -0
- package/dist/shaders/stars.frag.js +5 -0
- package/dist/shaders/stars.frag.js.map +1 -0
- package/dist/shaders/stars.vert.js +5 -0
- package/dist/shaders/stars.vert.js.map +1 -0
- package/dist/style.css +6 -4
- package/dist/tokens/css-vars.d.ts +91 -0
- package/dist/tokens/css-vars.js +228 -0
- package/dist/tokens/css-vars.js.map +1 -0
- package/dist/tokens/index.d.ts +71 -18
- package/dist/tokens/index.js +206 -97
- package/dist/tokens/index.js.map +1 -1
- package/dist/tokens/tokens.css +50 -50
- package/package.json +70 -58
- package/sdk-stub.js +10 -5
- package/dist/react/3d/EarthViewer.d.ts +0 -46
- package/dist/react/3d/SolarSystemViewer.d.ts +0 -43
- package/dist/react/chatgpt/ChatGPTCard.d.ts +0 -6
- package/dist/react/core/ActivityPlanner.js.map +0 -1
- package/dist/react/core/AppBar.js.map +0 -1
- package/dist/react/core/AstroIcon.js.map +0 -1
- package/dist/react/core/Badge.js.map +0 -1
- package/dist/react/core/Button.js.map +0 -1
- package/dist/react/core/Capture.js.map +0 -1
- package/dist/react/core/CardHeader.js.map +0 -1
- package/dist/react/core/ChatPanel.js.map +0 -1
- package/dist/react/core/Checkbox.js.map +0 -1
- package/dist/react/core/ColorPickerPanel.js.map +0 -1
- package/dist/react/core/CommandBuilder.js.map +0 -1
- package/dist/react/core/ConfirmDialog.js.map +0 -1
- package/dist/react/core/ConnectionForm.js.map +0 -1
- package/dist/react/core/Container.js.map +0 -1
- package/dist/react/core/CopyButton.js.map +0 -1
- package/dist/react/core/DataTable.js.map +0 -1
- package/dist/react/core/DataValue.js.map +0 -1
- package/dist/react/core/Dialog.js.map +0 -1
- package/dist/react/core/FileExplorer.js.map +0 -1
- package/dist/react/core/GlassCard.js.map +0 -1
- package/dist/react/core/HeaderIconWithStatus.js.map +0 -1
- package/dist/react/core/HexViewer.js.map +0 -1
- package/dist/react/core/Icon.js.map +0 -1
- package/dist/react/core/ImageGallery.js.map +0 -1
- package/dist/react/core/Input.js.map +0 -1
- package/dist/react/core/LimitsBar.js.map +0 -1
- package/dist/react/core/LogViewer.js.map +0 -1
- package/dist/react/core/MessageStream.js.map +0 -1
- package/dist/react/core/MissionCalendar.js.map +0 -1
- package/dist/react/core/NumberInput.js.map +0 -1
- package/dist/react/core/PacketViewer.js.map +0 -1
- package/dist/react/core/Pagination.js.map +0 -1
- package/dist/react/core/PinInput.js.map +0 -1
- package/dist/react/core/Popover.js.map +0 -1
- package/dist/react/core/Select.js.map +0 -1
- package/dist/react/core/SideNav.js.map +0 -1
- package/dist/react/core/SidePanel.js.map +0 -1
- package/dist/react/core/Tabs.js.map +0 -1
- package/dist/react/core/Toast.js.map +0 -1
- package/dist/react/core/Toggle.js.map +0 -1
- package/dist/react/core/Tooltip.js.map +0 -1
- package/dist/react/core/Typography.js.map +0 -1
- package/dist/react/core/capture-placeholder.png.js.map +0 -1
- package/dist/react/core/propertyConfig.js.map +0 -1
- package/dist/react/hooks/useSimulationTime.d.ts +0 -61
- package/dist/react/hooks/useSpacecraftPosition.d.ts +0 -50
- package/dist/react/hooks/useTelemetry.d.ts +0 -55
- package/dist/types.d.ts +0 -1
- package/dist/types.js +0 -2
- package/dist/types.js.map +0 -1
- /package/dist/react/core/{propertyConfig.js → data/propertyConfig.js} +0 -0
- /package/dist/react/core/{AstroIcon.d.ts → display/AstroIcon.d.ts} +0 -0
- /package/dist/react/core/{CopyButton.d.ts → display/CopyButton.d.ts} +0 -0
- /package/dist/react/core/{ConfirmDialog.d.ts → feedback/ConfirmDialog.d.ts} +0 -0
- /package/dist/react/core/{Dialog.d.ts → feedback/Dialog.d.ts} +0 -0
- /package/dist/react/core/{Toast.d.ts → feedback/Toast.d.ts} +0 -0
- /package/dist/react/core/{Button.d.ts → inputs/Button.d.ts} +0 -0
- /package/dist/react/core/{Checkbox.d.ts → inputs/Checkbox.d.ts} +0 -0
- /package/dist/react/core/{LimitsBar.d.ts → inputs/LimitsBar.d.ts} +0 -0
- /package/dist/react/core/{PinInput.d.ts → inputs/PinInput.d.ts} +0 -0
- /package/dist/react/core/{Select.d.ts → inputs/Select.d.ts} +0 -0
- /package/dist/react/core/{Toggle.d.ts → inputs/Toggle.d.ts} +0 -0
- /package/dist/react/core/{Pagination.d.ts → navigation/Pagination.d.ts} +0 -0
- /package/dist/react/core/{Tabs.d.ts → navigation/Tabs.d.ts} +0 -0
- /package/dist/react/core/{Popover.d.ts → overlays/Popover.d.ts} +0 -0
- /package/dist/react/core/{SidePanel.d.ts → overlays/SidePanel.d.ts} +0 -0
- /package/dist/react/core/{Tooltip.d.ts → overlays/Tooltip.d.ts} +0 -0
- /package/dist/react/core/{ActivityPlanner.d.ts → widgets/ActivityPlanner.d.ts} +0 -0
- /package/dist/react/core/{Capture.d.ts → widgets/Capture.d.ts} +0 -0
- /package/dist/react/core/{CommandBuilder.d.ts → widgets/CommandBuilder.d.ts} +0 -0
- /package/dist/react/core/{FileExplorer.d.ts → widgets/FileExplorer.d.ts} +0 -0
- /package/dist/react/core/{HexViewer.d.ts → widgets/HexViewer.d.ts} +0 -0
- /package/dist/react/core/{MissionCalendar.d.ts → widgets/MissionCalendar.d.ts} +0 -0
- /package/dist/react/core/{PacketViewer.d.ts → widgets/PacketViewer.d.ts} +0 -0
- /package/dist/react/core/{capture-placeholder.png.js → widgets/capture-placeholder.png.js} +0 -0
|
@@ -436,6 +436,17 @@ export interface ZenSpace3DProps {
|
|
|
436
436
|
timeScale?: number;
|
|
437
437
|
/** Auto-play on mount */
|
|
438
438
|
autoPlay?: boolean;
|
|
439
|
+
/**
|
|
440
|
+
* Reference time used to convert ECI / J2000 positions into the
|
|
441
|
+
* Earth-Fixed (ECEF) frame Cesium renders. Should be the **simulation
|
|
442
|
+
* clock as a real UTC Date** (sim epoch + sim seconds) so the
|
|
443
|
+
* sub-satellite point on Earth lines up with the actual ground track.
|
|
444
|
+
*
|
|
445
|
+
* If omitted, the Cesium backend falls back to wall-clock now —
|
|
446
|
+
* geometry stays self-consistent but the ground track will drift from
|
|
447
|
+
* the engine's truth as Earth rotates.
|
|
448
|
+
*/
|
|
449
|
+
referenceTime?: Date;
|
|
439
450
|
/**
|
|
440
451
|
* Sun direction vector for lighting and atmosphere effects
|
|
441
452
|
* Typically from Zendir SDK sun position calculation
|
|
@@ -485,8 +496,24 @@ export interface ZenSpace3DProps {
|
|
|
485
496
|
showAxisHelper?: boolean;
|
|
486
497
|
/** Maneuver nodes */
|
|
487
498
|
maneuverNodes?: ManeuverNode[];
|
|
488
|
-
/**
|
|
499
|
+
/**
|
|
500
|
+
* Render-flag layers — affect HOW objects are drawn.
|
|
501
|
+
* `labels` — name labels next to satellite / GS markers (default off)
|
|
502
|
+
* `coverage` — sensor footprint ellipses + cones (default off)
|
|
503
|
+
* `orbits` — historical orbit polylines (default on)
|
|
504
|
+
*/
|
|
489
505
|
layers?: Partial<LayerVisibility>;
|
|
506
|
+
/**
|
|
507
|
+
* Object-group visibility — toggle WHOLE categories on/off without
|
|
508
|
+
* unmounting the viewer. Defaults to "everything visible". Drives the
|
|
509
|
+
* upcoming `<LayerControlPanel />` — also usable directly for headless
|
|
510
|
+
* apps that want pre-set visibility.
|
|
511
|
+
*/
|
|
512
|
+
visibility?: {
|
|
513
|
+
spacecraft?: boolean;
|
|
514
|
+
groundStations?: boolean;
|
|
515
|
+
celestialBodies?: boolean;
|
|
516
|
+
};
|
|
490
517
|
/** Show controls panel */
|
|
491
518
|
showControls?: boolean;
|
|
492
519
|
/** Show timeline */
|
|
@@ -1,183 +1,27 @@
|
|
|
1
|
-
import { Vector3D
|
|
1
|
+
import { Vector3D } from './ZenSpace3DTypes';
|
|
2
2
|
|
|
3
|
-
/** Earth's radius in km */
|
|
3
|
+
/** Earth's mean radius in km. */
|
|
4
4
|
export declare const EARTH_RADIUS_KM = 6371;
|
|
5
|
-
/**
|
|
6
|
-
export declare const EARTH_MU = 398600.4418;
|
|
7
|
-
/** Astronomical Unit in km */
|
|
8
|
-
export declare const AU_KM = 149597870.7;
|
|
9
|
-
/** Degrees to radians */
|
|
5
|
+
/** Degrees → radians. */
|
|
10
6
|
export declare const DEG_TO_RAD: number;
|
|
11
|
-
/** Radians
|
|
7
|
+
/** Radians → degrees. */
|
|
12
8
|
export declare const RAD_TO_DEG: number;
|
|
13
|
-
/**
|
|
14
|
-
export declare const J2000_EPOCH: Date;
|
|
15
|
-
/** Seconds per day */
|
|
16
|
-
export declare const SECONDS_PER_DAY = 86400;
|
|
17
|
-
/** Minutes per day */
|
|
18
|
-
export declare const MINUTES_PER_DAY = 1440;
|
|
19
|
-
/** Scene Earth radius (render units) */
|
|
9
|
+
/** Earth radius in scene units (Three.js render space). */
|
|
20
10
|
export declare const SCENE_EARTH_RADIUS = 3000;
|
|
21
|
-
/**
|
|
11
|
+
/** Conversion factor: 1 km → scene units. */
|
|
22
12
|
export declare const KM_TO_SCENE: number;
|
|
23
|
-
/** Scene scale for Solar System (different scale) */
|
|
24
|
-
export declare const SOLAR_SYSTEM_SCALE = 1;
|
|
25
13
|
/**
|
|
26
|
-
* Convert
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
14
|
+
* Convert lat/lon/alt to a Cartesian point in scene space.
|
|
15
|
+
*
|
|
16
|
+
* Result is in *render units* (scaled by `KM_TO_SCENE`), suitable for
|
|
17
|
+
* direct use in the Three.js scene graph. For ECI→ECEF on the Cesium
|
|
18
|
+
* backend, use `Cesium.Transforms.computeTemeToPseudoFixedMatrix`.
|
|
19
|
+
*
|
|
20
|
+
* @param lat Latitude in degrees.
|
|
21
|
+
* @param lon Longitude in degrees.
|
|
22
|
+
* @param altKm Altitude above Earth surface in km (default 0).
|
|
23
|
+
* @param earthRadius Scene radius for Earth (default `SCENE_EARTH_RADIUS`).
|
|
32
24
|
*/
|
|
33
25
|
export declare function latLonAltToCartesian(lat: number, lon: number, altKm?: number, earthRadius?: number): Vector3D;
|
|
34
|
-
/**
|
|
35
|
-
* Convert Cartesian to latitude/longitude/altitude
|
|
36
|
-
* @param position Cartesian position
|
|
37
|
-
* @param earthRadius Scene radius for Earth
|
|
38
|
-
* @returns Lat/Lon/Alt
|
|
39
|
-
*/
|
|
40
|
-
export declare function cartesianToLatLonAlt(position: Vector3D, earthRadius?: number): LatLonAlt;
|
|
41
|
-
/**
|
|
42
|
-
* Convert Cartesian to spherical coordinates
|
|
43
|
-
*/
|
|
44
|
-
export declare function cartesianToSpherical(position: Vector3D): SphericalCoords;
|
|
45
|
-
/**
|
|
46
|
-
* Convert spherical to Cartesian coordinates
|
|
47
|
-
*/
|
|
48
|
-
export declare function sphericalToCartesian(coords: SphericalCoords): Vector3D;
|
|
49
|
-
/**
|
|
50
|
-
* Convert ECI (Earth-Centered Inertial) to ECEF (Earth-Centered Earth-Fixed)
|
|
51
|
-
* @param eci ECI position (km)
|
|
52
|
-
* @param gmst Greenwich Mean Sidereal Time (radians)
|
|
53
|
-
*/
|
|
54
|
-
export declare function eciToEcef(eci: Vector3D, gmst: number): Vector3D;
|
|
55
|
-
/**
|
|
56
|
-
* Calculate Greenwich Mean Sidereal Time
|
|
57
|
-
* @param date Date/time
|
|
58
|
-
* @returns GMST in radians
|
|
59
|
-
*/
|
|
60
|
-
export declare function calculateGMST(date: Date): number;
|
|
61
|
-
/**
|
|
62
|
-
* Convert Date to Julian Date
|
|
63
|
-
*/
|
|
64
|
-
export declare function dateToJulianDate(date: Date): number;
|
|
65
|
-
/**
|
|
66
|
-
* Parse Two-Line Element set
|
|
67
|
-
*/
|
|
68
|
-
export declare function parseTLE(line1: string, line2: string): TLEData | null;
|
|
69
|
-
/**
|
|
70
|
-
* Simplified SGP4 propagation
|
|
71
|
-
* @param tle TLE data
|
|
72
|
-
* @param minutesFromEpoch Minutes from TLE epoch
|
|
73
|
-
* @returns Position in km (ECI coordinates)
|
|
74
|
-
*/
|
|
75
|
-
export declare function propagateSGP4Simple(tle: TLEData, minutesFromEpoch: number): Vector3D;
|
|
76
|
-
/**
|
|
77
|
-
* Propagate satellite to specific time
|
|
78
|
-
* @param satellite Satellite with TLE
|
|
79
|
-
* @param time Target time
|
|
80
|
-
* @returns Position in km (ECI)
|
|
81
|
-
*/
|
|
82
|
-
export declare function propagateSatellite(satellite: Satellite, time: Date): Vector3D | null;
|
|
83
|
-
/**
|
|
84
|
-
* Generate orbit path for a satellite
|
|
85
|
-
* @param satellite Satellite with TLE
|
|
86
|
-
* @param startTime Start time
|
|
87
|
-
* @param duration Duration in minutes
|
|
88
|
-
* @param steps Number of steps
|
|
89
|
-
*/
|
|
90
|
-
export declare function generateOrbitPath(satellite: Satellite, startTime: Date, duration?: number, steps?: number): OrbitPath | null;
|
|
91
|
-
/**
|
|
92
|
-
* Calculate if a satellite is visible from a ground station
|
|
93
|
-
* @param satPos Satellite position (scene units)
|
|
94
|
-
* @param gsLatLon Ground station lat/lon
|
|
95
|
-
* @param minElevation Minimum elevation angle (degrees)
|
|
96
|
-
*/
|
|
97
|
-
export declare function isVisible(satPos: Vector3D, gsLatLon: {
|
|
98
|
-
latitude: number;
|
|
99
|
-
longitude: number;
|
|
100
|
-
}, minElevation?: number): boolean;
|
|
101
|
-
/**
|
|
102
|
-
* Calculate visibility cone vertices for rendering
|
|
103
|
-
* @param gsLatLon Ground station position
|
|
104
|
-
* @param minElevation Minimum elevation angle
|
|
105
|
-
* @param altitude Altitude for cone apex (km)
|
|
106
|
-
* @param segments Number of segments for cone circle
|
|
107
|
-
*/
|
|
108
|
-
export declare function calculateVisibilityConeGeometry(gsLatLon: {
|
|
109
|
-
latitude: number;
|
|
110
|
-
longitude: number;
|
|
111
|
-
}, minElevation?: number, altitude?: number, segments?: number): Vector3D[];
|
|
112
|
-
/**
|
|
113
|
-
* Generate footprint polygon for a satellite
|
|
114
|
-
* @param satPos Satellite position (scene units)
|
|
115
|
-
* @param minElevation Minimum elevation angle
|
|
116
|
-
* @param segments Number of segments
|
|
117
|
-
*/
|
|
118
|
-
export declare function calculateFootprint(satPos: Vector3D, minElevation?: number, segments?: number): Array<{
|
|
119
|
-
latitude: number;
|
|
120
|
-
longitude: number;
|
|
121
|
-
}>;
|
|
122
|
-
/**
|
|
123
|
-
* Generate a hexagonal grid covering the globe
|
|
124
|
-
* @param resolution Grid resolution (lower = fewer hexagons)
|
|
125
|
-
*/
|
|
126
|
-
export declare function generateHexGrid(resolution?: number): CoverageHexGrid;
|
|
127
|
-
/**
|
|
128
|
-
* Update hex grid coverage values based on satellite footprints
|
|
129
|
-
*/
|
|
130
|
-
export declare function updateHexGridCoverage(grid: CoverageHexGrid, satellites: Satellite[], time: Date): CoverageHexGrid;
|
|
131
|
-
export declare function dot(a: Vector3D, b: Vector3D): number;
|
|
132
|
-
export declare function cross(a: Vector3D, b: Vector3D): Vector3D;
|
|
133
|
-
export declare function magnitude(v: Vector3D): number;
|
|
134
|
-
export declare function normalize(v: Vector3D): Vector3D;
|
|
135
|
-
export declare function subtract(a: Vector3D, b: Vector3D): Vector3D;
|
|
136
|
-
export declare function add(a: Vector3D, b: Vector3D): Vector3D;
|
|
137
|
-
export declare function scale(v: Vector3D, s: number): Vector3D;
|
|
138
|
-
export declare function distance(a: Vector3D, b: Vector3D): number;
|
|
139
|
-
export declare function lerp(a: Vector3D, b: Vector3D, t: number): Vector3D;
|
|
140
|
-
/**
|
|
141
|
-
* Ease-out cubic function
|
|
142
|
-
*/
|
|
26
|
+
/** Cubic ease-out curve, used by camera fly-to animations. */
|
|
143
27
|
export declare function easeOutCubic(t: number): number;
|
|
144
|
-
/**
|
|
145
|
-
* Ease-in-out cubic function
|
|
146
|
-
*/
|
|
147
|
-
export declare function easeInOutCubic(t: number): number;
|
|
148
|
-
/**
|
|
149
|
-
* Smooth step function
|
|
150
|
-
*/
|
|
151
|
-
export declare function smoothstep(edge0: number, edge1: number, x: number): number;
|
|
152
|
-
/**
|
|
153
|
-
* Interpolate between two colors
|
|
154
|
-
*/
|
|
155
|
-
export declare function lerpColor(color1: string, color2: string, t: number): string;
|
|
156
|
-
/**
|
|
157
|
-
* Hex to RGB
|
|
158
|
-
*/
|
|
159
|
-
export declare function hexToRgb(hex: string): {
|
|
160
|
-
r: number;
|
|
161
|
-
g: number;
|
|
162
|
-
b: number;
|
|
163
|
-
} | null;
|
|
164
|
-
/**
|
|
165
|
-
* Get color from value (0-1) on a gradient scale
|
|
166
|
-
*/
|
|
167
|
-
export declare function getGradientColor(value: number, colors?: string[]): string;
|
|
168
|
-
/**
|
|
169
|
-
* Format time duration as HH:MM:SS
|
|
170
|
-
*/
|
|
171
|
-
export declare function formatDuration(seconds: number): string;
|
|
172
|
-
/**
|
|
173
|
-
* Format distance in appropriate units
|
|
174
|
-
*/
|
|
175
|
-
export declare function formatDistance(km: number): string;
|
|
176
|
-
/**
|
|
177
|
-
* Format velocity
|
|
178
|
-
*/
|
|
179
|
-
export declare function formatVelocity(kmPerSec: number): string;
|
|
180
|
-
/**
|
|
181
|
-
* Format date/time for display
|
|
182
|
-
*/
|
|
183
|
-
export declare function formatDateTime(date: Date): string;
|
|
@@ -1,9 +1,28 @@
|
|
|
1
1
|
const EARTH_RADIUS_KM = 6371;
|
|
2
2
|
const DEG_TO_RAD = Math.PI / 180;
|
|
3
3
|
const RAD_TO_DEG = 180 / Math.PI;
|
|
4
|
+
const SCENE_EARTH_RADIUS = 3e3;
|
|
5
|
+
const KM_TO_SCENE = SCENE_EARTH_RADIUS / EARTH_RADIUS_KM;
|
|
6
|
+
function latLonAltToCartesian(lat, lon, altKm = 0, earthRadius = SCENE_EARTH_RADIUS) {
|
|
7
|
+
const r = earthRadius + altKm * KM_TO_SCENE;
|
|
8
|
+
const phi = (90 - lat) * DEG_TO_RAD;
|
|
9
|
+
const theta = (lon + 180) * DEG_TO_RAD;
|
|
10
|
+
return {
|
|
11
|
+
x: -r * Math.sin(phi) * Math.cos(theta),
|
|
12
|
+
y: r * Math.cos(phi),
|
|
13
|
+
z: r * Math.sin(phi) * Math.sin(theta)
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function easeOutCubic(t) {
|
|
17
|
+
return 1 - Math.pow(1 - t, 3);
|
|
18
|
+
}
|
|
4
19
|
export {
|
|
5
20
|
DEG_TO_RAD,
|
|
6
21
|
EARTH_RADIUS_KM,
|
|
7
|
-
|
|
22
|
+
KM_TO_SCENE,
|
|
23
|
+
RAD_TO_DEG,
|
|
24
|
+
SCENE_EARTH_RADIUS,
|
|
25
|
+
easeOutCubic,
|
|
26
|
+
latLonAltToCartesian
|
|
8
27
|
};
|
|
9
28
|
//# sourceMappingURL=ZenSpace3DUtils.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ZenSpace3DUtils.js","sources":["../../../src/react/3d/ZenSpace3DUtils.ts"],"sourcesContent":["/**\r\n * @zendir/ui - ZenSpace3D Utility Functions\r\n * \r\n * Coordinate transformations, TLE propagation, coverage calculations,\r\n * and other utilities for 3D space visualization.\r\n */\r\n\r\nimport type {\r\n Vector3D,\r\n LatLonAlt,\r\n SphericalCoords,\r\n TLEData,\r\n Satellite,\r\n OrbitPath,\r\n CoverageHexGrid,\r\n VisibilityCone as _VisibilityCone,\r\n} from './ZenSpace3DTypes';\r\n\r\n// =============================================================================\r\n// Constants\r\n// =============================================================================\r\n\r\n/** Earth's radius in km */\r\nexport const EARTH_RADIUS_KM = 6371;\r\n\r\n/** Earth's gravitational parameter (km³/s²) */\r\nexport const EARTH_MU = 398600.4418;\r\n\r\n/** Astronomical Unit in km */\r\nexport const AU_KM = 149597870.7;\r\n\r\n/** Degrees to radians */\r\nexport const DEG_TO_RAD = Math.PI / 180;\r\n\r\n/** Radians to degrees */\r\nexport const RAD_TO_DEG = 180 / Math.PI;\r\n\r\n/** J2000 epoch (January 1, 2000, 12:00 TT) */\r\nexport const J2000_EPOCH = new Date('2000-01-01T12:00:00Z');\r\n\r\n/** Seconds per day */\r\nexport const SECONDS_PER_DAY = 86400;\r\n\r\n/** Minutes per day */\r\nexport const MINUTES_PER_DAY = 1440;\r\n\r\n// =============================================================================\r\n// Scene Scale Constants\r\n// =============================================================================\r\n\r\n/** Scene Earth radius (render units) */\r\nexport const SCENE_EARTH_RADIUS = 3000;\r\n\r\n/** Scene scale factor (km to render units) */\r\nexport const KM_TO_SCENE = SCENE_EARTH_RADIUS / EARTH_RADIUS_KM;\r\n\r\n/** Scene scale for Solar System (different scale) */\r\nexport const SOLAR_SYSTEM_SCALE = 1; // 1 unit = 1 km in solar system mode\r\n\r\n// =============================================================================\r\n// Coordinate Conversions\r\n// =============================================================================\r\n\r\n/**\r\n * Convert latitude/longitude/altitude to Cartesian (ECI-like for rendering)\r\n * @param lat Latitude in degrees\r\n * @param lon Longitude in degrees\r\n * @param altKm Altitude in kilometers\r\n * @param earthRadius Scene radius for Earth\r\n * @returns Cartesian coordinates\r\n */\r\nexport function latLonAltToCartesian(\r\n lat: number,\r\n lon: number,\r\n altKm: number = 0,\r\n earthRadius: number = SCENE_EARTH_RADIUS\r\n): Vector3D {\r\n const r = earthRadius + altKm * KM_TO_SCENE;\r\n const phi = (90 - lat) * DEG_TO_RAD;\r\n const theta = (lon + 180) * DEG_TO_RAD;\r\n \r\n return {\r\n x: -r * Math.sin(phi) * Math.cos(theta),\r\n y: r * Math.cos(phi),\r\n z: r * Math.sin(phi) * Math.sin(theta),\r\n };\r\n}\r\n\r\n/**\r\n * Convert Cartesian to latitude/longitude/altitude\r\n * @param position Cartesian position\r\n * @param earthRadius Scene radius for Earth\r\n * @returns Lat/Lon/Alt\r\n */\r\nexport function cartesianToLatLonAlt(\r\n position: Vector3D,\r\n earthRadius: number = SCENE_EARTH_RADIUS\r\n): LatLonAlt {\r\n const r = Math.sqrt(position.x ** 2 + position.y ** 2 + position.z ** 2);\r\n const lat = 90 - Math.acos(position.y / r) * RAD_TO_DEG;\r\n const lon = Math.atan2(position.z, -position.x) * RAD_TO_DEG - 180;\r\n const alt = (r - earthRadius) / KM_TO_SCENE;\r\n \r\n return { latitude: lat, longitude: lon, altitude: alt };\r\n}\r\n\r\n/**\r\n * Convert Cartesian to spherical coordinates\r\n */\r\nexport function cartesianToSpherical(position: Vector3D): SphericalCoords {\r\n const radius = Math.sqrt(position.x ** 2 + position.y ** 2 + position.z ** 2);\r\n const theta = Math.atan2(position.z, position.x);\r\n const phi = Math.acos(position.y / radius);\r\n \r\n return { radius, theta, phi };\r\n}\r\n\r\n/**\r\n * Convert spherical to Cartesian coordinates\r\n */\r\nexport function sphericalToCartesian(coords: SphericalCoords): Vector3D {\r\n return {\r\n x: coords.radius * Math.sin(coords.phi) * Math.cos(coords.theta),\r\n y: coords.radius * Math.cos(coords.phi),\r\n z: coords.radius * Math.sin(coords.phi) * Math.sin(coords.theta),\r\n };\r\n}\r\n\r\n/**\r\n * Convert ECI (Earth-Centered Inertial) to ECEF (Earth-Centered Earth-Fixed)\r\n * @param eci ECI position (km)\r\n * @param gmst Greenwich Mean Sidereal Time (radians)\r\n */\r\nexport function eciToEcef(eci: Vector3D, gmst: number): Vector3D {\r\n const cosGmst = Math.cos(gmst);\r\n const sinGmst = Math.sin(gmst);\r\n \r\n return {\r\n x: eci.x * cosGmst + eci.y * sinGmst,\r\n y: -eci.x * sinGmst + eci.y * cosGmst,\r\n z: eci.z,\r\n };\r\n}\r\n\r\n/**\r\n * Calculate Greenwich Mean Sidereal Time\r\n * @param date Date/time\r\n * @returns GMST in radians\r\n */\r\nexport function calculateGMST(date: Date): number {\r\n const jd = dateToJulianDate(date);\r\n const t = (jd - 2451545.0) / 36525.0;\r\n \r\n // GMST in degrees\r\n let gmst = 280.46061837 + \r\n 360.98564736629 * (jd - 2451545.0) + \r\n 0.000387933 * t * t - \r\n t * t * t / 38710000.0;\r\n \r\n // Normalize to 0-360\r\n gmst = gmst % 360;\r\n if (gmst < 0) gmst += 360;\r\n \r\n return gmst * DEG_TO_RAD;\r\n}\r\n\r\n/**\r\n * Convert Date to Julian Date\r\n */\r\nexport function dateToJulianDate(date: Date): number {\r\n const year = date.getUTCFullYear();\r\n const month = date.getUTCMonth() + 1;\r\n const day = date.getUTCDate();\r\n const hour = date.getUTCHours();\r\n const minute = date.getUTCMinutes();\r\n const second = date.getUTCSeconds();\r\n \r\n let y = year;\r\n let m = month;\r\n \r\n if (m <= 2) {\r\n y -= 1;\r\n m += 12;\r\n }\r\n \r\n const a = Math.floor(y / 100);\r\n const b = 2 - a + Math.floor(a / 4);\r\n \r\n const jd = Math.floor(365.25 * (y + 4716)) +\r\n Math.floor(30.6001 * (m + 1)) +\r\n day + b - 1524.5 +\r\n (hour + minute / 60 + second / 3600) / 24;\r\n \r\n return jd;\r\n}\r\n\r\n// =============================================================================\r\n// TLE Parsing & Propagation (Simplified SGP4)\r\n// =============================================================================\r\n\r\n/**\r\n * Parse Two-Line Element set\r\n */\r\nexport function parseTLE(line1: string, line2: string): TLEData | null {\r\n try {\r\n // Line 1 parsing\r\n const epochYear = parseInt(line1.substring(18, 20));\r\n const epochDay = parseFloat(line1.substring(20, 32));\r\n const bstar = parseScientificNotation(line1.substring(53, 61));\r\n \r\n // Line 2 parsing\r\n const inclination = parseFloat(line2.substring(8, 16));\r\n const raan = parseFloat(line2.substring(17, 25));\r\n const eccentricityStr = '0.' + line2.substring(26, 33);\r\n const eccentricity = parseFloat(eccentricityStr);\r\n const argOfPerigee = parseFloat(line2.substring(34, 42));\r\n const meanAnomaly = parseFloat(line2.substring(43, 51));\r\n const meanMotion = parseFloat(line2.substring(52, 63));\r\n \r\n // Calculate epoch date\r\n const fullYear = epochYear < 57 ? 2000 + epochYear : 1900 + epochYear;\r\n const epoch = new Date(Date.UTC(fullYear, 0, 1));\r\n epoch.setTime(epoch.getTime() + (epochDay - 1) * SECONDS_PER_DAY * 1000);\r\n \r\n return {\r\n line1,\r\n line2,\r\n epoch,\r\n meanMotion,\r\n eccentricity,\r\n inclination,\r\n raan,\r\n argOfPerigee,\r\n meanAnomaly,\r\n bstar,\r\n };\r\n } catch (e) {\r\n if (import.meta.env.DEV) {\r\n console.error('Failed to parse TLE:', e);\r\n }\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Parse TLE scientific notation (e.g., \" 12345-4\" = 0.12345e-4)\r\n */\r\nfunction parseScientificNotation(str: string): number {\r\n const trimmed = str.trim();\r\n if (trimmed.length === 0) return 0;\r\n \r\n // Find the position of the exponent sign\r\n let mantissa: string;\r\n let exponent: number;\r\n \r\n const lastSignPos = Math.max(trimmed.lastIndexOf('+'), trimmed.lastIndexOf('-'));\r\n if (lastSignPos > 0) {\r\n mantissa = '0.' + trimmed.substring(0, lastSignPos).replace(/[^0-9]/g, '');\r\n exponent = parseInt(trimmed.substring(lastSignPos));\r\n } else {\r\n mantissa = '0.' + trimmed.replace(/[^0-9]/g, '');\r\n exponent = 0;\r\n }\r\n \r\n return parseFloat(mantissa) * Math.pow(10, exponent);\r\n}\r\n\r\n/**\r\n * Simplified SGP4 propagation\r\n * @param tle TLE data\r\n * @param minutesFromEpoch Minutes from TLE epoch\r\n * @returns Position in km (ECI coordinates)\r\n */\r\nexport function propagateSGP4Simple(tle: TLEData, minutesFromEpoch: number): Vector3D {\r\n // Semi-major axis from mean motion\r\n const n = tle.meanMotion * 2 * Math.PI / MINUTES_PER_DAY; // rad/min\r\n const a = Math.pow(EARTH_MU / (n * n / 60 / 60), 1/3); // km\r\n \r\n // Current mean anomaly\r\n const M = (tle.meanAnomaly + (360 * tle.meanMotion * minutesFromEpoch / MINUTES_PER_DAY)) % 360;\r\n const M_rad = M * DEG_TO_RAD;\r\n \r\n // Solve Kepler's equation for eccentric anomaly (simplified Newton-Raphson)\r\n let E = M_rad;\r\n for (let i = 0; i < 10; i++) {\r\n E = M_rad + tle.eccentricity * Math.sin(E);\r\n }\r\n \r\n // True anomaly\r\n const cosE = Math.cos(E);\r\n const sinE = Math.sin(E);\r\n const nu = Math.atan2(\r\n Math.sqrt(1 - tle.eccentricity ** 2) * sinE,\r\n cosE - tle.eccentricity\r\n );\r\n \r\n // Distance\r\n const r = a * (1 - tle.eccentricity * cosE);\r\n \r\n // Position in orbital plane\r\n const xOrb = r * Math.cos(nu);\r\n const yOrb = r * Math.sin(nu);\r\n \r\n // RAAN and inclination with simple precession\r\n const raanRad = tle.raan * DEG_TO_RAD;\r\n const incRad = tle.inclination * DEG_TO_RAD;\r\n const argPeriRad = tle.argOfPerigee * DEG_TO_RAD;\r\n \r\n // Rotation matrices\r\n const cosRaan = Math.cos(raanRad);\r\n const sinRaan = Math.sin(raanRad);\r\n const cosInc = Math.cos(incRad);\r\n const sinInc = Math.sin(incRad);\r\n const cosArgPeri = Math.cos(argPeriRad);\r\n const sinArgPeri = Math.sin(argPeriRad);\r\n \r\n // Transform to ECI\r\n const x = (cosRaan * cosArgPeri - sinRaan * sinArgPeri * cosInc) * xOrb +\r\n (-cosRaan * sinArgPeri - sinRaan * cosArgPeri * cosInc) * yOrb;\r\n const y = (sinRaan * cosArgPeri + cosRaan * sinArgPeri * cosInc) * xOrb +\r\n (-sinRaan * sinArgPeri + cosRaan * cosArgPeri * cosInc) * yOrb;\r\n const z = (sinArgPeri * sinInc) * xOrb + (cosArgPeri * sinInc) * yOrb;\r\n \r\n return { x, y, z };\r\n}\r\n\r\n/**\r\n * Propagate satellite to specific time\r\n * @param satellite Satellite with TLE\r\n * @param time Target time\r\n * @returns Position in km (ECI)\r\n */\r\nexport function propagateSatellite(satellite: Satellite, time: Date): Vector3D | null {\r\n if (!satellite.tle) return null;\r\n \r\n const minutesFromEpoch = (time.getTime() - satellite.tle.epoch.getTime()) / 60000;\r\n return propagateSGP4Simple(satellite.tle, minutesFromEpoch);\r\n}\r\n\r\n/**\r\n * Generate orbit path for a satellite\r\n * @param satellite Satellite with TLE\r\n * @param startTime Start time\r\n * @param duration Duration in minutes\r\n * @param steps Number of steps\r\n */\r\nexport function generateOrbitPath(\r\n satellite: Satellite,\r\n startTime: Date,\r\n duration: number = 90,\r\n steps: number = 180\r\n): OrbitPath | null {\r\n if (!satellite.tle) return null;\r\n \r\n const points: Vector3D[] = [];\r\n const startMinutes = (startTime.getTime() - satellite.tle.epoch.getTime()) / 60000;\r\n \r\n for (let i = 0; i <= steps; i++) {\r\n const minutesFromEpoch = startMinutes + (i / steps) * duration;\r\n const pos = propagateSGP4Simple(satellite.tle, minutesFromEpoch);\r\n \r\n // Convert to scene coordinates\r\n points.push({\r\n x: pos.x * KM_TO_SCENE,\r\n y: pos.z * KM_TO_SCENE, // Swap Y/Z for Three.js\r\n z: pos.y * KM_TO_SCENE,\r\n });\r\n }\r\n \r\n return {\r\n objectId: satellite.id,\r\n points,\r\n timeSpan: duration * 60,\r\n isFuture: true,\r\n color: satellite.color || '#22d3ee',\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Coverage & Visibility Calculations\r\n// =============================================================================\r\n\r\n/**\r\n * Calculate if a satellite is visible from a ground station\r\n * @param satPos Satellite position (scene units)\r\n * @param gsLatLon Ground station lat/lon\r\n * @param minElevation Minimum elevation angle (degrees)\r\n */\r\nexport function isVisible(\r\n satPos: Vector3D,\r\n gsLatLon: { latitude: number; longitude: number },\r\n minElevation: number = 5\r\n): boolean {\r\n const gsPos = latLonAltToCartesian(gsLatLon.latitude, gsLatLon.longitude, 0);\r\n \r\n // Vector from ground station to satellite\r\n const toSat = {\r\n x: satPos.x - gsPos.x,\r\n y: satPos.y - gsPos.y,\r\n z: satPos.z - gsPos.z,\r\n };\r\n \r\n // Ground station \"up\" vector (normal to Earth surface)\r\n const up = normalize(gsPos);\r\n \r\n // Calculate elevation angle\r\n const elevation = 90 - Math.acos(dot(normalize(toSat), up)) * RAD_TO_DEG;\r\n \r\n return elevation >= minElevation;\r\n}\r\n\r\n/**\r\n * Calculate visibility cone vertices for rendering\r\n * @param gsLatLon Ground station position\r\n * @param minElevation Minimum elevation angle\r\n * @param altitude Altitude for cone apex (km)\r\n * @param segments Number of segments for cone circle\r\n */\r\nexport function calculateVisibilityConeGeometry(\r\n gsLatLon: { latitude: number; longitude: number },\r\n minElevation: number = 5,\r\n altitude: number = 2000,\r\n segments: number = 32\r\n): Vector3D[] {\r\n const gsPos = latLonAltToCartesian(gsLatLon.latitude, gsLatLon.longitude, 0);\r\n const vertices: Vector3D[] = [];\r\n \r\n // Cone apex is at ground station\r\n vertices.push(gsPos);\r\n \r\n // Calculate cone opening angle\r\n const coneAngle = (90 - minElevation) * DEG_TO_RAD;\r\n const coneRadius = altitude * Math.tan(coneAngle);\r\n \r\n // Get local tangent plane vectors\r\n const up = normalize(gsPos);\r\n const east = normalize(cross({ x: 0, y: 1, z: 0 }, up));\r\n const north = cross(up, east);\r\n \r\n // Generate cone base circle\r\n for (let i = 0; i <= segments; i++) {\r\n const angle = (i / segments) * Math.PI * 2;\r\n const basePoint = {\r\n x: gsPos.x + up.x * altitude * KM_TO_SCENE + \r\n (east.x * Math.cos(angle) + north.x * Math.sin(angle)) * coneRadius * KM_TO_SCENE,\r\n y: gsPos.y + up.y * altitude * KM_TO_SCENE + \r\n (east.y * Math.cos(angle) + north.y * Math.sin(angle)) * coneRadius * KM_TO_SCENE,\r\n z: gsPos.z + up.z * altitude * KM_TO_SCENE + \r\n (east.z * Math.cos(angle) + north.z * Math.sin(angle)) * coneRadius * KM_TO_SCENE,\r\n };\r\n vertices.push(basePoint);\r\n }\r\n \r\n return vertices;\r\n}\r\n\r\n/**\r\n * Generate footprint polygon for a satellite\r\n * @param satPos Satellite position (scene units)\r\n * @param minElevation Minimum elevation angle\r\n * @param segments Number of segments\r\n */\r\nexport function calculateFootprint(\r\n satPos: Vector3D,\r\n minElevation: number = 5,\r\n segments: number = 36\r\n): Array<{ latitude: number; longitude: number }> {\r\n const satLla = cartesianToLatLonAlt(satPos);\r\n const footprint: Array<{ latitude: number; longitude: number }> = [];\r\n \r\n // Simplified footprint calculation\r\n // Central angle of visibility circle\r\n const earthAngularRadius = Math.asin(EARTH_RADIUS_KM / (EARTH_RADIUS_KM + satLla.altitude));\r\n const elevAngle = minElevation * DEG_TO_RAD;\r\n const nadir = Math.PI / 2 - elevAngle - earthAngularRadius;\r\n const footprintRadius = nadir * RAD_TO_DEG;\r\n \r\n for (let i = 0; i < segments; i++) {\r\n const bearing = (i / segments) * 360;\r\n const point = destinationPoint(\r\n satLla.latitude,\r\n satLla.longitude,\r\n footprintRadius * 111.32, // Approximate km per degree\r\n bearing\r\n );\r\n footprint.push(point);\r\n }\r\n \r\n return footprint;\r\n}\r\n\r\n/**\r\n * Calculate destination point given start, distance, and bearing\r\n */\r\nfunction destinationPoint(\r\n lat: number,\r\n lon: number,\r\n distanceKm: number,\r\n bearing: number\r\n): { latitude: number; longitude: number } {\r\n const R = EARTH_RADIUS_KM;\r\n const d = distanceKm / R;\r\n const brng = bearing * DEG_TO_RAD;\r\n const lat1 = lat * DEG_TO_RAD;\r\n const lon1 = lon * DEG_TO_RAD;\r\n \r\n const lat2 = Math.asin(\r\n Math.sin(lat1) * Math.cos(d) +\r\n Math.cos(lat1) * Math.sin(d) * Math.cos(brng)\r\n );\r\n \r\n const lon2 = lon1 + Math.atan2(\r\n Math.sin(brng) * Math.sin(d) * Math.cos(lat1),\r\n Math.cos(d) - Math.sin(lat1) * Math.sin(lat2)\r\n );\r\n \r\n return {\r\n latitude: lat2 * RAD_TO_DEG,\r\n longitude: lon2 * RAD_TO_DEG,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Hexagonal Grid for Coverage\r\n// =============================================================================\r\n\r\n/**\r\n * Generate a hexagonal grid covering the globe\r\n * @param resolution Grid resolution (lower = fewer hexagons)\r\n */\r\nexport function generateHexGrid(resolution: number = 2): CoverageHexGrid {\r\n const hexagons: CoverageHexGrid['hexagons'] = [];\r\n \r\n // Simplified hex grid generation (not true H3, but visually similar)\r\n const latStep = 180 / (resolution * 8);\r\n const lonStep = 360 / (resolution * 16);\r\n \r\n let id = 0;\r\n for (let lat = -90 + latStep / 2; lat < 90; lat += latStep) {\r\n // Adjust longitude step for latitude (narrower near poles)\r\n const adjustedLonStep = lonStep / Math.cos(lat * DEG_TO_RAD);\r\n const offset = (Math.floor((lat + 90) / latStep) % 2) * (adjustedLonStep / 2);\r\n \r\n for (let lon = -180 + offset; lon < 180; lon += adjustedLonStep) {\r\n hexagons.push({\r\n id: `hex_${id++}`,\r\n value: 0,\r\n center: { latitude: lat, longitude: lon },\r\n });\r\n }\r\n }\r\n \r\n return {\r\n resolution,\r\n hexagons,\r\n colorScale: { min: '#1a1a2e', max: '#00ff88' },\r\n };\r\n}\r\n\r\n/**\r\n * Update hex grid coverage values based on satellite footprints\r\n */\r\nexport function updateHexGridCoverage(\r\n grid: CoverageHexGrid,\r\n satellites: Satellite[],\r\n time: Date\r\n): CoverageHexGrid {\r\n // Clone grid\r\n const updatedGrid = {\r\n ...grid,\r\n hexagons: grid.hexagons.map(h => ({ ...h, value: 0 })),\r\n };\r\n \r\n satellites.forEach(sat => {\r\n const pos = propagateSatellite(sat, time);\r\n if (!pos) return;\r\n \r\n const scenePos = {\r\n x: pos.x * KM_TO_SCENE,\r\n y: pos.z * KM_TO_SCENE,\r\n z: pos.y * KM_TO_SCENE,\r\n };\r\n \r\n const footprint = calculateFootprint(scenePos);\r\n \r\n // Check each hexagon\r\n updatedGrid.hexagons.forEach(hex => {\r\n const inFootprint = isPointInPolygon(hex.center, footprint);\r\n if (inFootprint) {\r\n hex.value = Math.min(1, hex.value + 0.2);\r\n }\r\n });\r\n });\r\n \r\n return updatedGrid;\r\n}\r\n\r\n/**\r\n * Point-in-polygon test (simplified)\r\n */\r\nfunction isPointInPolygon(\r\n point: { latitude: number; longitude: number },\r\n polygon: Array<{ latitude: number; longitude: number }>\r\n): boolean {\r\n let inside = false;\r\n const n = polygon.length;\r\n \r\n for (let i = 0, j = n - 1; i < n; j = i++) {\r\n const xi = polygon[i].longitude;\r\n const yi = polygon[i].latitude;\r\n const xj = polygon[j].longitude;\r\n const yj = polygon[j].latitude;\r\n \r\n if (((yi > point.latitude) !== (yj > point.latitude)) &&\r\n (point.longitude < (xj - xi) * (point.latitude - yi) / (yj - yi) + xi)) {\r\n inside = !inside;\r\n }\r\n }\r\n \r\n return inside;\r\n}\r\n\r\n// =============================================================================\r\n// Vector Math Utilities\r\n// =============================================================================\r\n\r\nexport function dot(a: Vector3D, b: Vector3D): number {\r\n return a.x * b.x + a.y * b.y + a.z * b.z;\r\n}\r\n\r\nexport function cross(a: Vector3D, b: Vector3D): Vector3D {\r\n return {\r\n x: a.y * b.z - a.z * b.y,\r\n y: a.z * b.x - a.x * b.z,\r\n z: a.x * b.y - a.y * b.x,\r\n };\r\n}\r\n\r\nexport function magnitude(v: Vector3D): number {\r\n return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z);\r\n}\r\n\r\nexport function normalize(v: Vector3D): Vector3D {\r\n const m = magnitude(v);\r\n if (m === 0) return { x: 0, y: 0, z: 0 };\r\n return { x: v.x / m, y: v.y / m, z: v.z / m };\r\n}\r\n\r\nexport function subtract(a: Vector3D, b: Vector3D): Vector3D {\r\n return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z };\r\n}\r\n\r\nexport function add(a: Vector3D, b: Vector3D): Vector3D {\r\n return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z };\r\n}\r\n\r\nexport function scale(v: Vector3D, s: number): Vector3D {\r\n return { x: v.x * s, y: v.y * s, z: v.z * s };\r\n}\r\n\r\nexport function distance(a: Vector3D, b: Vector3D): number {\r\n return magnitude(subtract(a, b));\r\n}\r\n\r\nexport function lerp(a: Vector3D, b: Vector3D, t: number): Vector3D {\r\n return {\r\n x: a.x + (b.x - a.x) * t,\r\n y: a.y + (b.y - a.y) * t,\r\n z: a.z + (b.z - a.z) * t,\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// Animation Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Ease-out cubic function\r\n */\r\nexport function easeOutCubic(t: number): number {\r\n return 1 - Math.pow(1 - t, 3);\r\n}\r\n\r\n/**\r\n * Ease-in-out cubic function\r\n */\r\nexport function easeInOutCubic(t: number): number {\r\n return t < 0.5\r\n ? 4 * t * t * t\r\n : 1 - Math.pow(-2 * t + 2, 3) / 2;\r\n}\r\n\r\n/**\r\n * Smooth step function\r\n */\r\nexport function smoothstep(edge0: number, edge1: number, x: number): number {\r\n const t = Math.max(0, Math.min(1, (x - edge0) / (edge1 - edge0)));\r\n return t * t * (3 - 2 * t);\r\n}\r\n\r\n// =============================================================================\r\n// Color Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Interpolate between two colors\r\n */\r\nexport function lerpColor(color1: string, color2: string, t: number): string {\r\n const c1 = hexToRgb(color1);\r\n const c2 = hexToRgb(color2);\r\n \r\n if (!c1 || !c2) return color1;\r\n \r\n const r = Math.round(c1.r + (c2.r - c1.r) * t);\r\n const g = Math.round(c1.g + (c2.g - c1.g) * t);\r\n const b = Math.round(c1.b + (c2.b - c1.b) * t);\r\n \r\n return `rgb(${r}, ${g}, ${b})`;\r\n}\r\n\r\n/**\r\n * Hex to RGB\r\n */\r\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } | null {\r\n const result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})$/i.exec(hex);\r\n return result\r\n ? {\r\n r: parseInt(result[1], 16),\r\n g: parseInt(result[2], 16),\r\n b: parseInt(result[3], 16),\r\n }\r\n : null;\r\n}\r\n\r\n/**\r\n * Get color from value (0-1) on a gradient scale\r\n */\r\nexport function getGradientColor(\r\n value: number,\r\n colors: string[] = ['#1a1a2e', '#0f3460', '#16c79a', '#ff6b6b']\r\n): string {\r\n const clampedValue = Math.max(0, Math.min(1, value));\r\n const scaledValue = clampedValue * (colors.length - 1);\r\n const index = Math.floor(scaledValue);\r\n const t = scaledValue - index;\r\n \r\n if (index >= colors.length - 1) return colors[colors.length - 1];\r\n \r\n return lerpColor(colors[index], colors[index + 1], t);\r\n}\r\n\r\n// =============================================================================\r\n// Format Utilities\r\n// =============================================================================\r\n\r\n/**\r\n * Format time duration as HH:MM:SS\r\n */\r\nexport function formatDuration(seconds: number): string {\r\n const h = Math.floor(seconds / 3600);\r\n const m = Math.floor((seconds % 3600) / 60);\r\n const s = Math.floor(seconds % 60);\r\n \r\n return `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;\r\n}\r\n\r\n/**\r\n * Format distance in appropriate units\r\n */\r\nexport function formatDistance(km: number): string {\r\n if (km < 1) {\r\n return `${(km * 1000).toFixed(0)} m`;\r\n } else if (km < 1000) {\r\n return `${km.toFixed(1)} km`;\r\n } else if (km < AU_KM / 100) {\r\n return `${(km / 1000).toFixed(2)} thousand km`;\r\n } else {\r\n return `${(km / AU_KM).toFixed(4)} AU`;\r\n }\r\n}\r\n\r\n/**\r\n * Format velocity\r\n */\r\nexport function formatVelocity(kmPerSec: number): string {\r\n return `${kmPerSec.toFixed(3)} km/s`;\r\n}\r\n\r\n/**\r\n * Format date/time for display\r\n */\r\nexport function formatDateTime(date: Date): string {\r\n return date.toISOString().replace('T', ' ').split('.')[0] + ' UTC';\r\n}\r\n"],"names":[],"mappings":"AAuBO,MAAM,kBAAkB;AASxB,MAAM,aAAa,KAAK,KAAK;AAG7B,MAAM,aAAa,MAAM,KAAK;"}
|
|
1
|
+
{"version":3,"file":"ZenSpace3DUtils.js","sources":["../../../src/react/3d/ZenSpace3DUtils.ts"],"sourcesContent":["/**\n * @zendir/ui - ZenSpace3D rendering math\n *\n * The minimal helper set needed by the live 3D backends:\n * • Earth + scene scaling constants used by the Three.js path\n * (`ZenSpace3D.tsx`) and the Cesium capture source\n * (`CesiumCaptureSource.ts`)\n * • `latLonAltToCartesian` — lat/lon/alt → render-space Cartesian\n * • `easeOutCubic` — camera-fly-to easing\n *\n * Higher-level orbital math (TLE/SGP4 propagation, GMST, visibility cones,\n * hex-grid coverage) was removed — those weren't consumed by either\n * backend. The Cesium backend uses Cesium's own `Transforms` for\n * ECI→ECEF, and the Three.js backend draws coverage from explicit\n * `SatelliteCoverage` props rather than computing it locally.\n */\n\nimport type { Vector3D } from './ZenSpace3DTypes';\n\n// ── Constants ─────────────────────────────────────────────────────────────────\n\n/** Earth's mean radius in km. */\nexport const EARTH_RADIUS_KM = 6371;\n\n/** Degrees → radians. */\nexport const DEG_TO_RAD = Math.PI / 180;\n\n/** Radians → degrees. */\nexport const RAD_TO_DEG = 180 / Math.PI;\n\n/** Earth radius in scene units (Three.js render space). */\nexport const SCENE_EARTH_RADIUS = 3000;\n\n/** Conversion factor: 1 km → scene units. */\nexport const KM_TO_SCENE = SCENE_EARTH_RADIUS / EARTH_RADIUS_KM;\n\n// ── Coordinate conversion ─────────────────────────────────────────────────────\n\n/**\n * Convert lat/lon/alt to a Cartesian point in scene space.\n *\n * Result is in *render units* (scaled by `KM_TO_SCENE`), suitable for\n * direct use in the Three.js scene graph. For ECI→ECEF on the Cesium\n * backend, use `Cesium.Transforms.computeTemeToPseudoFixedMatrix`.\n *\n * @param lat Latitude in degrees.\n * @param lon Longitude in degrees.\n * @param altKm Altitude above Earth surface in km (default 0).\n * @param earthRadius Scene radius for Earth (default `SCENE_EARTH_RADIUS`).\n */\nexport function latLonAltToCartesian(\n lat: number,\n lon: number,\n altKm: number = 0,\n earthRadius: number = SCENE_EARTH_RADIUS,\n): Vector3D {\n const r = earthRadius + altKm * KM_TO_SCENE;\n const phi = (90 - lat) * DEG_TO_RAD;\n const theta = (lon + 180) * DEG_TO_RAD;\n return {\n x: -r * Math.sin(phi) * Math.cos(theta),\n y: r * Math.cos(phi),\n z: r * Math.sin(phi) * Math.sin(theta),\n };\n}\n\n// ── Easing ────────────────────────────────────────────────────────────────────\n\n/** Cubic ease-out curve, used by camera fly-to animations. */\nexport function easeOutCubic(t: number): number {\n return 1 - Math.pow(1 - t, 3);\n}\n"],"names":[],"mappings":"AAsBO,MAAM,kBAAkB;AAGxB,MAAM,aAAa,KAAK,KAAK;AAG7B,MAAM,aAAa,MAAM,KAAK;AAG9B,MAAM,qBAAqB;AAG3B,MAAM,cAAc,qBAAqB;AAgBzC,SAAS,qBACd,KACA,KACA,QAAgB,GAChB,cAAsB,oBACZ;AACV,QAAM,IAAI,cAAc,QAAQ;AAChC,QAAM,OAAO,KAAK,OAAO;AACzB,QAAM,SAAS,MAAM,OAAO;AAC5B,SAAO;AAAA,IACL,GAAG,CAAC,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK;AAAA,IACtC,GAAG,IAAI,KAAK,IAAI,GAAG;AAAA,IACnB,GAAG,IAAI,KAAK,IAAI,GAAG,IAAI,KAAK,IAAI,KAAK;AAAA,EAAA;AAEzC;AAKO,SAAS,aAAa,GAAmB;AAC9C,SAAO,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC;AAC9B;"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
function rgbToLuma(r, g, b) {
|
|
2
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
3
|
+
}
|
|
4
|
+
async function meanLuminanceFromPngBytes(png) {
|
|
5
|
+
var _a;
|
|
6
|
+
if (typeof createImageBitmap !== "function" || typeof document === "undefined") {
|
|
7
|
+
return 0;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
const blob = new Blob([png], { type: "image/png" });
|
|
11
|
+
const bmp = await createImageBitmap(blob);
|
|
12
|
+
const w = bmp.width;
|
|
13
|
+
const h = bmp.height;
|
|
14
|
+
const canvas = document.createElement("canvas");
|
|
15
|
+
const step = Math.max(1, Math.floor(Math.sqrt(w * h / 4096)));
|
|
16
|
+
canvas.width = Math.ceil(w / step);
|
|
17
|
+
canvas.height = Math.ceil(h / step);
|
|
18
|
+
const ctx = canvas.getContext("2d");
|
|
19
|
+
if (!ctx) return 0;
|
|
20
|
+
ctx.drawImage(bmp, 0, 0, w, h, 0, 0, canvas.width, canvas.height);
|
|
21
|
+
const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
22
|
+
let sum = 0;
|
|
23
|
+
const n = data.length / 4;
|
|
24
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
25
|
+
sum += rgbToLuma(data[i], data[i + 1], data[i + 2]);
|
|
26
|
+
}
|
|
27
|
+
(_a = bmp.close) == null ? void 0 : _a.call(bmp);
|
|
28
|
+
return n > 0 ? sum / n : 0;
|
|
29
|
+
} catch {
|
|
30
|
+
return 0;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
async function isPngMostlyBlack(png, threshold = 5) {
|
|
34
|
+
const m = await meanLuminanceFromPngBytes(png);
|
|
35
|
+
return m < threshold;
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
isPngMostlyBlack,
|
|
39
|
+
meanLuminanceFromPngBytes,
|
|
40
|
+
rgbToLuma
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=capturePngAnalysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capturePngAnalysis.js","sources":["../../../src/react/3d/capturePngAnalysis.ts"],"sourcesContent":["/**\r\n * Lightweight PNG analysis for capture QA (brightness / \"all black\" detection).\r\n * Used by tests and optional runtime checks — keep dependency-free (no pngjs).\r\n */\r\n\r\n/** ITU-R BT.709 luma from RGB */\r\nexport function rgbToLuma(r: number, g: number, b: number): number {\r\n return 0.2126 * r + 0.7152 * g + 0.0722 * b;\r\n}\r\n\r\n/**\r\n * Sample mean luma of PNG bytes by drawing to a small canvas (browser / happy-dom).\r\n * Returns 0 if decode fails. For very large images, samples a grid (max ~4096 samples).\r\n */\r\nexport async function meanLuminanceFromPngBytes(png: Uint8Array): Promise<number> {\r\n if (typeof createImageBitmap !== 'function' || typeof document === 'undefined') {\r\n return 0;\r\n }\r\n try {\r\n const blob = new Blob([png as unknown as BlobPart], { type: 'image/png' });\r\n const bmp = await createImageBitmap(blob);\r\n const w = bmp.width;\r\n const h = bmp.height;\r\n const canvas = document.createElement('canvas');\r\n const step = Math.max(1, Math.floor(Math.sqrt((w * h) / 4096)));\r\n canvas.width = Math.ceil(w / step);\r\n canvas.height = Math.ceil(h / step);\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return 0;\r\n ctx.drawImage(bmp, 0, 0, w, h, 0, 0, canvas.width, canvas.height);\r\n const { data } = ctx.getImageData(0, 0, canvas.width, canvas.height);\r\n let sum = 0;\r\n const n = data.length / 4;\r\n for (let i = 0; i < data.length; i += 4) {\r\n sum += rgbToLuma(data[i], data[i + 1], data[i + 2]);\r\n }\r\n bmp.close?.();\r\n return n > 0 ? sum / n : 0;\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\n/**\r\n * True if the image is uniformly dark (likely failed render / empty GL buffer).\r\n * Threshold is mean luma on 0–255 scale (default 5 ≈ pure black).\r\n */\r\nexport async function isPngMostlyBlack(png: Uint8Array, threshold = 5): Promise<boolean> {\r\n const m = await meanLuminanceFromPngBytes(png);\r\n return m < threshold;\r\n}\r\n"],"names":[],"mappings":"AAMO,SAAS,UAAU,GAAW,GAAW,GAAmB;AACjE,SAAO,SAAS,IAAI,SAAS,IAAI,SAAS;AAC5C;AAMA,eAAsB,0BAA0B,KAAkC;AAR3E;AASL,MAAI,OAAO,sBAAsB,cAAc,OAAO,aAAa,aAAa;AAC9E,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,OAAO,IAAI,KAAK,CAAC,GAA0B,GAAG,EAAE,MAAM,aAAa;AACzE,UAAM,MAAM,MAAM,kBAAkB,IAAI;AACxC,UAAM,IAAI,IAAI;AACd,UAAM,IAAI,IAAI;AACd,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,UAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,KAAM,IAAI,IAAK,IAAI,CAAC,CAAC;AAC9D,WAAO,QAAQ,KAAK,KAAK,IAAI,IAAI;AACjC,WAAO,SAAS,KAAK,KAAK,IAAI,IAAI;AAClC,UAAM,MAAM,OAAO,WAAW,IAAI;AAClC,QAAI,CAAC,IAAK,QAAO;AACjB,QAAI,UAAU,KAAK,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AAChE,UAAM,EAAE,KAAA,IAAS,IAAI,aAAa,GAAG,GAAG,OAAO,OAAO,OAAO,MAAM;AACnE,QAAI,MAAM;AACV,UAAM,IAAI,KAAK,SAAS;AACxB,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,GAAG;AACvC,aAAO,UAAU,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC;AAAA,IACpD;AACA,cAAI,UAAJ;AACA,WAAO,IAAI,IAAI,MAAM,IAAI;AAAA,EAC3B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAMA,eAAsB,iBAAiB,KAAiB,YAAY,GAAqB;AACvF,QAAM,IAAI,MAAM,0BAA0B,GAAG;AAC7C,SAAO,IAAI;AACb;"}
|
package/dist/react/3d/index.d.ts
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @zendir/ui - 3D Components
|
|
3
3
|
*
|
|
4
|
-
* ZenSpace3D
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* Components:
|
|
8
|
-
* - ZenSpace3D: Unified 3D space visualization (Cesium default, Three.js fallback)
|
|
9
|
-
* - EarthViewer: Earth-focused 3D (Three.js, legacy)
|
|
10
|
-
* - SolarSystemViewer: Solar system (Three.js, legacy)
|
|
4
|
+
* `ZenSpace3D` is the single canonical 3D viewer. Cesium is used when the
|
|
5
|
+
* peer dep is installed (production path); a Three.js renderer is used
|
|
6
|
+
* otherwise. Pair it with `useSimulationScene` for live-data integration.
|
|
11
7
|
*/
|
|
12
8
|
export { ZenSpace3D, default as ZenSpace3DDefault } from './ZenSpace3D';
|
|
13
9
|
export { ZenSpace3DCesium } from './ZenSpace3DCesium';
|
|
14
10
|
export type { ZenSpace3DCesiumProps } from './ZenSpace3DCesium';
|
|
15
11
|
export type { ZenSpace3DProps, ZenSpace3DHandle, ViewMode, CameraMode, ObjectCategory, SpaceObject, Satellite, Debris, SpaceStation, Asteroid, TLEData, OrbitPath, ManeuverNode, VisibilityCone, SatelliteCoverage, CoverageRegion, CoverageHexGrid, OverpassInfo, OrbitDesignArc, CoverageCell, TimeState, SelectionState, CameraState, LayerVisibility, ToolType, ToolState, Vector3D, LatLonAlt, SphericalCoords, SceneConfig, SceneObject, ZenSpace3DCallbacks, } from './ZenSpace3DTypes';
|
|
16
|
-
export { latLonAltToCartesian,
|
|
12
|
+
export { latLonAltToCartesian, easeOutCubic, EARTH_RADIUS_KM, DEG_TO_RAD, RAD_TO_DEG, SCENE_EARTH_RADIUS, KM_TO_SCENE, } from './ZenSpace3DUtils';
|
|
17
13
|
export { atmosphereVertexShader, atmosphereFragmentShader, starsVertexShader, starsFragmentShader, coverageVertexShader, coverageFragmentShader, visibilityConeVertexShader, visibilityConeFragmentShader, orbitLineVertexShader, orbitLineFragmentShader, objectGlowVertexShader, objectGlowFragmentShader, selectionRingVertexShader, selectionRingFragmentShader, terminatorVertexShader, terminatorFragmentShader, gridVertexShader, gridFragmentShader, planetRingVertexShader, planetRingFragmentShader, debrisVertexShader, debrisFragmentShader, createAtmosphereUniforms, createStarsUniforms, createVisibilityConeUniforms, } from './ZenSpace3DShaders';
|
|
18
14
|
export { createCesiumCaptureSource, ecefMetersToSdkPosition, eulerXyzToHpr, ecefEulerXyzToHpr, computeDofBlurPx } from './CesiumCaptureSource';
|
|
19
15
|
export type { CesiumCaptureSourceOptions, CesiumCaptureSourceHandle } from './CesiumCaptureSource';
|
|
@@ -21,7 +17,5 @@ export type { CesiumCaptureSourceOptions, CesiumCaptureSourceHandle } from './Ce
|
|
|
21
17
|
export { rgbToLuma, meanLuminanceFromPngBytes, isPngMostlyBlack } from './capturePngAnalysis';
|
|
22
18
|
export { loadThree, isThreeLoaded } from './threeLoader';
|
|
23
19
|
export type { ThreeModule, OrbitControlsType } from './threeLoader';
|
|
24
|
-
export {
|
|
25
|
-
export type {
|
|
26
|
-
export { SolarSystemViewer } from './SolarSystemViewer';
|
|
27
|
-
export type { SolarSystemViewerProps, PlanetPosition } from './SolarSystemViewer';
|
|
20
|
+
export { useSimulationScene } from '../hooks/useSimulationScene';
|
|
21
|
+
export type { CelestialBody, PositionTickDiag, SimulationSceneClient, SimulationSceneObject, StructureDiag, UseSimulationSceneOptions, UseSimulationSceneResult, } from '../hooks/useSimulationScene';
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { ZenSpace3D, ZenSpace3D as ZenSpace3D2 } from "./ZenSpace3D.js";
|
|
2
|
+
import { ZenSpace3DCesium } from "./ZenSpace3DCesium.js";
|
|
3
|
+
import { DEG_TO_RAD, EARTH_RADIUS_KM, KM_TO_SCENE, RAD_TO_DEG, SCENE_EARTH_RADIUS, easeOutCubic, latLonAltToCartesian } from "./ZenSpace3DUtils.js";
|
|
4
|
+
import { atmosphereFragmentShader, atmosphereVertexShader, coverageFragmentShader, coverageVertexShader, createAtmosphereUniforms, createStarsUniforms, createVisibilityConeUniforms, debrisFragmentShader, debrisVertexShader, gridFragmentShader, gridVertexShader, objectGlowFragmentShader, objectGlowVertexShader, orbitLineFragmentShader, orbitLineVertexShader, planetRingFragmentShader, planetRingVertexShader, selectionRingFragmentShader, selectionRingVertexShader, starsFragmentShader, starsVertexShader, terminatorFragmentShader, terminatorVertexShader, visibilityConeFragmentShader, visibilityConeVertexShader } from "./ZenSpace3DShaders.js";
|
|
5
|
+
import { computeDofBlurPx, createCesiumCaptureSource, ecefEulerXyzToHpr, ecefMetersToSdkPosition, eulerXyzToHpr } from "./CesiumCaptureSource.js";
|
|
6
|
+
import { isPngMostlyBlack, meanLuminanceFromPngBytes, rgbToLuma } from "./capturePngAnalysis.js";
|
|
7
|
+
import { isThreeLoaded, loadThree } from "./threeLoader.js";
|
|
8
|
+
import { useSimulationScene } from "../hooks/useSimulationScene.js";
|
|
9
|
+
export {
|
|
10
|
+
DEG_TO_RAD,
|
|
11
|
+
EARTH_RADIUS_KM,
|
|
12
|
+
KM_TO_SCENE,
|
|
13
|
+
RAD_TO_DEG,
|
|
14
|
+
SCENE_EARTH_RADIUS,
|
|
15
|
+
ZenSpace3D,
|
|
16
|
+
ZenSpace3DCesium,
|
|
17
|
+
ZenSpace3D2 as ZenSpace3DDefault,
|
|
18
|
+
atmosphereFragmentShader,
|
|
19
|
+
atmosphereVertexShader,
|
|
20
|
+
computeDofBlurPx,
|
|
21
|
+
coverageFragmentShader,
|
|
22
|
+
coverageVertexShader,
|
|
23
|
+
createAtmosphereUniforms,
|
|
24
|
+
createCesiumCaptureSource,
|
|
25
|
+
createStarsUniforms,
|
|
26
|
+
createVisibilityConeUniforms,
|
|
27
|
+
debrisFragmentShader,
|
|
28
|
+
debrisVertexShader,
|
|
29
|
+
easeOutCubic,
|
|
30
|
+
ecefEulerXyzToHpr,
|
|
31
|
+
ecefMetersToSdkPosition,
|
|
32
|
+
eulerXyzToHpr,
|
|
33
|
+
gridFragmentShader,
|
|
34
|
+
gridVertexShader,
|
|
35
|
+
isPngMostlyBlack,
|
|
36
|
+
isThreeLoaded,
|
|
37
|
+
latLonAltToCartesian,
|
|
38
|
+
loadThree,
|
|
39
|
+
meanLuminanceFromPngBytes,
|
|
40
|
+
objectGlowFragmentShader,
|
|
41
|
+
objectGlowVertexShader,
|
|
42
|
+
orbitLineFragmentShader,
|
|
43
|
+
orbitLineVertexShader,
|
|
44
|
+
planetRingFragmentShader,
|
|
45
|
+
planetRingVertexShader,
|
|
46
|
+
rgbToLuma,
|
|
47
|
+
selectionRingFragmentShader,
|
|
48
|
+
selectionRingVertexShader,
|
|
49
|
+
starsFragmentShader,
|
|
50
|
+
starsVertexShader,
|
|
51
|
+
terminatorFragmentShader,
|
|
52
|
+
terminatorVertexShader,
|
|
53
|
+
useSimulationScene,
|
|
54
|
+
visibilityConeFragmentShader,
|
|
55
|
+
visibilityConeVertexShader
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
let loadPromise = null;
|
|
2
|
+
async function loadThree() {
|
|
3
|
+
if (loadPromise) {
|
|
4
|
+
return loadPromise;
|
|
5
|
+
}
|
|
6
|
+
loadPromise = (async () => {
|
|
7
|
+
const [THREE, { OrbitControls }] = await Promise.all([
|
|
8
|
+
import("three"),
|
|
9
|
+
import("three/examples/jsm/controls/OrbitControls.js")
|
|
10
|
+
]);
|
|
11
|
+
return { THREE, OrbitControls };
|
|
12
|
+
})();
|
|
13
|
+
return loadPromise;
|
|
14
|
+
}
|
|
15
|
+
function isThreeLoaded() {
|
|
16
|
+
return loadPromise !== null;
|
|
17
|
+
}
|
|
18
|
+
export {
|
|
19
|
+
isThreeLoaded,
|
|
20
|
+
loadThree
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=threeLoader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"threeLoader.js","sources":["../../../src/react/3d/threeLoader.ts"],"sourcesContent":["/**\r\n * Shared Three.js loader\r\n * \r\n * Ensures only one instance of Three.js is loaded across all 3D components.\r\n * This prevents the \"Multiple instances of Three.js being imported\" warning.\r\n */\r\n\r\nexport type ThreeModule = typeof import('three');\r\nexport type OrbitControlsType = typeof import('three/examples/jsm/controls/OrbitControls.js').OrbitControls;\r\n\r\ninterface ThreeLoaderResult {\r\n THREE: ThreeModule;\r\n OrbitControls: OrbitControlsType;\r\n}\r\n\r\n// Cached promise to ensure single load\r\nlet loadPromise: Promise<ThreeLoaderResult> | null = null;\r\n\r\n/**\r\n * Load Three.js and OrbitControls\r\n * Returns cached instance if already loaded\r\n */\r\nexport async function loadThree(): Promise<ThreeLoaderResult> {\r\n if (loadPromise) {\r\n return loadPromise;\r\n }\r\n\r\n loadPromise = (async () => {\r\n const [THREE, { OrbitControls }] = await Promise.all([\r\n import('three'),\r\n import('three/examples/jsm/controls/OrbitControls.js'),\r\n ]);\r\n \r\n return { THREE, OrbitControls };\r\n })();\r\n\r\n return loadPromise;\r\n}\r\n\r\n/**\r\n * Check if Three.js is already loaded\r\n */\r\nexport function isThreeLoaded(): boolean {\r\n return loadPromise !== null;\r\n}\r\n"],"names":[],"mappings":"AAgBA,IAAI,cAAiD;AAMrD,eAAsB,YAAwC;AAC5D,MAAI,aAAa;AACf,WAAO;AAAA,EACT;AAEA,iBAAe,YAAY;AACzB,UAAM,CAAC,OAAO,EAAE,cAAA,CAAe,IAAI,MAAM,QAAQ,IAAI;AAAA,MACnD,OAAO,OAAO;AAAA,MACd,OAAO,8CAA8C;AAAA,IAAA,CACtD;AAED,WAAO,EAAE,OAAO,cAAA;AAAA,EAClB,GAAA;AAEA,SAAO;AACT;AAKO,SAAS,gBAAyB;AACvC,SAAO,gBAAgB;AACzB;"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo } from "react";
|
|
3
|
-
import { classNames } from "../utils/index.js";
|
|
4
3
|
import { useTheme } from "../theme/ThemeProvider.js";
|
|
4
|
+
import { classNames } from "../utils/index.js";
|
|
5
5
|
const CLASSIFICATION_STYLES = {
|
|
6
6
|
unclassified: {
|
|
7
7
|
bg: "#007a33",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo } from "react";
|
|
3
|
-
import { safeAccentText, classNames } from "../utils/index.js";
|
|
4
3
|
import { useTheme } from "../theme/ThemeProvider.js";
|
|
4
|
+
import { safeAccentText, classNames } from "../utils/index.js";
|
|
5
5
|
const GlobalStatusBar = memo(function GlobalStatusBar2({
|
|
6
6
|
appName = "Zendir",
|
|
7
7
|
appDomain,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx } from "react/jsx-runtime";
|
|
2
2
|
import { memo, useState, useMemo, useCallback, useEffect } from "react";
|
|
3
|
-
import { tabularNumsStyle, classNames } from "../utils/index.js";
|
|
4
3
|
import { useTheme } from "../theme/ThemeProvider.js";
|
|
4
|
+
import { tabularNumsStyle, classNames } from "../utils/index.js";
|
|
5
5
|
function formatMET(ms, showMilliseconds = false) {
|
|
6
6
|
const totalSeconds = Math.floor(Math.abs(ms) / 1e3);
|
|
7
7
|
const days = Math.floor(totalSeconds / 86400);
|
|
@@ -342,7 +342,7 @@ const MissionClock = memo(function MissionClock2({
|
|
|
342
342
|
}
|
|
343
343
|
);
|
|
344
344
|
});
|
|
345
|
-
memo(function SimpleTimer2({
|
|
345
|
+
const SimpleTimer = memo(function SimpleTimer2({
|
|
346
346
|
label,
|
|
347
347
|
timestamp,
|
|
348
348
|
direction = "countdown",
|
|
@@ -359,7 +359,7 @@ memo(function SimpleTimer2({
|
|
|
359
359
|
const timer = { label, timestamp, direction, status, showDays };
|
|
360
360
|
return /* @__PURE__ */ jsx("div", { className: classNames("zendir-simple-timer", className), children: /* @__PURE__ */ jsx(TimerDisplay, { timer, currentTime: now, tokens }) });
|
|
361
361
|
});
|
|
362
|
-
memo(function MissionElapsedTime2({
|
|
362
|
+
const MissionElapsedTime = memo(function MissionElapsedTime2({
|
|
363
363
|
launchTime,
|
|
364
364
|
showMilliseconds = false,
|
|
365
365
|
className = "",
|
|
@@ -378,7 +378,7 @@ memo(function MissionElapsedTime2({
|
|
|
378
378
|
}
|
|
379
379
|
);
|
|
380
380
|
});
|
|
381
|
-
memo(function SimulationClock2({
|
|
381
|
+
const SimulationClock = memo(function SimulationClock2({
|
|
382
382
|
epoch,
|
|
383
383
|
elapsedSeconds = 0,
|
|
384
384
|
timeScale = 1,
|
|
@@ -406,6 +406,9 @@ memo(function SimulationClock2({
|
|
|
406
406
|
);
|
|
407
407
|
});
|
|
408
408
|
export {
|
|
409
|
-
MissionClock
|
|
409
|
+
MissionClock,
|
|
410
|
+
MissionElapsedTime,
|
|
411
|
+
SimpleTimer,
|
|
412
|
+
SimulationClock
|
|
410
413
|
};
|
|
411
414
|
//# sourceMappingURL=MissionClock.js.map
|