react-native-nitro-ar 2026.2.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/README.md +347 -0
- package/app.plugin.js +24 -0
- package/ios/Bridge.h +8 -0
- package/ios/HybridARAnchor.swift +58 -0
- package/ios/HybridARBoundingBoxBuilder.swift +142 -0
- package/ios/HybridARDepthData.swift +138 -0
- package/ios/HybridARFrame.swift +121 -0
- package/ios/HybridARLightEstimate.swift +58 -0
- package/ios/HybridARMeasurement.swift +33 -0
- package/ios/HybridARMeshAnchor.swift +108 -0
- package/ios/HybridARPlaneAnchor.swift +114 -0
- package/ios/HybridARRaycastResult.swift +53 -0
- package/ios/HybridARSession.swift +505 -0
- package/ios/HybridARView.swift +725 -0
- package/ios/HybridARVolume.swift +52 -0
- package/ios/HybridARWorldMap.swift +55 -0
- package/lib/commonjs/index.js +24 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/commonjs/package.json +3 -0
- package/lib/commonjs/specs/ARAnchor.nitro.js +6 -0
- package/lib/commonjs/specs/ARAnchor.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARBoundingBoxBuilder.nitro.js +6 -0
- package/lib/commonjs/specs/ARBoundingBoxBuilder.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARDepthData.nitro.js +6 -0
- package/lib/commonjs/specs/ARDepthData.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARFrame.nitro.js +6 -0
- package/lib/commonjs/specs/ARFrame.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARLightEstimate.nitro.js +6 -0
- package/lib/commonjs/specs/ARLightEstimate.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARMeasurement.nitro.js +6 -0
- package/lib/commonjs/specs/ARMeasurement.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARPlaneAnchor.nitro.js +6 -0
- package/lib/commonjs/specs/ARPlaneAnchor.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARRaycastResult.nitro.js +6 -0
- package/lib/commonjs/specs/ARRaycastResult.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARSceneMesh.nitro.js +6 -0
- package/lib/commonjs/specs/ARSceneMesh.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARSession.nitro.js +6 -0
- package/lib/commonjs/specs/ARSession.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARView.nitro.js +6 -0
- package/lib/commonjs/specs/ARView.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARVolume.nitro.js +6 -0
- package/lib/commonjs/specs/ARVolume.nitro.js.map +1 -0
- package/lib/commonjs/specs/ARWorldMap.nitro.js +6 -0
- package/lib/commonjs/specs/ARWorldMap.nitro.js.map +1 -0
- package/lib/module/index.js +18 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/specs/ARAnchor.nitro.js +4 -0
- package/lib/module/specs/ARAnchor.nitro.js.map +1 -0
- package/lib/module/specs/ARBoundingBoxBuilder.nitro.js +4 -0
- package/lib/module/specs/ARBoundingBoxBuilder.nitro.js.map +1 -0
- package/lib/module/specs/ARDepthData.nitro.js +4 -0
- package/lib/module/specs/ARDepthData.nitro.js.map +1 -0
- package/lib/module/specs/ARFrame.nitro.js +4 -0
- package/lib/module/specs/ARFrame.nitro.js.map +1 -0
- package/lib/module/specs/ARLightEstimate.nitro.js +4 -0
- package/lib/module/specs/ARLightEstimate.nitro.js.map +1 -0
- package/lib/module/specs/ARMeasurement.nitro.js +4 -0
- package/lib/module/specs/ARMeasurement.nitro.js.map +1 -0
- package/lib/module/specs/ARPlaneAnchor.nitro.js +4 -0
- package/lib/module/specs/ARPlaneAnchor.nitro.js.map +1 -0
- package/lib/module/specs/ARRaycastResult.nitro.js +4 -0
- package/lib/module/specs/ARRaycastResult.nitro.js.map +1 -0
- package/lib/module/specs/ARSceneMesh.nitro.js +4 -0
- package/lib/module/specs/ARSceneMesh.nitro.js.map +1 -0
- package/lib/module/specs/ARSession.nitro.js +4 -0
- package/lib/module/specs/ARSession.nitro.js.map +1 -0
- package/lib/module/specs/ARView.nitro.js +4 -0
- package/lib/module/specs/ARView.nitro.js.map +1 -0
- package/lib/module/specs/ARVolume.nitro.js +4 -0
- package/lib/module/specs/ARVolume.nitro.js.map +1 -0
- package/lib/module/specs/ARWorldMap.nitro.js +4 -0
- package/lib/module/specs/ARWorldMap.nitro.js.map +1 -0
- package/lib/typescript/src/index.d.ts +20 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARAnchor.nitro.d.ts +18 -0
- package/lib/typescript/src/specs/ARAnchor.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARBoundingBoxBuilder.nitro.d.ts +11 -0
- package/lib/typescript/src/specs/ARBoundingBoxBuilder.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARDepthData.nitro.d.ts +26 -0
- package/lib/typescript/src/specs/ARDepthData.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARFrame.nitro.d.ts +32 -0
- package/lib/typescript/src/specs/ARFrame.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARLightEstimate.nitro.d.ts +18 -0
- package/lib/typescript/src/specs/ARLightEstimate.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARMeasurement.nitro.d.ts +11 -0
- package/lib/typescript/src/specs/ARMeasurement.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARPlaneAnchor.nitro.d.ts +32 -0
- package/lib/typescript/src/specs/ARPlaneAnchor.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARRaycastResult.nitro.d.ts +26 -0
- package/lib/typescript/src/specs/ARRaycastResult.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARSceneMesh.nitro.d.ts +47 -0
- package/lib/typescript/src/specs/ARSceneMesh.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARSession.nitro.d.ts +75 -0
- package/lib/typescript/src/specs/ARSession.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARView.nitro.d.ts +51 -0
- package/lib/typescript/src/specs/ARView.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARVolume.nitro.d.ts +14 -0
- package/lib/typescript/src/specs/ARVolume.nitro.d.ts.map +1 -0
- package/lib/typescript/src/specs/ARWorldMap.nitro.d.ts +17 -0
- package/lib/typescript/src/specs/ARWorldMap.nitro.d.ts.map +1 -0
- package/nitro.json +23 -0
- package/nitrogen/generated/.gitattributes +1 -0
- package/nitrogen/generated/ios/NitroAR+autolinking.rb +60 -0
- package/nitrogen/generated/ios/NitroAR-Swift-Cxx-Bridge.cpp +335 -0
- package/nitrogen/generated/ios/NitroAR-Swift-Cxx-Bridge.hpp +934 -0
- package/nitrogen/generated/ios/NitroAR-Swift-Cxx-Umbrella.hpp +169 -0
- package/nitrogen/generated/ios/NitroARAutolinking.mm +49 -0
- package/nitrogen/generated/ios/NitroARAutolinking.swift +50 -0
- package/nitrogen/generated/ios/c++/HybridARAnchorSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARAnchorSpecSwift.hpp +99 -0
- package/nitrogen/generated/ios/c++/HybridARBoundingBoxBuilderSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARBoundingBoxBuilderSpecSwift.hpp +95 -0
- package/nitrogen/generated/ios/c++/HybridARDepthDataSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARDepthDataSpecSwift.hpp +103 -0
- package/nitrogen/generated/ios/c++/HybridARDirectionalLightEstimateSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARDirectionalLightEstimateSpecSwift.hpp +88 -0
- package/nitrogen/generated/ios/c++/HybridARFrameSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARFrameSpecSwift.hpp +135 -0
- package/nitrogen/generated/ios/c++/HybridARLightEstimateSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARLightEstimateSpecSwift.hpp +80 -0
- package/nitrogen/generated/ios/c++/HybridARMeasurementSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARMeasurementSpecSwift.hpp +90 -0
- package/nitrogen/generated/ios/c++/HybridARMeshAnchorSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARMeshAnchorSpecSwift.hpp +107 -0
- package/nitrogen/generated/ios/c++/HybridARPlaneAnchorSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARPlaneAnchorSpecSwift.hpp +116 -0
- package/nitrogen/generated/ios/c++/HybridARPlaneGeometrySpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARPlaneGeometrySpecSwift.hpp +90 -0
- package/nitrogen/generated/ios/c++/HybridARRaycastResultSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARRaycastResultSpecSwift.hpp +97 -0
- package/nitrogen/generated/ios/c++/HybridARSessionSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARSessionSpecSwift.hpp +296 -0
- package/nitrogen/generated/ios/c++/HybridARViewSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARViewSpecSwift.hpp +243 -0
- package/nitrogen/generated/ios/c++/HybridARVolumeSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARVolumeSpecSwift.hpp +94 -0
- package/nitrogen/generated/ios/c++/HybridARWorldMapSpecSwift.cpp +11 -0
- package/nitrogen/generated/ios/c++/HybridARWorldMapSpecSwift.hpp +97 -0
- package/nitrogen/generated/ios/c++/views/HybridARViewComponent.mm +152 -0
- package/nitrogen/generated/ios/swift/ARSessionConfiguration.swift +189 -0
- package/nitrogen/generated/ios/swift/ARViewHitResult.swift +39 -0
- package/nitrogen/generated/ios/swift/CameraPose.swift +46 -0
- package/nitrogen/generated/ios/swift/EnvironmentTexturing.swift +44 -0
- package/nitrogen/generated/ios/swift/Func_void.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_TrackingState_TrackingStateReason.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_HybridARFrameSpec_.swift +50 -0
- package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_HybridARWorldMapSpec_.swift +50 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__shared_ptr_HybridARAnchorSpec___std__vector_std__shared_ptr_HybridARAnchorSpec___std__vector_std__string_.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__shared_ptr_HybridARMeshAnchorSpec___std__vector_std__shared_ptr_HybridARMeshAnchorSpec___std__vector_std__string_.swift +54 -0
- package/nitrogen/generated/ios/swift/Func_void_std__vector_std__shared_ptr_HybridARPlaneAnchorSpec___std__vector_std__shared_ptr_HybridARPlaneAnchorSpec___std__vector_std__string_.swift +54 -0
- package/nitrogen/generated/ios/swift/HybridARAnchorSpec.swift +60 -0
- package/nitrogen/generated/ios/swift/HybridARAnchorSpec_cxx.swift +192 -0
- package/nitrogen/generated/ios/swift/HybridARBoundingBoxBuilderSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridARBoundingBoxBuilderSpec_cxx.swift +161 -0
- package/nitrogen/generated/ios/swift/HybridARDepthDataSpec.swift +59 -0
- package/nitrogen/generated/ios/swift/HybridARDepthDataSpec_cxx.swift +188 -0
- package/nitrogen/generated/ios/swift/HybridARDirectionalLightEstimateSpec.swift +57 -0
- package/nitrogen/generated/ios/swift/HybridARDirectionalLightEstimateSpec_cxx.swift +162 -0
- package/nitrogen/generated/ios/swift/HybridARFrameSpec.swift +65 -0
- package/nitrogen/generated/ios/swift/HybridARFrameSpec_cxx.swift +285 -0
- package/nitrogen/generated/ios/swift/HybridARLightEstimateSpec.swift +56 -0
- package/nitrogen/generated/ios/swift/HybridARLightEstimateSpec_cxx.swift +140 -0
- package/nitrogen/generated/ios/swift/HybridARMeasurementSpec.swift +58 -0
- package/nitrogen/generated/ios/swift/HybridARMeasurementSpec_cxx.swift +160 -0
- package/nitrogen/generated/ios/swift/HybridARMeshAnchorSpec.swift +62 -0
- package/nitrogen/generated/ios/swift/HybridARMeshAnchorSpec_cxx.swift +212 -0
- package/nitrogen/generated/ios/swift/HybridARPlaneAnchorSpec.swift +62 -0
- package/nitrogen/generated/ios/swift/HybridARPlaneAnchorSpec_cxx.swift +209 -0
- package/nitrogen/generated/ios/swift/HybridARPlaneGeometrySpec.swift +58 -0
- package/nitrogen/generated/ios/swift/HybridARPlaneGeometrySpec_cxx.swift +178 -0
- package/nitrogen/generated/ios/swift/HybridARRaycastResultSpec.swift +59 -0
- package/nitrogen/generated/ios/swift/HybridARRaycastResultSpec_cxx.swift +179 -0
- package/nitrogen/generated/ios/swift/HybridARSessionSpec.swift +78 -0
- package/nitrogen/generated/ios/swift/HybridARSessionSpec_cxx.swift +591 -0
- package/nitrogen/generated/ios/swift/HybridARViewSpec.swift +78 -0
- package/nitrogen/generated/ios/swift/HybridARViewSpec_cxx.swift +561 -0
- package/nitrogen/generated/ios/swift/HybridARVolumeSpec.swift +60 -0
- package/nitrogen/generated/ios/swift/HybridARVolumeSpec_cxx.swift +180 -0
- package/nitrogen/generated/ios/swift/HybridARWorldMapSpec.swift +58 -0
- package/nitrogen/generated/ios/swift/HybridARWorldMapSpec_cxx.swift +176 -0
- package/nitrogen/generated/ios/swift/LiDARCapabilities.swift +39 -0
- package/nitrogen/generated/ios/swift/MeshClassification.swift +64 -0
- package/nitrogen/generated/ios/swift/PlaneAlignment.swift +40 -0
- package/nitrogen/generated/ios/swift/PlaneClassification.swift +64 -0
- package/nitrogen/generated/ios/swift/PlaneDetectionMode.swift +40 -0
- package/nitrogen/generated/ios/swift/RaycastAlignment.swift +44 -0
- package/nitrogen/generated/ios/swift/RaycastQuery.swift +44 -0
- package/nitrogen/generated/ios/swift/RaycastTarget.swift +48 -0
- package/nitrogen/generated/ios/swift/SceneReconstructionMode.swift +44 -0
- package/nitrogen/generated/ios/swift/TrackingState.swift +44 -0
- package/nitrogen/generated/ios/swift/TrackingStateReason.swift +52 -0
- package/nitrogen/generated/ios/swift/WorldAlignment.swift +44 -0
- package/nitrogen/generated/ios/swift/WorldMappingStatus.swift +48 -0
- package/nitrogen/generated/shared/c++/ARSessionConfiguration.hpp +132 -0
- package/nitrogen/generated/shared/c++/ARViewHitResult.hpp +91 -0
- package/nitrogen/generated/shared/c++/CameraPose.hpp +87 -0
- package/nitrogen/generated/shared/c++/EnvironmentTexturing.hpp +80 -0
- package/nitrogen/generated/shared/c++/HybridARAnchorSpec.cpp +26 -0
- package/nitrogen/generated/shared/c++/HybridARAnchorSpec.hpp +69 -0
- package/nitrogen/generated/shared/c++/HybridARBoundingBoxBuilderSpec.cpp +23 -0
- package/nitrogen/generated/shared/c++/HybridARBoundingBoxBuilderSpec.hpp +68 -0
- package/nitrogen/generated/shared/c++/HybridARDepthDataSpec.cpp +26 -0
- package/nitrogen/generated/shared/c++/HybridARDepthDataSpec.hpp +66 -0
- package/nitrogen/generated/shared/c++/HybridARDirectionalLightEstimateSpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridARDirectionalLightEstimateSpec.hpp +67 -0
- package/nitrogen/generated/shared/c++/HybridARFrameSpec.cpp +32 -0
- package/nitrogen/generated/shared/c++/HybridARFrameSpec.hpp +83 -0
- package/nitrogen/generated/shared/c++/HybridARLightEstimateSpec.cpp +22 -0
- package/nitrogen/generated/shared/c++/HybridARLightEstimateSpec.hpp +63 -0
- package/nitrogen/generated/shared/c++/HybridARMeasurementSpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridARMeasurementSpec.hpp +67 -0
- package/nitrogen/generated/shared/c++/HybridARMeshAnchorSpec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridARMeshAnchorSpec.hpp +72 -0
- package/nitrogen/generated/shared/c++/HybridARPlaneAnchorSpec.cpp +28 -0
- package/nitrogen/generated/shared/c++/HybridARPlaneAnchorSpec.hpp +79 -0
- package/nitrogen/generated/shared/c++/HybridARPlaneGeometrySpec.cpp +24 -0
- package/nitrogen/generated/shared/c++/HybridARPlaneGeometrySpec.hpp +65 -0
- package/nitrogen/generated/shared/c++/HybridARRaycastResultSpec.cpp +25 -0
- package/nitrogen/generated/shared/c++/HybridARRaycastResultSpec.hpp +70 -0
- package/nitrogen/generated/shared/c++/HybridARSessionSpec.cpp +45 -0
- package/nitrogen/generated/shared/c++/HybridARSessionSpec.hpp +131 -0
- package/nitrogen/generated/shared/c++/HybridARViewSpec.cpp +55 -0
- package/nitrogen/generated/shared/c++/HybridARViewSpec.hpp +101 -0
- package/nitrogen/generated/shared/c++/HybridARVolumeSpec.cpp +26 -0
- package/nitrogen/generated/shared/c++/HybridARVolumeSpec.hpp +67 -0
- package/nitrogen/generated/shared/c++/HybridARWorldMapSpec.cpp +25 -0
- package/nitrogen/generated/shared/c++/HybridARWorldMapSpec.hpp +66 -0
- package/nitrogen/generated/shared/c++/LiDARCapabilities.hpp +91 -0
- package/nitrogen/generated/shared/c++/MeshClassification.hpp +100 -0
- package/nitrogen/generated/shared/c++/PlaneAlignment.hpp +76 -0
- package/nitrogen/generated/shared/c++/PlaneClassification.hpp +100 -0
- package/nitrogen/generated/shared/c++/PlaneDetectionMode.hpp +76 -0
- package/nitrogen/generated/shared/c++/RaycastAlignment.hpp +80 -0
- package/nitrogen/generated/shared/c++/RaycastQuery.hpp +99 -0
- package/nitrogen/generated/shared/c++/RaycastTarget.hpp +84 -0
- package/nitrogen/generated/shared/c++/SceneReconstructionMode.hpp +80 -0
- package/nitrogen/generated/shared/c++/TrackingState.hpp +80 -0
- package/nitrogen/generated/shared/c++/TrackingStateReason.hpp +88 -0
- package/nitrogen/generated/shared/c++/WorldAlignment.hpp +80 -0
- package/nitrogen/generated/shared/c++/WorldMappingStatus.hpp +84 -0
- package/nitrogen/generated/shared/c++/views/HybridARViewComponent.cpp +182 -0
- package/nitrogen/generated/shared/c++/views/HybridARViewComponent.hpp +120 -0
- package/nitrogen/generated/shared/json/ARViewConfig.json +19 -0
- package/package.json +98 -0
- package/react-native-nitro-ar.podspec +40 -0
- package/src/index.ts +60 -0
- package/src/specs/ARAnchor.nitro.ts +21 -0
- package/src/specs/ARBoundingBoxBuilder.nitro.ts +11 -0
- package/src/specs/ARDepthData.nitro.ts +29 -0
- package/src/specs/ARFrame.nitro.ts +41 -0
- package/src/specs/ARLightEstimate.nitro.ts +20 -0
- package/src/specs/ARMeasurement.nitro.ts +10 -0
- package/src/specs/ARPlaneAnchor.nitro.ts +46 -0
- package/src/specs/ARRaycastResult.nitro.ts +32 -0
- package/src/specs/ARSceneMesh.nitro.ts +63 -0
- package/src/specs/ARSession.nitro.ts +112 -0
- package/src/specs/ARView.nitro.ts +84 -0
- package/src/specs/ARVolume.nitro.ts +15 -0
- package/src/specs/ARWorldMap.nitro.ts +20 -0
package/README.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# react-native-nitro-ar
|
|
2
|
+
|
|
3
|
+
A high-performance [Nitro module](https://nitro.margelo.com/) that provides ARKit functionality for React Native on iOS.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **AR Session Management** - Start, pause, and reset AR sessions with full configuration control
|
|
8
|
+
- **Plane Detection** - Detect horizontal and vertical planes with classification (floor, wall, ceiling, table, seat, window, door)
|
|
9
|
+
- **Raycasting** - Hit-test against detected planes and estimated surfaces
|
|
10
|
+
- **Anchors** - Create and track anchors in 3D space
|
|
11
|
+
- **Measurements** - Measure distances between anchor points
|
|
12
|
+
- **Bounding Boxes** - Calculate oriented bounding boxes (OBB) using PCA
|
|
13
|
+
- **Light Estimation** - Access ambient and directional light data with spherical harmonics
|
|
14
|
+
- **LiDAR Depth** - Access scene depth and smoothed depth data (iOS 14+, LiDAR devices)
|
|
15
|
+
- **World Maps** - Save and restore AR world maps for persistent AR experiences
|
|
16
|
+
- **Camera Data** - Access camera pose, intrinsics, projection/view matrices
|
|
17
|
+
|
|
18
|
+
## Requirements
|
|
19
|
+
|
|
20
|
+
- React Native 0.78.0+
|
|
21
|
+
- Node 18.0.0+
|
|
22
|
+
- iOS 13.0+ (iOS 14.0+ for LiDAR depth features)
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npm install react-native-nitro-ar react-native-nitro-modules
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Expo
|
|
31
|
+
|
|
32
|
+
If you're using Expo, add the plugin to your `app.json`:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"expo": {
|
|
37
|
+
"plugins": ["react-native-nitro-ar"]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Then run prebuild:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx expo prebuild
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Bare React Native
|
|
49
|
+
|
|
50
|
+
Add camera usage description to your `Info.plist`:
|
|
51
|
+
|
|
52
|
+
```xml
|
|
53
|
+
<key>NSCameraUsageDescription</key>
|
|
54
|
+
<string>This app uses the camera for AR experiences</string>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Then install pods:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
cd ios && pod install
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
### Basic Session
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { createARSession } from "react-native-nitro-ar";
|
|
69
|
+
|
|
70
|
+
const session = createARSession();
|
|
71
|
+
|
|
72
|
+
// Start with default configuration
|
|
73
|
+
session.start();
|
|
74
|
+
|
|
75
|
+
// Or with custom configuration
|
|
76
|
+
session.start({
|
|
77
|
+
planeDetection: ["horizontal", "vertical"],
|
|
78
|
+
lightEstimation: true,
|
|
79
|
+
environmentTexturing: "automatic",
|
|
80
|
+
worldAlignment: "gravity",
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Pause/resume
|
|
84
|
+
session.pause();
|
|
85
|
+
session.start();
|
|
86
|
+
|
|
87
|
+
// Reset tracking
|
|
88
|
+
session.reset();
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Plane Detection
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// Get all detected planes
|
|
95
|
+
const planes = session.planeAnchors;
|
|
96
|
+
|
|
97
|
+
for (const plane of planes) {
|
|
98
|
+
console.log("Plane:", plane.identifier);
|
|
99
|
+
console.log("Classification:", plane.classification); // floor, wall, table, etc.
|
|
100
|
+
console.log("Alignment:", plane.alignment); // horizontal or vertical
|
|
101
|
+
console.log("Extent:", plane.extent); // [width, height]
|
|
102
|
+
console.log("Center:", plane.center); // [x, y, z]
|
|
103
|
+
|
|
104
|
+
// Access plane geometry for rendering
|
|
105
|
+
const geo = plane.geometry;
|
|
106
|
+
console.log("Vertices:", geo.vertices);
|
|
107
|
+
console.log("Indices:", geo.triangleIndices);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Subscribe to plane updates
|
|
111
|
+
const unsubscribe = session.onPlanesUpdated((added, updated, removedIds) => {
|
|
112
|
+
console.log("Added planes:", added.length);
|
|
113
|
+
console.log("Updated planes:", updated.length);
|
|
114
|
+
console.log("Removed plane IDs:", removedIds);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Later: unsubscribe()
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Raycasting
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
// Simple raycast (normalized screen coordinates 0-1)
|
|
124
|
+
const hit = session.raycast(0.5, 0.5);
|
|
125
|
+
|
|
126
|
+
if (hit) {
|
|
127
|
+
console.log("Hit position:", hit.position);
|
|
128
|
+
console.log("Hit rotation:", hit.rotation);
|
|
129
|
+
console.log("Distance:", hit.distance);
|
|
130
|
+
|
|
131
|
+
// Create an anchor at the hit location
|
|
132
|
+
const anchor = session.createAnchor(hit);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Advanced raycast with options
|
|
136
|
+
const results = session.raycastWithQuery({
|
|
137
|
+
x: 0.5,
|
|
138
|
+
y: 0.5,
|
|
139
|
+
target: "existingPlaneGeometry", // or 'existingPlaneInfinite', 'estimatedPlane', 'any'
|
|
140
|
+
alignment: "horizontal", // or 'vertical', 'any'
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Anchors
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
// Create anchor from raycast
|
|
148
|
+
const anchor = session.createAnchor(raycastResult);
|
|
149
|
+
|
|
150
|
+
// Create anchor at specific position
|
|
151
|
+
const anchor = session.createAnchorAtPosition(
|
|
152
|
+
[0, 0, -1], // position [x, y, z]
|
|
153
|
+
[0, 0, 0, 1], // rotation quaternion [x, y, z, w]
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
// Access anchor properties
|
|
157
|
+
console.log("ID:", anchor.identifier);
|
|
158
|
+
console.log("Position:", anchor.position);
|
|
159
|
+
console.log("Rotation:", anchor.rotation);
|
|
160
|
+
console.log("Is tracked:", anchor.isTracked);
|
|
161
|
+
|
|
162
|
+
// Remove anchor
|
|
163
|
+
session.removeAnchor(anchor);
|
|
164
|
+
|
|
165
|
+
// Subscribe to anchor updates
|
|
166
|
+
const unsubscribe = session.onAnchorsUpdated((added, updated, removedIds) => {
|
|
167
|
+
// Handle anchor changes
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Measurements
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// Create measurement between two anchors
|
|
175
|
+
const measurement = session.createMeasurement(startAnchor, endAnchor);
|
|
176
|
+
|
|
177
|
+
console.log("Length (meters):", measurement.length);
|
|
178
|
+
console.log("Is valid:", measurement.isValid);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### Frame Updates
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
// Subscribe to frame updates
|
|
185
|
+
const unsubscribe = session.onFrameUpdate((frame) => {
|
|
186
|
+
console.log("Timestamp:", frame.timestamp);
|
|
187
|
+
console.log("Camera position:", frame.cameraPosition);
|
|
188
|
+
console.log("Camera rotation:", frame.cameraRotation);
|
|
189
|
+
|
|
190
|
+
// Light estimation
|
|
191
|
+
if (frame.lightEstimate) {
|
|
192
|
+
console.log("Ambient intensity:", frame.lightEstimate.ambientIntensity);
|
|
193
|
+
console.log("Color temperature:", frame.lightEstimate.ambientColorTemperature);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Directional light (for realistic lighting)
|
|
197
|
+
if (frame.directionalLightEstimate) {
|
|
198
|
+
console.log("Light direction:", frame.directionalLightEstimate.primaryLightDirection);
|
|
199
|
+
console.log(
|
|
200
|
+
"Spherical harmonics:",
|
|
201
|
+
frame.directionalLightEstimate.sphericalHarmonicsCoefficients,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// LiDAR depth (iOS 14+, devices with LiDAR)
|
|
206
|
+
if (frame.sceneDepth) {
|
|
207
|
+
const depth = frame.sceneDepth;
|
|
208
|
+
console.log("Depth map size:", depth.width, "x", depth.height);
|
|
209
|
+
|
|
210
|
+
// Get depth at specific point
|
|
211
|
+
const depthValue = depth.getDepthAt(0.5, 0.5);
|
|
212
|
+
const confidence = depth.getConfidenceAt(0.5, 0.5);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Capture camera image
|
|
216
|
+
const base64Image = frame.getCapturedImage(0.8); // quality 0-1
|
|
217
|
+
});
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Tracking State
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
// Check current state
|
|
224
|
+
console.log("Is running:", session.isRunning);
|
|
225
|
+
console.log("Tracking state:", session.trackingState); // 'normal', 'limited', 'notAvailable'
|
|
226
|
+
console.log("Tracking reason:", session.trackingStateReason); // 'none', 'initializing', 'excessiveMotion', etc.
|
|
227
|
+
console.log("World mapping:", session.worldMappingStatus); // 'notAvailable', 'limited', 'extending', 'mapped'
|
|
228
|
+
|
|
229
|
+
// Subscribe to tracking changes
|
|
230
|
+
const unsubscribe = session.onTrackingStateChanged((state, reason) => {
|
|
231
|
+
if (state === "limited") {
|
|
232
|
+
console.log("Tracking limited:", reason);
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### World Map Persistence
|
|
238
|
+
|
|
239
|
+
```typescript
|
|
240
|
+
// Save world map (for relocalization later)
|
|
241
|
+
const worldMap = await session.getCurrentWorldMap();
|
|
242
|
+
const mapData = worldMap.getData(); // base64 encoded
|
|
243
|
+
|
|
244
|
+
// Store mapData somewhere (file, cloud, etc.)
|
|
245
|
+
await saveToStorage(mapData);
|
|
246
|
+
|
|
247
|
+
// Later: restore session with saved map
|
|
248
|
+
const savedMapData = await loadFromStorage();
|
|
249
|
+
session.start({
|
|
250
|
+
initialWorldMap: savedMapData,
|
|
251
|
+
});
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### Bounding Box Builder
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { createARBoundingBoxBuilder } from "react-native-nitro-ar";
|
|
258
|
+
|
|
259
|
+
const builder = createARBoundingBoxBuilder();
|
|
260
|
+
|
|
261
|
+
// Add points (from raycasts, anchors, etc.)
|
|
262
|
+
builder.addPoint([x, y, z]);
|
|
263
|
+
builder.addPoints([
|
|
264
|
+
[x1, y1, z1],
|
|
265
|
+
[x2, y2, z2],
|
|
266
|
+
[x3, y3, z3],
|
|
267
|
+
]);
|
|
268
|
+
|
|
269
|
+
// Get oriented bounding box (uses PCA for optimal orientation)
|
|
270
|
+
const obb = builder.getOrientedBoundingBox();
|
|
271
|
+
console.log("Center:", obb.center);
|
|
272
|
+
console.log("Half extents:", obb.halfExtents);
|
|
273
|
+
console.log("Axes:", obb.axes); // 3 orthogonal direction vectors
|
|
274
|
+
|
|
275
|
+
// Reset for new calculation
|
|
276
|
+
builder.clear();
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## API Reference
|
|
280
|
+
|
|
281
|
+
### ARSession
|
|
282
|
+
|
|
283
|
+
| Property/Method | Type | Description |
|
|
284
|
+
| ----------------------------------- | --------------------- | --------------------------------- |
|
|
285
|
+
| `start(config?)` | `void` | Start AR session |
|
|
286
|
+
| `pause()` | `void` | Pause AR session |
|
|
287
|
+
| `reset()` | `void` | Reset tracking and remove anchors |
|
|
288
|
+
| `isRunning` | `boolean` | Session running state |
|
|
289
|
+
| `trackingState` | `TrackingState` | Current tracking quality |
|
|
290
|
+
| `trackingStateReason` | `TrackingStateReason` | Reason for limited tracking |
|
|
291
|
+
| `worldMappingStatus` | `WorldMappingStatus` | World map quality |
|
|
292
|
+
| `getCameraPose()` | `CameraPose` | Current camera position/rotation |
|
|
293
|
+
| `currentFrame` | `ARFrame?` | Latest frame data |
|
|
294
|
+
| `raycast(x, y)` | `ARRaycastResult?` | Hit-test at screen point |
|
|
295
|
+
| `raycastWithQuery(query)` | `ARRaycastResult[]` | Advanced hit-test |
|
|
296
|
+
| `createAnchor(hit)` | `ARAnchor` | Create anchor from raycast |
|
|
297
|
+
| `createAnchorAtPosition(pos, rot?)` | `ARAnchor` | Create anchor at position |
|
|
298
|
+
| `removeAnchor(anchor)` | `void` | Remove anchor |
|
|
299
|
+
| `anchors` | `ARAnchor[]` | All anchors |
|
|
300
|
+
| `planeAnchors` | `ARPlaneAnchor[]` | Detected planes |
|
|
301
|
+
| `createMeasurement(start, end)` | `ARMeasurement` | Measure between anchors |
|
|
302
|
+
| `getCurrentWorldMap()` | `Promise<ARWorldMap>` | Get world map for persistence |
|
|
303
|
+
| `onFrameUpdate(callback)` | `() => void` | Subscribe to frame updates |
|
|
304
|
+
| `onTrackingStateChanged(callback)` | `() => void` | Subscribe to tracking changes |
|
|
305
|
+
| `onAnchorsUpdated(callback)` | `() => void` | Subscribe to anchor changes |
|
|
306
|
+
| `onPlanesUpdated(callback)` | `() => void` | Subscribe to plane changes |
|
|
307
|
+
|
|
308
|
+
### ARSessionConfiguration
|
|
309
|
+
|
|
310
|
+
| Property | Type | Default | Description |
|
|
311
|
+
| ---------------------- | ----------------------- | ---------------------------- | --------------------------- |
|
|
312
|
+
| `planeDetection` | `PlaneDetectionMode[]?` | `['horizontal', 'vertical']` | Planes to detect |
|
|
313
|
+
| `lightEstimation` | `boolean?` | `true` | Enable light estimation |
|
|
314
|
+
| `environmentTexturing` | `EnvironmentTexturing?` | - | Environment texturing mode |
|
|
315
|
+
| `worldAlignment` | `WorldAlignment?` | `'gravity'` | World coordinate alignment |
|
|
316
|
+
| `sceneDepth` | `boolean?` | `false` | Enable LiDAR depth |
|
|
317
|
+
| `smoothedSceneDepth` | `boolean?` | `false` | Enable smoothed depth |
|
|
318
|
+
| `initialWorldMap` | `string?` | - | Base64 world map to restore |
|
|
319
|
+
|
|
320
|
+
## Development
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
# Install dependencies
|
|
324
|
+
bun install
|
|
325
|
+
|
|
326
|
+
# Run codegen (generates Nitro bridge code)
|
|
327
|
+
bun run codegen
|
|
328
|
+
|
|
329
|
+
# Type check and build
|
|
330
|
+
bun run build
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
To run the example app:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
# from root
|
|
337
|
+
bun link
|
|
338
|
+
cd example
|
|
339
|
+
bun install
|
|
340
|
+
bun run ios --device
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Physical devices are required.
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
[MIT](./LICENSE)
|
package/app.plugin.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
const { withInfoPlist, withEntitlementsPlist, withXcodeProject } = require('@expo/config-plugins');
|
|
2
|
+
|
|
3
|
+
const withNitroAR = (config) => {
|
|
4
|
+
// Add camera usage description
|
|
5
|
+
config = withInfoPlist(config, (config) => {
|
|
6
|
+
config.modResults.NSCameraUsageDescription =
|
|
7
|
+
config.modResults.NSCameraUsageDescription ||
|
|
8
|
+
'This app uses the camera for augmented reality features.';
|
|
9
|
+
|
|
10
|
+
// Add ARKit to required device capabilities
|
|
11
|
+
if (!config.modResults.UIRequiredDeviceCapabilities) {
|
|
12
|
+
config.modResults.UIRequiredDeviceCapabilities = [];
|
|
13
|
+
}
|
|
14
|
+
if (!config.modResults.UIRequiredDeviceCapabilities.includes('arkit')) {
|
|
15
|
+
config.modResults.UIRequiredDeviceCapabilities.push('arkit');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return config;
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return config;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
module.exports = withNitroAR;
|
package/ios/Bridge.h
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import ARKit
|
|
2
|
+
import NitroModules
|
|
3
|
+
import simd
|
|
4
|
+
|
|
5
|
+
final class HybridARAnchor: HybridARAnchorSpec {
|
|
6
|
+
let anchor: ARAnchor
|
|
7
|
+
weak var session: ARSession?
|
|
8
|
+
|
|
9
|
+
init(anchor: ARAnchor, session: ARSession) {
|
|
10
|
+
self.anchor = anchor
|
|
11
|
+
self.session = session
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
var identifier: String {
|
|
15
|
+
anchor.identifier.uuidString
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var position: [Double] {
|
|
19
|
+
let t = anchor.transform
|
|
20
|
+
return [
|
|
21
|
+
Double(t.columns.3.x),
|
|
22
|
+
Double(t.columns.3.y),
|
|
23
|
+
Double(t.columns.3.z)
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
var rotation: [Double] {
|
|
28
|
+
let q = simd_quatf(anchor.transform)
|
|
29
|
+
return [
|
|
30
|
+
Double(q.vector.x),
|
|
31
|
+
Double(q.vector.y),
|
|
32
|
+
Double(q.vector.z),
|
|
33
|
+
Double(q.vector.w)
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var transform: [Double] {
|
|
38
|
+
let t = anchor.transform
|
|
39
|
+
return [
|
|
40
|
+
Double(t.columns.0.x), Double(t.columns.0.y),
|
|
41
|
+
Double(t.columns.0.z), Double(t.columns.0.w),
|
|
42
|
+
Double(t.columns.1.x), Double(t.columns.1.y),
|
|
43
|
+
Double(t.columns.1.z), Double(t.columns.1.w),
|
|
44
|
+
Double(t.columns.2.x), Double(t.columns.2.y),
|
|
45
|
+
Double(t.columns.2.z), Double(t.columns.2.w),
|
|
46
|
+
Double(t.columns.3.x), Double(t.columns.3.y),
|
|
47
|
+
Double(t.columns.3.z), Double(t.columns.3.w)
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
var isTracked: Bool {
|
|
52
|
+
session?.currentFrame?.anchors.contains(anchor) ?? false
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
var label: String? {
|
|
56
|
+
anchor.name
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import NitroModules
|
|
2
|
+
import simd
|
|
3
|
+
import Accelerate
|
|
4
|
+
|
|
5
|
+
final class HybridARBoundingBoxBuilder: HybridARBoundingBoxBuilderSpec {
|
|
6
|
+
|
|
7
|
+
private var anchors: [HybridARAnchor] = []
|
|
8
|
+
|
|
9
|
+
func addBaseAnchor(
|
|
10
|
+
anchor: HybridARAnchorSpec
|
|
11
|
+
) {
|
|
12
|
+
anchors.append(anchor as! HybridARAnchor)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var canBuild: Bool {
|
|
16
|
+
anchors.count >= 4
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
func build() -> HybridARVolumeSpec {
|
|
20
|
+
let positions = anchors.map {
|
|
21
|
+
SIMD3(
|
|
22
|
+
$0.anchor.transform.columns.3.x,
|
|
23
|
+
$0.anchor.transform.columns.3.y,
|
|
24
|
+
$0.anchor.transform.columns.3.z
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Compute centroid
|
|
29
|
+
let centroid = positions.reduce(SIMD3<Float>.zero, +) / Float(positions.count)
|
|
30
|
+
|
|
31
|
+
// Center the points
|
|
32
|
+
let centered = positions.map { $0 - centroid }
|
|
33
|
+
|
|
34
|
+
// Build covariance matrix
|
|
35
|
+
var cov = simd_float3x3(0)
|
|
36
|
+
for p in centered {
|
|
37
|
+
cov += simd_float3x3(
|
|
38
|
+
SIMD3(p.x * p.x, p.x * p.y, p.x * p.z),
|
|
39
|
+
SIMD3(p.y * p.x, p.y * p.y, p.y * p.z),
|
|
40
|
+
SIMD3(p.z * p.x, p.z * p.y, p.z * p.z)
|
|
41
|
+
)
|
|
42
|
+
}
|
|
43
|
+
cov = cov * (1.0 / Float(positions.count))
|
|
44
|
+
|
|
45
|
+
// Compute eigenvectors using power iteration for principal axes
|
|
46
|
+
let (eigenvectors, isStable) = computeEigenvectors(cov)
|
|
47
|
+
|
|
48
|
+
// Build rotation matrix from eigenvectors (columns are the principal axes)
|
|
49
|
+
let rotationMatrix = simd_float3x3(
|
|
50
|
+
eigenvectors.0,
|
|
51
|
+
eigenvectors.1,
|
|
52
|
+
eigenvectors.2
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
// Ensure right-handed coordinate system
|
|
56
|
+
let det = simd_determinant(rotationMatrix)
|
|
57
|
+
let correctedMatrix: simd_float3x3
|
|
58
|
+
if det < 0 {
|
|
59
|
+
correctedMatrix = simd_float3x3(
|
|
60
|
+
eigenvectors.0,
|
|
61
|
+
eigenvectors.1,
|
|
62
|
+
-eigenvectors.2
|
|
63
|
+
)
|
|
64
|
+
} else {
|
|
65
|
+
correctedMatrix = rotationMatrix
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Transform points to OBB space
|
|
69
|
+
let inverseRotation = correctedMatrix.transpose
|
|
70
|
+
let rotatedPoints = centered.map { inverseRotation * $0 }
|
|
71
|
+
|
|
72
|
+
// Find AABB in OBB space
|
|
73
|
+
let minBounds = rotatedPoints.reduce(rotatedPoints[0], simd_min)
|
|
74
|
+
let maxBounds = rotatedPoints.reduce(rotatedPoints[0], simd_max)
|
|
75
|
+
|
|
76
|
+
let size = maxBounds - minBounds
|
|
77
|
+
let localCenter = (minBounds + maxBounds) / 2
|
|
78
|
+
|
|
79
|
+
// Transform center back to world space
|
|
80
|
+
let worldCenter = correctedMatrix * localCenter + centroid
|
|
81
|
+
|
|
82
|
+
// Convert rotation matrix to quaternion
|
|
83
|
+
let rotation = simd_quatf(correctedMatrix)
|
|
84
|
+
|
|
85
|
+
return HybridARVolume(
|
|
86
|
+
center: worldCenter,
|
|
87
|
+
width: Double(size.x),
|
|
88
|
+
height: Double(size.y),
|
|
89
|
+
depth: Double(size.z),
|
|
90
|
+
rotation: rotation,
|
|
91
|
+
isStable: isStable
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private func computeEigenvectors(
|
|
96
|
+
_ matrix: simd_float3x3
|
|
97
|
+
) -> ((SIMD3<Float>, SIMD3<Float>, SIMD3<Float>), Bool) {
|
|
98
|
+
// Power iteration to find dominant eigenvector
|
|
99
|
+
var v1 = normalize(SIMD3<Float>(1, 0, 0))
|
|
100
|
+
var stable = true
|
|
101
|
+
|
|
102
|
+
for _ in 0..<50 {
|
|
103
|
+
let next = normalize(matrix * v1)
|
|
104
|
+
if simd_length(next - v1) < 1e-6 {
|
|
105
|
+
break
|
|
106
|
+
}
|
|
107
|
+
v1 = next
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Deflate matrix and find second eigenvector
|
|
111
|
+
let lambda1 = simd_dot(v1, matrix * v1)
|
|
112
|
+
let deflated1 = matrix - lambda1 * simd_float3x3(
|
|
113
|
+
SIMD3(v1.x * v1.x, v1.x * v1.y, v1.x * v1.z),
|
|
114
|
+
SIMD3(v1.y * v1.x, v1.y * v1.y, v1.y * v1.z),
|
|
115
|
+
SIMD3(v1.z * v1.x, v1.z * v1.y, v1.z * v1.z)
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
var v2 = normalize(SIMD3<Float>(0, 1, 0))
|
|
119
|
+
// Ensure v2 is orthogonal to v1
|
|
120
|
+
v2 = normalize(v2 - simd_dot(v2, v1) * v1)
|
|
121
|
+
|
|
122
|
+
for _ in 0..<50 {
|
|
123
|
+
var next = deflated1 * v2
|
|
124
|
+
next = next - simd_dot(next, v1) * v1 // Gram-Schmidt
|
|
125
|
+
let len = simd_length(next)
|
|
126
|
+
if len < 1e-6 {
|
|
127
|
+
stable = false
|
|
128
|
+
break
|
|
129
|
+
}
|
|
130
|
+
next = next / len
|
|
131
|
+
if simd_length(next - v2) < 1e-6 {
|
|
132
|
+
break
|
|
133
|
+
}
|
|
134
|
+
v2 = next
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Third eigenvector is cross product (orthogonal to both)
|
|
138
|
+
let v3 = normalize(simd_cross(v1, v2))
|
|
139
|
+
|
|
140
|
+
return ((v1, v2, v3), stable)
|
|
141
|
+
}
|
|
142
|
+
}
|