replate-camera 0.1.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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Filippo Cavallari
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # replate-camera
2
+
3
+ Camera component for Replate Manager
4
+
5
+ ## Installation
6
+
7
+ ```sh
8
+ npm install replate-camera
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```js
14
+ import { ReplateCameraView } from "replate-camera";
15
+
16
+ // ...
17
+
18
+ <ReplateCameraView color="tomato" />
19
+ ```
20
+
21
+ ## Contributing
22
+
23
+ See the [contributing guide](CONTRIBUTING.md) to learn how to contribute to the repository and the development workflow.
24
+
25
+ ## License
26
+
27
+ MIT
28
+
29
+ ---
30
+
31
+ Made with [create-react-native-library](https://github.com/callstack/react-native-builder-bob)
@@ -0,0 +1,94 @@
1
+ buildscript {
2
+ // Buildscript is evaluated before everything else so we can't use getExtOrDefault
3
+ def kotlin_version = rootProject.ext.has("kotlinVersion") ? rootProject.ext.get("kotlinVersion") : project.properties["ReplateCamera_kotlinVersion"]
4
+
5
+ repositories {
6
+ google()
7
+ mavenCentral()
8
+ }
9
+
10
+ dependencies {
11
+ classpath "com.android.tools.build:gradle:7.2.1"
12
+ // noinspection DifferentKotlinGradleVersion
13
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
14
+ }
15
+ }
16
+
17
+ def isNewArchitectureEnabled() {
18
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
19
+ }
20
+
21
+ apply plugin: "com.android.library"
22
+ apply plugin: "kotlin-android"
23
+
24
+ if (isNewArchitectureEnabled()) {
25
+ apply plugin: "com.facebook.react"
26
+ }
27
+
28
+ def getExtOrDefault(name) {
29
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["ReplateCamera_" + name]
30
+ }
31
+
32
+ def getExtOrIntegerDefault(name) {
33
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["ReplateCamera_" + name]).toInteger()
34
+ }
35
+
36
+ def supportsNamespace() {
37
+ def parsed = com.android.Version.ANDROID_GRADLE_PLUGIN_VERSION.tokenize('.')
38
+ def major = parsed[0].toInteger()
39
+ def minor = parsed[1].toInteger()
40
+
41
+ // Namespace support was added in 7.3.0
42
+ return (major == 7 && minor >= 3) || major >= 8
43
+ }
44
+
45
+ android {
46
+ if (supportsNamespace()) {
47
+ namespace "com.replatecamera"
48
+
49
+ sourceSets {
50
+ main {
51
+ manifest.srcFile "src/main/AndroidManifestNew.xml"
52
+ }
53
+ }
54
+ }
55
+
56
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
57
+
58
+ defaultConfig {
59
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
60
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
61
+
62
+ }
63
+
64
+ buildTypes {
65
+ release {
66
+ minifyEnabled false
67
+ }
68
+ }
69
+
70
+ lintOptions {
71
+ disable "GradleCompatible"
72
+ }
73
+
74
+ compileOptions {
75
+ sourceCompatibility JavaVersion.VERSION_1_8
76
+ targetCompatibility JavaVersion.VERSION_1_8
77
+ }
78
+ }
79
+
80
+ repositories {
81
+ mavenCentral()
82
+ google()
83
+ }
84
+
85
+ def kotlin_version = getExtOrDefault("kotlinVersion")
86
+
87
+ dependencies {
88
+ // For < 0.71, this will be from the local maven repo
89
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
90
+ //noinspection GradleDynamicVersion
91
+ implementation "com.facebook.react:react-native:+"
92
+ implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
93
+ }
94
+
@@ -0,0 +1,5 @@
1
+ ReplateCamera_kotlinVersion=1.7.0
2
+ ReplateCamera_minSdkVersion=21
3
+ ReplateCamera_targetSdkVersion=31
4
+ ReplateCamera_compileSdkVersion=31
5
+ ReplateCamera_ndkversion=21.4.7075529
@@ -0,0 +1,3 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android"
2
+ package="com.replatecamera">
3
+ </manifest>
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,17 @@
1
+ package com.replatecamera
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+
9
+ class ReplateCameraPackage : ReactPackage {
10
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
11
+ return emptyList()
12
+ }
13
+
14
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
15
+ return listOf(ReplateCameraViewManager())
16
+ }
17
+ }
@@ -0,0 +1,20 @@
1
+ package com.replatecamera
2
+
3
+ import android.graphics.Color
4
+ import android.view.View
5
+ import com.facebook.react.uimanager.SimpleViewManager
6
+ import com.facebook.react.uimanager.ThemedReactContext
7
+ import com.facebook.react.uimanager.annotations.ReactProp
8
+
9
+ class ReplateCameraViewManager : SimpleViewManager<View>() {
10
+ override fun getName() = "ReplateCameraView"
11
+
12
+ override fun createViewInstance(reactContext: ThemedReactContext): View {
13
+ return View(reactContext)
14
+ }
15
+
16
+ @ReactProp(name = "color")
17
+ fun setColor(view: View, color: String) {
18
+ view.setBackgroundColor(Color.parseColor(color))
19
+ }
20
+ }
@@ -0,0 +1,3 @@
1
+ #import <React/RCTViewManager.h>
2
+ #import <React/RCTBridgeModule.h>
3
+ #import <React/RCTEventEmitter.h>
@@ -0,0 +1,15 @@
1
+ @objc(ReplateCameraController)
2
+ class ReplateCameraController: NSObject {
3
+
4
+ @objc(takePhoto:rejecter:)
5
+ func takePhoto(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) -> Void {
6
+ print("Take photo")
7
+ resolver("Photo taken")
8
+ }
9
+
10
+ @objc
11
+ func constantsToExport() -> [String: Any]! {
12
+ return ["someKey": "someValue"]
13
+ }
14
+
15
+ }
@@ -0,0 +1,24 @@
1
+ #import <React/RCTViewManager.h>
2
+ #import <React/RCTUIManager.h>
3
+ #import <React/RCTBridgeModule.h>
4
+
5
+ @interface RCT_EXTERN_MODULE(ReplateCameraViewManager, RCTViewManager)
6
+
7
+ // RCT_EXPORT_VIEW_PROPERTY(rect, NSDictionary)
8
+ RCT_EXPORT_VIEW_PROPERTY(color, NSString)
9
+
10
+
11
+ @end
12
+
13
+
14
+ @interface RCT_EXTERN_MODULE(ReplateCameraController, NSObject)
15
+
16
+ RCT_EXTERN_METHOD(takePhoto:(RCTPromiseResolveBlock*)resolve
17
+ rejecter:(RCTPromiseRejectBlock)reject)
18
+
19
+ + (BOOL)requiresMainQueueSetup
20
+ {
21
+ return NO;
22
+ }
23
+
24
+ @end
@@ -0,0 +1,377 @@
1
+ import ARKit
2
+ import RealityKit
3
+ import UIKit
4
+ import AVFoundation
5
+
6
+ @objc(ReplateCameraViewManager)
7
+ class ReplateCameraViewManager: RCTViewManager {
8
+
9
+ override func view() -> (ReplateCameraView) {
10
+ let replCameraView = ReplateCameraView()
11
+ return replCameraView
12
+ }
13
+
14
+ @objc override static func requiresMainQueueSetup() -> Bool {
15
+ return false
16
+ }
17
+
18
+
19
+ }
20
+
21
+ class ReplateCameraView : UIView, ARSessionDelegate {
22
+
23
+ static var arView: ARView!
24
+ static var anchor: ARAnchor!
25
+ static var anchorEntity: AnchorEntity!
26
+ static var model: Entity!
27
+ static var spheresModels: [ModelEntity] = []
28
+ static var upperSpheresSet: [Bool] = [Bool](repeating: false, count: 72)
29
+ static var lowerSpheresSet: [Bool] = [Bool](repeating: false, count: 72)
30
+
31
+ override init(frame: CGRect) {
32
+ super.init(frame: frame)
33
+ requestCameraPermissions()
34
+ // setupAR()
35
+ }
36
+
37
+ required init?(coder: NSCoder) {
38
+ super.init(coder: coder)
39
+ requestCameraPermissions()
40
+ // setupAR()
41
+ }
42
+
43
+ func requestCameraPermissions(){
44
+
45
+ if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
46
+ print("Camera permissions already granted")
47
+ } else {
48
+ AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in
49
+ if granted {
50
+ print("Camera permissions granted")
51
+ } else {
52
+ print("Camera permissions denied")
53
+ }
54
+ })
55
+ }
56
+ }
57
+
58
+ override func layoutSubviews() {
59
+ super.layoutSubviews()
60
+
61
+ // Now you can safely access the size
62
+ let width = self.frame.width
63
+ let height = self.frame.height
64
+
65
+ // Do something with width and height
66
+ print("Width: \(width), Height: \(height)")
67
+ self.setupAR()
68
+ }
69
+
70
+ func setupAR() {
71
+ print("Setup AR")
72
+ let width = self.frame.width
73
+ let height = self.frame.height
74
+ ReplateCameraView.arView = ARView(frame: CGRect(x: 0, y: 0, width: width, height: height))
75
+ ReplateCameraView.arView.backgroundColor = hexStringToUIColor(hexColor: "#32a852")
76
+ addSubview(ReplateCameraView.arView)
77
+ ReplateCameraView.arView.session.delegate = self
78
+ let configuration = ARWorldTrackingConfiguration()
79
+ // guard let obj = ARReferenceObject.referenceObjects(inGroupNamed: "AR Resource Group",
80
+ // bundle: nil)
81
+ // else { fatalError("See no reference object") }
82
+ // print(obj)
83
+ configuration.planeDetection = ARWorldTrackingConfiguration.PlaneDetection.horizontal
84
+ if #available(iOS 16.0, *) {
85
+ print("recommendedVideoFormatForHighResolutionFrameCapturing")
86
+ configuration.videoFormat = ARWorldTrackingConfiguration.recommendedVideoFormatForHighResolutionFrameCapturing ?? ARWorldTrackingConfiguration.recommendedVideoFormatFor4KResolution ?? ARWorldTrackingConfiguration.supportedVideoFormats[0]
87
+ } else {
88
+ print("Alternative high resolution method")
89
+ let maxResolutionFormat = ARWorldTrackingConfiguration.supportedVideoFormats.max(by: { format1, format2 in
90
+ let resolution1 = format1.imageResolution.width * format1.imageResolution.height
91
+ let resolution2 = format2.imageResolution.width * format2.imageResolution.height
92
+ return resolution1 < resolution2
93
+ })!
94
+ configuration.videoFormat = maxResolutionFormat
95
+ }
96
+ // configuration.detectionObjects = obj
97
+ ReplateCameraView.arView.session.run(configuration)
98
+ }
99
+
100
+ func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
101
+ print("ANCHOR FOUND")
102
+ if (ReplateCameraView.anchor == nil){
103
+ guard let _anchor = anchors.first else { return }
104
+ ReplateCameraView.anchor = _anchor
105
+ }
106
+ if (ReplateCameraView.model == nil && ReplateCameraView.anchorEntity == nil){
107
+ let anchorTransform = ReplateCameraView.anchor.transform
108
+ // let path = Bundle.main.path(forResource: "anchor", ofType: "usdz")!
109
+ // let url = URL(fileURLWithPath: path)
110
+ // let entity: ModelEntity = try! ModelEntity.loadModel(contentsOf: url)
111
+
112
+ // if #available(iOS 15.0, *) {
113
+ // entity.model!.mesh.
114
+ // ReplateCameraView.spheresModels = Array(entity.model!.mesh.contents.models)
115
+ // }
116
+ // entity.scale *= 4.5
117
+ // entity.position = SIMD3(anchorTransform.columns.3.x, anchorTransform.columns.3.y, anchorTransform.columns.3.z)
118
+
119
+ func createSphere(position: SIMD3<Float>) -> ModelEntity {
120
+ let sphereMesh = MeshResource.generateSphere(radius: 0.0025)
121
+ let sphereEntity = ModelEntity(mesh: sphereMesh, materials: [SimpleMaterial(color: .white.withAlphaComponent(0.7), isMetallic: false)])
122
+ sphereEntity.position = position
123
+ return sphereEntity
124
+ }
125
+
126
+ func createSpheres(y: Float){
127
+ let radius = Float(0.1)
128
+ for i in 0..<72 {
129
+ let angle = Float(i) * (Float.pi / 180) * 5 // 10 degrees in radians
130
+ let x = radius * cos(angle)
131
+ let z = radius * sin(angle)
132
+ var spherePosition = SIMD3<Float>(x, y, z)
133
+ var sphereEntity = createSphere(position: spherePosition)
134
+ ReplateCameraView.spheresModels.append(sphereEntity)
135
+ ReplateCameraView.anchorEntity.addChild(sphereEntity)
136
+ }
137
+ }
138
+
139
+ ReplateCameraView.anchorEntity = AnchorEntity()
140
+ createSpheres(y: 0.0)
141
+ createSpheres(y: 0.3)
142
+ ReplateCameraView.arView.scene.anchors.append(ReplateCameraView.anchorEntity)
143
+ }
144
+ }
145
+
146
+ // @objc func setCameraRect(_ node: NSNumber, rect: NSDictionary) {
147
+ // let x = rect["x"] as? CGFloat ?? 0
148
+ // let y = rect["y"] as? CGFloat ?? 0
149
+ // let width = rect["width"] as? CGFloat ?? 0
150
+ // let height = rect["height"] as? CGFloat ?? 0
151
+ //// arView.(CGRect(x: x, y: y, width: width, height: height))
152
+ // }
153
+
154
+ @objc var color: String = "" {
155
+ didSet {
156
+ self.backgroundColor = hexStringToUIColor(hexColor: color)
157
+ }
158
+ }
159
+
160
+ func hexStringToUIColor(hexColor: String) -> UIColor {
161
+ let stringScanner = Scanner(string: hexColor)
162
+
163
+ if(hexColor.hasPrefix("#")) {
164
+ stringScanner.scanLocation = 1
165
+ }
166
+ var color: UInt32 = 0
167
+ stringScanner.scanHexInt32(&color)
168
+
169
+ let r = CGFloat(Int(color >> 16) & 0x000000FF)
170
+ let g = CGFloat(Int(color >> 8) & 0x000000FF)
171
+ let b = CGFloat(Int(color) & 0x000000FF)
172
+
173
+ return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
174
+ }
175
+
176
+ func session(_ session: ARSession, didUpdate frame: ARFrame) {
177
+ // Handle AR frame updates
178
+ // You can perform actions here, such as updating the AR content based on the camera frame
179
+ }
180
+
181
+ func sessionWasInterrupted(_ session: ARSession) {
182
+ // Handle session interruption (e.g., app goes to the background)
183
+
184
+ // Pause the AR session to save resources
185
+ ReplateCameraView.arView.session.pause()
186
+ }
187
+
188
+ func sessionInterruptionEnded(_ session: ARSession) {
189
+ // Handle resuming session after interruption
190
+
191
+ // Resume the AR session
192
+ ReplateCameraView.arView.session.run(ARWorldTrackingConfiguration())
193
+ }
194
+
195
+
196
+ }
197
+
198
+ @objc(ReplateCameraController)
199
+ class ReplateCameraController: NSObject {
200
+
201
+ @objc(takePhoto:rejecter:)
202
+ func takePhoto(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) -> Void {
203
+
204
+ //DEVICE ORIENTATION
205
+ guard let anchorNode = ReplateCameraView.anchorEntity else {
206
+ rejecter("[ReplateCameraController]", "Error saving photo", NSError(domain: "ReplateCameraController", code: 001, userInfo: nil));
207
+ return
208
+ }
209
+ // Assuming you have two points
210
+ let point1 = SIMD3<Float>(anchorNode.position.x,
211
+ anchorNode.position.y,
212
+ anchorNode.position.z)
213
+ let point2 = SIMD3<Float>(anchorNode.position.x,
214
+ anchorNode.position.y + 0.3,
215
+ anchorNode.position.z)
216
+
217
+ // Function to calculate the angle between two vectors
218
+ func angleBetweenVectors(_ vector1: SIMD3<Float>, _ vector2: SIMD3<Float>) -> Float {
219
+ let dotProduct = dot(normalize(vector1), normalize(vector2))
220
+ return acos(dotProduct)
221
+ }
222
+
223
+ // Threshold angle for considering if the device is pointing towards a point
224
+ let thresholdAngle: Float = 0.3 // Adjust this threshold as needed
225
+ var deviceTargetInFocus = -1
226
+ // Check if the device is pointing towards one of the two points
227
+ if let cameraTransform = ReplateCameraView.arView.session.currentFrame?.camera.transform {
228
+ let deviceDirection = SIMD3<Float>(-cameraTransform.columns.2.x, -cameraTransform.columns.2.y, -cameraTransform.columns.2.z)
229
+
230
+ let cameraPosition = SIMD3<Float>(cameraTransform.columns.3.x, cameraTransform.columns.3.y, cameraTransform.columns.3.z)
231
+
232
+
233
+ let directionToFirstPoint = normalize(point1 - cameraPosition)
234
+ let directionToSecondPoint = normalize(point2 - cameraPosition)
235
+
236
+ let angleToFirstPoint = angleBetweenVectors(deviceDirection, directionToFirstPoint)
237
+ let angleToSecondPoint = angleBetweenVectors(deviceDirection, directionToSecondPoint)
238
+ print("Camera Y: \(cameraPosition.y)")
239
+ let isPointingAtFirstPoint = angleToFirstPoint < thresholdAngle && cameraPosition.y < 0.25
240
+ let isPointingAtSecondPoint = angleToSecondPoint < thresholdAngle && cameraPosition.y >= 0.25
241
+ if (isPointingAtFirstPoint) {
242
+ deviceTargetInFocus = 0
243
+ }else if(isPointingAtSecondPoint){
244
+ deviceTargetInFocus = 1
245
+ }
246
+ // Now you can determine if the device is pointing towards one of the two points
247
+ print("Is pointing at first point: \(isPointingAtFirstPoint)")
248
+ print("Is pointing at second point: \(isPointingAtSecondPoint)")
249
+ } else {
250
+ print("Camera transform data not available")
251
+ }
252
+
253
+ print("Take photo")
254
+ if(deviceTargetInFocus != -1){
255
+ if let image = ReplateCameraView.arView?.session.currentFrame?.capturedImage {
256
+ let ciimg = CIImage(cvImageBuffer: image)
257
+ let ciImage = ciimg
258
+ let cgImage = ReplateCameraController.cgImage(from: ciImage)!
259
+ let finImage = UIImage(cgImage: cgImage)
260
+ print("Saving photo")
261
+ if let url = ReplateCameraController.saveImageAsJPEG(finImage) {
262
+ resolver(url.absoluteString)
263
+ print("Saved photo")
264
+ updateSpheres(deviceTargetInFocus: deviceTargetInFocus)
265
+ return
266
+ }
267
+ }
268
+ }
269
+
270
+ print("Error saving photo")
271
+ rejecter("[ReplateCameraController]", "Error saving photo", NSError(domain: "ReplateCameraController", code: 001, userInfo: nil))
272
+
273
+ }
274
+
275
+
276
+ static func cgImage(from ciImage: CIImage) -> CGImage? {
277
+ let context = CIContext(options: nil)
278
+ return context.createCGImage(ciImage, from: ciImage.extent)
279
+ }
280
+
281
+ static func saveImageAsJPEG(_ image: UIImage) -> URL? {
282
+ // Convert UIImage to Data with JPEG representation
283
+ guard let imageData = image.jpegData(compressionQuality: 1.0) else {
284
+ // Handle error if unable to convert to JPEG data
285
+ print("Error converting UIImage to JPEG data")
286
+ return nil
287
+ }
288
+
289
+ // Get the temporary directory URL
290
+ let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
291
+
292
+ // Create a unique filename (you can use a UUID or any other method to generate a unique name)
293
+ let uniqueFilename = "image_\(Date().timeIntervalSince1970).jpg"
294
+
295
+ // Combine the temporary directory URL with the unique filename to get the full file URL
296
+ let fileURL = temporaryDirectoryURL.appendingPathComponent(uniqueFilename)
297
+
298
+ do {
299
+ // Write the JPEG data to the file
300
+ try imageData.write(to: fileURL, options: .atomic)
301
+
302
+ // Print the file URL for reference
303
+ print("Image saved at: \(fileURL.absoluteString)")
304
+ return fileURL
305
+ } catch {
306
+ // Handle the error if unable to write to the file
307
+ print("Error saving image: \(error.localizedDescription)")
308
+ return nil
309
+ }
310
+ }
311
+
312
+
313
+ @objc
314
+ func constantsToExport() -> [String: Any]! {
315
+ return ["someKey": "someValue"]
316
+ }
317
+
318
+ func updateSpheres(deviceTargetInFocus: Int) {
319
+ guard let anchorNode = ReplateCameraView.anchorEntity else { return }
320
+
321
+ // Get the camera's pose
322
+ if let frame = ReplateCameraView.arView.session.currentFrame {
323
+ let cameraTransform = frame.camera.transform
324
+
325
+ // Calculate the angle between the camera and the anchor
326
+ let anchorPosition = SCNVector3(anchorNode.position.x,
327
+ anchorNode.position.y,
328
+ anchorNode.position.z)
329
+ let cameraPosition = SCNVector3(cameraTransform.columns.3.x,
330
+ cameraTransform.columns.3.y,
331
+ cameraTransform.columns.3.z)
332
+
333
+ let angleToAnchor = calculateAngle(cameraPosition, anchorPosition)
334
+
335
+ let sphereIndex = Int(floor(angleToAnchor/5))
336
+ var mesh: ModelEntity?
337
+ if(deviceTargetInFocus == 1 && !ReplateCameraView.upperSpheresSet[sphereIndex]){
338
+ ReplateCameraView.upperSpheresSet[sphereIndex] = true
339
+ mesh = ReplateCameraView.spheresModels[72+sphereIndex]
340
+ }else if(deviceTargetInFocus == 0 && !ReplateCameraView.lowerSpheresSet[sphereIndex]){
341
+ ReplateCameraView.lowerSpheresSet[sphereIndex] = true
342
+ mesh = ReplateCameraView.spheresModels[sphereIndex]
343
+ }
344
+ if (mesh != nil){
345
+ let material = SimpleMaterial(color: .green, isMetallic: false)
346
+ mesh?.model?.materials[0] = material
347
+ }
348
+ }
349
+ }
350
+
351
+ func calculateAngle(_ vector1: SCNVector3, _ vector2: SCNVector3) -> Float {
352
+ // Calculate the angle in 2D plane (x-z plane) using atan2
353
+ let angle = atan2(vector1.z, vector1.x)
354
+
355
+ // Convert from radians to degrees
356
+ var angleInDegrees = GLKMathRadiansToDegrees(Float(angle))
357
+
358
+ // Adjust the angle to be between 0 and 360 degrees
359
+ if angleInDegrees < 0 {
360
+ angleInDegrees += 360
361
+ }
362
+
363
+ return angleInDegrees
364
+ }
365
+
366
+ }
367
+
368
+ extension SCNVector3 {
369
+ func normalized() -> SCNVector3 {
370
+ let length = sqrt(x*x + y*y + z*z)
371
+ return SCNVector3(x/length, y/length, z/length)
372
+ }
373
+
374
+ static func Dot(_ a: SCNVector3, _ b: SCNVector3) -> Float {
375
+ return a.x*b.x + a.y*b.y + a.z*b.z
376
+ }
377
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ReplateCameraView = void 0;
7
+ exports.takePhoto = takePhoto;
8
+ var _reactNative = require("react-native");
9
+ const LINKING_ERROR = `The package 'replate-camera' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
10
+ ios: "- You have run 'pod install'\n",
11
+ default: ''
12
+ }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
13
+ const ComponentName = 'ReplateCameraView';
14
+ const ReplateCameraView = exports.ReplateCameraView = _reactNative.UIManager.getViewManagerConfig(ComponentName) != null ? (0, _reactNative.requireNativeComponent)(ComponentName) : () => {
15
+ throw new Error(LINKING_ERROR);
16
+ };
17
+ const ReplateCameraModule = _reactNative.NativeModules.ReplateCameraController ? _reactNative.NativeModules.ReplateCameraController : new Proxy({}, {
18
+ get() {
19
+ throw new Error(LINKING_ERROR);
20
+ }
21
+ });
22
+ function takePhoto() {
23
+ return ReplateCameraModule.takePhoto();
24
+ }
25
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","LINKING_ERROR","Platform","select","ios","default","ComponentName","ReplateCameraView","exports","UIManager","getViewManagerConfig","requireNativeComponent","Error","ReplateCameraModule","NativeModules","ReplateCameraController","Proxy","get","takePhoto"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;;;;;;AAAA,IAAAA,YAAA,GAAAC,OAAA;AAQA,MAAMC,aAAa,GAChB,yEAAwE,GACzEC,qBAAQ,CAACC,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAQjC,MAAMC,aAAa,GAAG,mBAAmB;AAElC,MAAMC,iBAAiB,GAAAC,OAAA,CAAAD,iBAAA,GAC5BE,sBAAS,CAACC,oBAAoB,CAACJ,aAAa,CAAC,IAAI,IAAI,GACjD,IAAAK,mCAAsB,EAAqBL,aAAa,CAAC,GACzD,MAAM;EACJ,MAAM,IAAIM,KAAK,CAACX,aAAa,CAAC;AAChC,CAAC;AAEP,MAAMY,mBAAmB,GAAGC,0BAAa,CAACC,uBAAuB,GAC7DD,0BAAa,CAACC,uBAAuB,GACrC,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIL,KAAK,CAACX,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAEE,SAASiB,SAASA,CAAA,EAAoB;EAC3C,OAAOL,mBAAmB,CAACK,SAAS,CAAC,CAAC;AACxC","ignoreList":[]}
@@ -0,0 +1,18 @@
1
+ import { requireNativeComponent, UIManager, Platform, NativeModules } from 'react-native';
2
+ const LINKING_ERROR = `The package 'replate-camera' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
3
+ ios: "- You have run 'pod install'\n",
4
+ default: ''
5
+ }) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo Go\n';
6
+ const ComponentName = 'ReplateCameraView';
7
+ export const ReplateCameraView = UIManager.getViewManagerConfig(ComponentName) != null ? requireNativeComponent(ComponentName) : () => {
8
+ throw new Error(LINKING_ERROR);
9
+ };
10
+ const ReplateCameraModule = NativeModules.ReplateCameraController ? NativeModules.ReplateCameraController : new Proxy({}, {
11
+ get() {
12
+ throw new Error(LINKING_ERROR);
13
+ }
14
+ });
15
+ export function takePhoto() {
16
+ return ReplateCameraModule.takePhoto();
17
+ }
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["requireNativeComponent","UIManager","Platform","NativeModules","LINKING_ERROR","select","ios","default","ComponentName","ReplateCameraView","getViewManagerConfig","Error","ReplateCameraModule","ReplateCameraController","Proxy","get","takePhoto"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"AAAA,SACEA,sBAAsB,EACtBC,SAAS,EACTC,QAAQ,EAERC,aAAa,QACR,cAAc;AAErB,MAAMC,aAAa,GAChB,yEAAwE,GACzEF,QAAQ,CAACG,MAAM,CAAC;EAAEC,GAAG,EAAE,gCAAgC;EAAEC,OAAO,EAAE;AAAG,CAAC,CAAC,GACvE,sDAAsD,GACtD,+BAA+B;AAQjC,MAAMC,aAAa,GAAG,mBAAmB;AAEzC,OAAO,MAAMC,iBAAiB,GAC5BR,SAAS,CAACS,oBAAoB,CAACF,aAAa,CAAC,IAAI,IAAI,GACjDR,sBAAsB,CAAqBQ,aAAa,CAAC,GACzD,MAAM;EACJ,MAAM,IAAIG,KAAK,CAACP,aAAa,CAAC;AAChC,CAAC;AAEP,MAAMQ,mBAAmB,GAAGT,aAAa,CAACU,uBAAuB,GAC7DV,aAAa,CAACU,uBAAuB,GACrC,IAAIC,KAAK,CACP,CAAC,CAAC,EACF;EACEC,GAAGA,CAAA,EAAG;IACJ,MAAM,IAAIJ,KAAK,CAACP,aAAa,CAAC;EAChC;AACF,CACF,CAAC;AAEL,OAAO,SAASY,SAASA,CAAA,EAAoB;EAC3C,OAAOJ,mBAAmB,CAACI,SAAS,CAAC,CAAC;AACxC","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ import { type ViewStyle } from 'react-native';
2
+ type ReplateCameraProps = {
3
+ color: string;
4
+ style: ViewStyle;
5
+ };
6
+ export declare const ReplateCameraView: import("react-native").HostComponent<ReplateCameraProps> | (() => never);
7
+ export declare function takePhoto(): Promise<string>;
8
+ export {};
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,SAAS,EAEf,MAAM,cAAc,CAAC;AAQtB,KAAK,kBAAkB,GAAG;IAExB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;CAClB,CAAC;AAIF,eAAO,MAAM,iBAAiB,0EAKvB,CAAC;AAaR,wBAAgB,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAE3C"}
package/package.json ADDED
@@ -0,0 +1,160 @@
1
+ {
2
+ "name": "replate-camera",
3
+ "version": "0.1.1",
4
+ "description": "Camera component for Replate Manager",
5
+ "main": "lib/commonjs/index",
6
+ "module": "lib/module/index",
7
+ "types": "lib/typescript/src/index.d.ts",
8
+ "react-native": "src/index",
9
+ "source": "src/index",
10
+ "files": [
11
+ "src",
12
+ "lib",
13
+ "android",
14
+ "ios",
15
+ "cpp",
16
+ "*.podspec",
17
+ "!ios/build",
18
+ "!android/build",
19
+ "!android/gradle",
20
+ "!android/gradlew",
21
+ "!android/gradlew.bat",
22
+ "!android/local.properties",
23
+ "!**/__tests__",
24
+ "!**/__fixtures__",
25
+ "!**/__mocks__",
26
+ "!**/.*"
27
+ ],
28
+ "scripts": {
29
+ "example": "yarn workspace replate-camera-example",
30
+ "test": "jest",
31
+ "typecheck": "tsc --noEmit",
32
+ "lint": "eslint \"**/*.{js,ts,tsx}\"",
33
+ "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
34
+ "prepare": "bob build",
35
+ "release": "release-it"
36
+ },
37
+ "keywords": [
38
+ "react-native",
39
+ "ios",
40
+ "android"
41
+ ],
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/ReplateItaly/replate-camera.git"
45
+ },
46
+ "author": "Filippo Cavallari <filippo.cavallari99@gmail.com> (https://github.com/Filocava99)",
47
+ "license": "MIT",
48
+ "bugs": {
49
+ "url": "https://github.com/ReplateItaly/replate-camera/issues"
50
+ },
51
+ "homepage": "https://github.com/ReplateItaly/replate-camera#readme",
52
+ "publishConfig": {
53
+ "registry": "https://registry.npmjs.org/"
54
+ },
55
+ "devDependencies": {
56
+ "@commitlint/config-conventional": "^17.0.2",
57
+ "@evilmartians/lefthook": "^1.5.0",
58
+ "@react-native/eslint-config": "^0.73.1",
59
+ "@release-it/conventional-changelog": "^5.0.0",
60
+ "@types/jest": "^29.5.5",
61
+ "@types/react": "^18.2.44",
62
+ "commitlint": "^17.0.2",
63
+ "del-cli": "^5.1.0",
64
+ "eslint": "^8.51.0",
65
+ "eslint-config-prettier": "^9.0.0",
66
+ "eslint-plugin-prettier": "^5.0.1",
67
+ "jest": "^29.7.0",
68
+ "prettier": "^3.0.3",
69
+ "react": "18.2.0",
70
+ "react-native": "0.73.5",
71
+ "react-native-builder-bob": "^0.20.0",
72
+ "release-it": "^15.0.0",
73
+ "turbo": "^1.10.7",
74
+ "typescript": "^5.2.2"
75
+ },
76
+ "resolutions": {
77
+ "@types/react": "^18.2.44"
78
+ },
79
+ "peerDependencies": {
80
+ "react": "*",
81
+ "react-native": "*"
82
+ },
83
+ "workspaces": [
84
+ "example"
85
+ ],
86
+ "packageManager": "yarn@3.6.1",
87
+ "jest": {
88
+ "preset": "react-native",
89
+ "modulePathIgnorePatterns": [
90
+ "<rootDir>/example/node_modules",
91
+ "<rootDir>/lib/"
92
+ ]
93
+ },
94
+ "commitlint": {
95
+ "extends": [
96
+ "@commitlint/config-conventional"
97
+ ]
98
+ },
99
+ "release-it": {
100
+ "git": {
101
+ "commitMessage": "chore: release ${version}",
102
+ "tagName": "v${version}"
103
+ },
104
+ "npm": {
105
+ "publish": true
106
+ },
107
+ "github": {
108
+ "release": true
109
+ },
110
+ "plugins": {
111
+ "@release-it/conventional-changelog": {
112
+ "preset": "angular"
113
+ }
114
+ }
115
+ },
116
+ "eslintConfig": {
117
+ "root": true,
118
+ "extends": [
119
+ "@react-native",
120
+ "prettier"
121
+ ],
122
+ "rules": {
123
+ "prettier/prettier": [
124
+ "error",
125
+ {
126
+ "quoteProps": "consistent",
127
+ "singleQuote": true,
128
+ "tabWidth": 2,
129
+ "trailingComma": "es5",
130
+ "useTabs": false
131
+ }
132
+ ]
133
+ }
134
+ },
135
+ "eslintIgnore": [
136
+ "node_modules/",
137
+ "lib/"
138
+ ],
139
+ "prettier": {
140
+ "quoteProps": "consistent",
141
+ "singleQuote": true,
142
+ "tabWidth": 2,
143
+ "trailingComma": "es5",
144
+ "useTabs": false
145
+ },
146
+ "react-native-builder-bob": {
147
+ "source": "src",
148
+ "output": "lib",
149
+ "targets": [
150
+ "commonjs",
151
+ "module",
152
+ [
153
+ "typescript",
154
+ {
155
+ "project": "tsconfig.build.json"
156
+ }
157
+ ]
158
+ ]
159
+ }
160
+ }
@@ -0,0 +1,42 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "package.json")))
4
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = "replate-camera"
8
+ s.version = package["version"]
9
+ s.summary = package["description"]
10
+ s.homepage = package["homepage"]
11
+ s.license = package["license"]
12
+ s.authors = package["author"]
13
+
14
+ s.platforms = { :ios => min_ios_version_supported }
15
+ s.source = { :git => "https://github.com/ReplateItaly/replate-camera.git", :tag => "#{s.version}" }
16
+
17
+ s.source_files = "ios/**/*.{h,m,mm,swift}"
18
+
19
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
20
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
21
+ if respond_to?(:install_modules_dependencies, true)
22
+ install_modules_dependencies(s)
23
+ else
24
+ s.dependency "React-Core"
25
+
26
+ # Don't install the dependencies when we run `pod install` in the old architecture.
27
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
28
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
29
+ s.pod_target_xcconfig = {
30
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
31
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
32
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
33
+ }
34
+ s.dependency "React-RCTFabric"
35
+ s.dependency "React-Codegen"
36
+ s.dependency "RCT-Folly"
37
+ s.dependency "RCTRequired"
38
+ s.dependency "RCTTypeSafety"
39
+ s.dependency "ReactCommon/turbomodule/core"
40
+ end
41
+ end
42
+ end
package/src/index.tsx ADDED
@@ -0,0 +1,43 @@
1
+ import {
2
+ requireNativeComponent,
3
+ UIManager,
4
+ Platform,
5
+ type ViewStyle,
6
+ NativeModules,
7
+ } from 'react-native';
8
+
9
+ const LINKING_ERROR =
10
+ `The package 'replate-camera' doesn't seem to be linked. Make sure: \n\n` +
11
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
12
+ '- You rebuilt the app after installing the package\n' +
13
+ '- You are not using Expo Go\n';
14
+
15
+ type ReplateCameraProps = {
16
+ // rect: Object;
17
+ color: string;
18
+ style: ViewStyle;
19
+ };
20
+
21
+ const ComponentName = 'ReplateCameraView';
22
+
23
+ export const ReplateCameraView =
24
+ UIManager.getViewManagerConfig(ComponentName) != null
25
+ ? requireNativeComponent<ReplateCameraProps>(ComponentName)
26
+ : () => {
27
+ throw new Error(LINKING_ERROR);
28
+ };
29
+
30
+ const ReplateCameraModule = NativeModules.ReplateCameraController
31
+ ? NativeModules.ReplateCameraController
32
+ : new Proxy(
33
+ {},
34
+ {
35
+ get() {
36
+ throw new Error(LINKING_ERROR);
37
+ },
38
+ }
39
+ );
40
+
41
+ export function takePhoto(): Promise<string> {
42
+ return ReplateCameraModule.takePhoto();
43
+ }