replate-camera 0.1.49 → 0.1.50
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/ios/ReplateCameraViewManager.m +3 -2
- package/ios/ReplateCameraViewManager.swift +145 -139
- package/lib/commonjs/index.js +4 -0
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/index.js +3 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/index.tsx +4 -0
|
@@ -7,14 +7,13 @@
|
|
|
7
7
|
// RCT_EXPORT_VIEW_PROPERTY(rect, NSDictionary)
|
|
8
8
|
RCT_EXPORT_VIEW_PROPERTY(color, NSString)
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
@end
|
|
12
11
|
|
|
13
12
|
|
|
14
13
|
@interface RCT_EXTERN_MODULE(ReplateCameraController, NSObject)
|
|
15
14
|
|
|
16
15
|
RCT_EXTERN_METHOD(takePhoto:(BOOL*)unlimited
|
|
17
|
-
resolver:(RCTPromiseResolveBlock)resolver
|
|
16
|
+
resolver:(RCTPromiseResolveBlock)resolver
|
|
18
17
|
rejecter:(RCTPromiseRejectBlock)rejecter)
|
|
19
18
|
|
|
20
19
|
RCT_EXTERN_METHOD(getPhotosCount:(RCTPromiseResolveBlock*)resolve
|
|
@@ -36,6 +35,8 @@ RCT_EXTERN_METHOD(registerCompletedLowerSpheresCallback:(RCTResponseSenderBlock)
|
|
|
36
35
|
|
|
37
36
|
RCT_EXTERN_METHOD(registerOpenedTutorialCallback:(RCTResponseSenderBlock)callback)
|
|
38
37
|
|
|
38
|
+
RCT_EXTERN_METHOD(reset)
|
|
39
|
+
|
|
39
40
|
+ (BOOL)requiresMainQueueSetup
|
|
40
41
|
{
|
|
41
42
|
return NO;
|
|
@@ -5,17 +5,16 @@ import AVFoundation
|
|
|
5
5
|
|
|
6
6
|
@objc(ReplateCameraViewManager)
|
|
7
7
|
class ReplateCameraViewManager: RCTViewManager {
|
|
8
|
-
|
|
8
|
+
|
|
9
9
|
override func view() -> (ReplateCameraView) {
|
|
10
10
|
let replCameraView = ReplateCameraView()
|
|
11
11
|
return replCameraView
|
|
12
12
|
}
|
|
13
|
-
|
|
13
|
+
|
|
14
14
|
@objc override static func requiresMainQueueSetup() -> Bool {
|
|
15
15
|
return false
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
|
|
19
18
|
}
|
|
20
19
|
|
|
21
20
|
extension UIImage {
|
|
@@ -24,26 +23,26 @@ extension UIImage {
|
|
|
24
23
|
// Trim off the extremely small float value to prevent core graphics from rounding it up
|
|
25
24
|
newSize.width = floor(newSize.width)
|
|
26
25
|
newSize.height = floor(newSize.height)
|
|
27
|
-
|
|
26
|
+
|
|
28
27
|
UIGraphicsBeginImageContextWithOptions(newSize, false, self.scale)
|
|
29
28
|
let context = UIGraphicsGetCurrentContext()!
|
|
30
|
-
|
|
29
|
+
|
|
31
30
|
// Move origin to middle
|
|
32
31
|
context.translateBy(x: newSize.width / 2, y: newSize.height / 2)
|
|
33
32
|
// Rotate around middle
|
|
34
33
|
context.rotate(by: CGFloat(radians))
|
|
35
34
|
// Draw the image at its center
|
|
36
35
|
self.draw(in: CGRect(x: -self.size.width / 2, y: -self.size.height / 2, width: self.size.width, height: self.size.height))
|
|
37
|
-
|
|
36
|
+
|
|
38
37
|
let newImage = UIGraphicsGetImageFromCurrentImageContext()!
|
|
39
38
|
UIGraphicsEndImageContext()
|
|
40
|
-
|
|
39
|
+
|
|
41
40
|
return newImage
|
|
42
41
|
}
|
|
43
42
|
}
|
|
44
43
|
|
|
45
44
|
class ReplateCameraView: UIView, ARSessionDelegate {
|
|
46
|
-
|
|
45
|
+
|
|
47
46
|
static var arView: ARView!
|
|
48
47
|
static var anchorEntity: AnchorEntity!
|
|
49
48
|
static var model: Entity!
|
|
@@ -64,22 +63,22 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
64
63
|
static var distanceBetweenCircles = Float(0.10)
|
|
65
64
|
static var circleInFocus = 0 //0 for lower, 1 for upper
|
|
66
65
|
static var dotAnchors: [AnchorEntity] = []
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
|
|
67
|
+
|
|
69
68
|
override init(frame: CGRect) {
|
|
70
69
|
super.init(frame: frame)
|
|
71
70
|
requestCameraPermissions()
|
|
72
71
|
// setupAR()
|
|
73
72
|
ReplateCameraView.INSTANCE = self
|
|
74
73
|
}
|
|
75
|
-
|
|
74
|
+
|
|
76
75
|
required init?(coder: NSCoder) {
|
|
77
76
|
super.init(coder: coder)
|
|
78
77
|
requestCameraPermissions()
|
|
79
78
|
ReplateCameraView.INSTANCE = self
|
|
80
79
|
// setupAR()
|
|
81
80
|
}
|
|
82
|
-
|
|
81
|
+
|
|
83
82
|
static func addRecognizer() {
|
|
84
83
|
let recognizer = UITapGestureRecognizer(target: ReplateCameraView.INSTANCE,
|
|
85
84
|
action: #selector(ReplateCameraView.INSTANCE.viewTapped(_:)))
|
|
@@ -89,9 +88,9 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
89
88
|
let pinchGestureRecognizer = UIPinchGestureRecognizer(target: ReplateCameraView.INSTANCE, action: #selector(ReplateCameraView.INSTANCE.handlePinch(_:)))
|
|
90
89
|
ReplateCameraView.arView.addGestureRecognizer(pinchGestureRecognizer)
|
|
91
90
|
}
|
|
92
|
-
|
|
91
|
+
|
|
93
92
|
func requestCameraPermissions() {
|
|
94
|
-
|
|
93
|
+
|
|
95
94
|
if AVCaptureDevice.authorizationStatus(for: .video) == .authorized {
|
|
96
95
|
print("Camera permissions already granted")
|
|
97
96
|
} else {
|
|
@@ -104,19 +103,19 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
104
103
|
})
|
|
105
104
|
}
|
|
106
105
|
}
|
|
107
|
-
|
|
106
|
+
|
|
108
107
|
override func layoutSubviews() {
|
|
109
108
|
super.layoutSubviews()
|
|
110
|
-
|
|
109
|
+
|
|
111
110
|
// Now you can safely access the size
|
|
112
111
|
let width = self.frame.width
|
|
113
112
|
let height = self.frame.height
|
|
114
|
-
|
|
113
|
+
|
|
115
114
|
// Do something with width and height
|
|
116
115
|
print("Width: \(width), Height: \(height)")
|
|
117
116
|
self.setupAR()
|
|
118
117
|
}
|
|
119
|
-
|
|
118
|
+
|
|
120
119
|
@objc private func handlePan(_ gestureRecognizer: UIPanGestureRecognizer) {
|
|
121
120
|
print("handle pan")
|
|
122
121
|
guard let sceneView = gestureRecognizer.view as? ARView else {
|
|
@@ -130,11 +129,11 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
130
129
|
print(translation)
|
|
131
130
|
let initialPosition = anchorEntity.position
|
|
132
131
|
ReplateCameraView.anchorEntity.position = initialPosition + SIMD3(Float(translation.x / ReplateCameraView.dragSpeed), 0, Float(translation.y / ReplateCameraView.dragSpeed))
|
|
133
|
-
|
|
132
|
+
|
|
134
133
|
gestureRecognizer.setTranslation(.zero, in: sceneView)
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
|
-
|
|
136
|
+
|
|
138
137
|
@objc func handlePinch(_ gestureRecognizer: UIPinchGestureRecognizer) {
|
|
139
138
|
guard let sceneView = gestureRecognizer.view as? ARView else {
|
|
140
139
|
return
|
|
@@ -145,13 +144,13 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
145
144
|
DispatchQueue.main.async {
|
|
146
145
|
// Calculate the scale based on the gesture recognizer's scale
|
|
147
146
|
let scale = Float(gestureRecognizer.scale)
|
|
148
|
-
|
|
147
|
+
|
|
149
148
|
// Ensure anchor entity is not nil before proceeding
|
|
150
149
|
guard let anchorEntity = ReplateCameraView.anchorEntity else {
|
|
151
150
|
print("[handlePinch] Anchor entity is nil.")
|
|
152
151
|
return
|
|
153
152
|
}
|
|
154
|
-
|
|
153
|
+
|
|
155
154
|
// Remove all child entities safely
|
|
156
155
|
ReplateCameraView.spheresModels.forEach { entity in
|
|
157
156
|
anchorEntity.removeChild(entity)
|
|
@@ -159,20 +158,20 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
159
158
|
if let focusModel = ReplateCameraView.focusModel {
|
|
160
159
|
anchorEntity.removeChild(focusModel)
|
|
161
160
|
}
|
|
162
|
-
|
|
161
|
+
|
|
163
162
|
// Clear spheres models array
|
|
164
163
|
ReplateCameraView.spheresModels = []
|
|
165
|
-
|
|
164
|
+
|
|
166
165
|
// Update the scales
|
|
167
166
|
ReplateCameraView.sphereRadius *= scale
|
|
168
167
|
ReplateCameraView.spheresRadius *= scale
|
|
169
168
|
ReplateCameraView.sphereAngle *= scale
|
|
170
|
-
|
|
169
|
+
|
|
171
170
|
// Recreate spheres and the focus sphere
|
|
172
171
|
self.createSpheres(y: ReplateCameraView.spheresHeight)
|
|
173
172
|
self.createSpheres(y: ReplateCameraView.distanceBetweenCircles + ReplateCameraView.spheresHeight)
|
|
174
173
|
self.createFocusSphere()
|
|
175
|
-
|
|
174
|
+
|
|
176
175
|
// Update the material of the spheres based on their state
|
|
177
176
|
for i in 0..<72 {
|
|
178
177
|
let material = SimpleMaterial(color: .green, roughness: 1, isMetallic: false)
|
|
@@ -193,7 +192,7 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
193
192
|
}
|
|
194
193
|
}
|
|
195
194
|
}
|
|
196
|
-
|
|
195
|
+
|
|
197
196
|
// Reset the gesture recognizer's scale to 1 to avoid cumulative scaling
|
|
198
197
|
gestureRecognizer.scale = 1.0
|
|
199
198
|
}
|
|
@@ -201,22 +200,22 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
201
200
|
break
|
|
202
201
|
}
|
|
203
202
|
}
|
|
204
|
-
|
|
203
|
+
|
|
205
204
|
func addDots(to planeAnchor: ARPlaneAnchor) {
|
|
206
205
|
print("Adding dots to plane anchor") // Debugging line
|
|
207
206
|
let center = planeAnchor.center
|
|
208
207
|
let extent = planeAnchor.extent
|
|
209
|
-
|
|
208
|
+
|
|
210
209
|
var dotPositions: [SIMD3<Float>] = []
|
|
211
210
|
let dotSpacing: Float = 0.05 // Adjust the spacing of dots (smaller value for more dots)
|
|
212
|
-
|
|
211
|
+
|
|
213
212
|
for x in stride(from: -extent.x / 2, through: extent.x / 2, by: dotSpacing) {
|
|
214
213
|
for z in stride(from: -extent.z / 2, through: extent.z / 2, by: dotSpacing) {
|
|
215
214
|
let position = SIMD3<Float>(x + center.x, 0, z + center.z)
|
|
216
215
|
dotPositions.append(position)
|
|
217
216
|
}
|
|
218
217
|
}
|
|
219
|
-
|
|
218
|
+
|
|
220
219
|
DispatchQueue.main.async {
|
|
221
220
|
// Add the dots to the ARView
|
|
222
221
|
for position in dotPositions {
|
|
@@ -230,37 +229,37 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
230
229
|
}
|
|
231
230
|
}
|
|
232
231
|
|
|
233
|
-
|
|
232
|
+
|
|
234
233
|
func createDot(at position: SIMD3<Float>) -> ModelEntity {
|
|
235
234
|
// Define the dimensions of the box
|
|
236
235
|
let width: Float = 0.005 // 1 cm width
|
|
237
236
|
let height: Float = 0.0001 // Very small height to make it almost flat
|
|
238
237
|
let depth: Float = width // 1 cm depth
|
|
239
238
|
let cornerRadius: Float = width/2.0 // Half of the width to make it look like a circle
|
|
240
|
-
|
|
239
|
+
|
|
241
240
|
// Generate a box with rounded corners
|
|
242
241
|
let cylinderMesh = MeshResource.generateBox(size: [width, height, depth], cornerRadius: cornerRadius)
|
|
243
|
-
|
|
242
|
+
|
|
244
243
|
// Create the material
|
|
245
244
|
let material = SimpleMaterial(color: .white, roughness: 1, isMetallic: false)
|
|
246
|
-
|
|
245
|
+
|
|
247
246
|
// Create the entity
|
|
248
247
|
let circleEntity = ModelEntity(mesh: cylinderMesh, materials: [material])
|
|
249
248
|
circleEntity.position = position
|
|
250
249
|
return circleEntity
|
|
251
250
|
}
|
|
252
|
-
|
|
253
|
-
|
|
251
|
+
|
|
252
|
+
|
|
254
253
|
@objc private func viewTapped(_ recognizer: UITapGestureRecognizer) {
|
|
255
254
|
print("VIEW TAPPED")
|
|
256
255
|
let tapLocation: CGPoint = recognizer.location(in: ReplateCameraView.arView)
|
|
257
256
|
let estimatedPlane: ARRaycastQuery.Target = .estimatedPlane
|
|
258
257
|
let alignment: ARRaycastQuery.TargetAlignment = .horizontal
|
|
259
|
-
|
|
258
|
+
|
|
260
259
|
let result: [ARRaycastResult] = ReplateCameraView.arView.raycast(from: tapLocation,
|
|
261
260
|
allowing: estimatedPlane,
|
|
262
261
|
alignment: alignment)
|
|
263
|
-
|
|
262
|
+
|
|
264
263
|
guard let rayCast: ARRaycastResult = result.first
|
|
265
264
|
else {
|
|
266
265
|
return
|
|
@@ -286,7 +285,7 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
286
285
|
createSpheres(y: ReplateCameraView.spheresHeight)
|
|
287
286
|
createSpheres(y: ReplateCameraView.distanceBetweenCircles + ReplateCameraView.spheresHeight)
|
|
288
287
|
createFocusSphere()
|
|
289
|
-
|
|
288
|
+
|
|
290
289
|
//DEBUG MESHES
|
|
291
290
|
// let xAxis = MeshResource.generateBox(width: 2, height: 0.001, depth: 0.01)
|
|
292
291
|
// let xLineEntity = ModelEntity(mesh: xAxis)
|
|
@@ -321,34 +320,34 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
321
320
|
// let circleEntity = ModelEntity(mesh: MeshResource.generateBox(size: 2, cornerRadius: 1))
|
|
322
321
|
// circleEntity.setPosition(SIMD3<Float>(0, 0, 0), relativeTo: ReplateCameraView.anchorEntity)
|
|
323
322
|
// circleEntity.model?.materials = [SimpleMaterial(color: .yellow, isMetallic: false)]
|
|
324
|
-
|
|
325
|
-
|
|
323
|
+
|
|
324
|
+
|
|
326
325
|
ReplateCameraView.arView.scene.anchors.append(ReplateCameraView.anchorEntity)
|
|
327
326
|
}
|
|
328
327
|
}
|
|
329
|
-
|
|
328
|
+
|
|
330
329
|
func createFocusSphere() {
|
|
331
330
|
DispatchQueue.main.async {
|
|
332
331
|
// Generate the sphere mesh
|
|
333
332
|
let sphereMesh = MeshResource.generateSphere(radius: ReplateCameraView.sphereRadius * 1.5)
|
|
334
|
-
|
|
333
|
+
|
|
335
334
|
// Create the sphere entity with initial material
|
|
336
335
|
let sphereEntity = ModelEntity(mesh: sphereMesh, materials: [SimpleMaterial(color: .white.withAlphaComponent(0.7), roughness: 1, isMetallic: false)])
|
|
337
|
-
|
|
336
|
+
|
|
338
337
|
// Set the position for the sphere entity
|
|
339
338
|
sphereEntity.position = SIMD3(x: 0, y: ReplateCameraView.spheresHeight + (ReplateCameraView.distanceBetweenCircles / 2), z: 0)
|
|
340
|
-
|
|
339
|
+
|
|
341
340
|
// Update the material of the sphere entity
|
|
342
341
|
sphereEntity.model?.materials = [SimpleMaterial(color: .green.withAlphaComponent(1), roughness: 1, isMetallic: false)]
|
|
343
|
-
|
|
342
|
+
|
|
344
343
|
// Set the focus model for the global state
|
|
345
344
|
ReplateCameraView.focusModel = sphereEntity
|
|
346
|
-
|
|
345
|
+
|
|
347
346
|
// Safely add the sphere entity to the anchor entity
|
|
348
347
|
ReplateCameraView.anchorEntity?.addChild(sphereEntity)
|
|
349
348
|
}
|
|
350
349
|
}
|
|
351
|
-
|
|
350
|
+
|
|
352
351
|
func createSphere(position: SIMD3<Float>) -> ModelEntity {
|
|
353
352
|
// Ensure execution on the main thread
|
|
354
353
|
guard Thread.isMainThread else {
|
|
@@ -356,20 +355,20 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
356
355
|
return createSphere(position: position)
|
|
357
356
|
}
|
|
358
357
|
}
|
|
359
|
-
|
|
358
|
+
|
|
360
359
|
// Generate sphere mesh safely
|
|
361
360
|
let sphereMesh = MeshResource.generateSphere(radius: ReplateCameraView.sphereRadius)
|
|
362
|
-
|
|
361
|
+
|
|
363
362
|
// Create sphere entity with the specified material
|
|
364
363
|
let sphereEntity = ModelEntity(mesh: sphereMesh, materials: [SimpleMaterial(color: .white.withAlphaComponent(1), roughness: 1, isMetallic: false)])
|
|
365
|
-
|
|
364
|
+
|
|
366
365
|
// Set the position for the sphere entity
|
|
367
366
|
sphereEntity.position = position
|
|
368
|
-
|
|
367
|
+
|
|
369
368
|
// Return the created sphere entity
|
|
370
369
|
return sphereEntity
|
|
371
370
|
}
|
|
372
|
-
|
|
371
|
+
|
|
373
372
|
func createSpheres(y: Float) {
|
|
374
373
|
let radius = ReplateCameraView.spheresRadius
|
|
375
374
|
for i in 0..<72 {
|
|
@@ -387,7 +386,7 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
387
386
|
ReplateCameraView.anchorEntity.addChild(sphereEntity)
|
|
388
387
|
}
|
|
389
388
|
}
|
|
390
|
-
|
|
389
|
+
|
|
391
390
|
func setupAR() {
|
|
392
391
|
print("Setup AR")
|
|
393
392
|
reset()
|
|
@@ -412,7 +411,7 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
412
411
|
// return resolution1 < resolution2
|
|
413
412
|
// })!
|
|
414
413
|
// }
|
|
415
|
-
|
|
414
|
+
|
|
416
415
|
ReplateCameraView.arView.renderOptions.insert(ARView.RenderOptions.disableMotionBlur)
|
|
417
416
|
ReplateCameraView.arView.renderOptions.insert(ARView.RenderOptions.disableCameraGrain)
|
|
418
417
|
ReplateCameraView.arView.renderOptions.insert(ARView.RenderOptions.disableAREnvironmentLighting)
|
|
@@ -451,29 +450,29 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
451
450
|
ReplateCameraView.arView.addCoaching()
|
|
452
451
|
ReplateCameraView.sessionId = ReplateCameraView.arView.session.identifier
|
|
453
452
|
}
|
|
454
|
-
|
|
453
|
+
|
|
455
454
|
@objc var color: String = "" {
|
|
456
455
|
didSet {
|
|
457
456
|
self.backgroundColor = hexStringToUIColor(hexColor: color)
|
|
458
457
|
}
|
|
459
458
|
}
|
|
460
|
-
|
|
459
|
+
|
|
461
460
|
func hexStringToUIColor(hexColor: String) -> UIColor {
|
|
462
461
|
let stringScanner = Scanner(string: hexColor)
|
|
463
|
-
|
|
462
|
+
|
|
464
463
|
if (hexColor.hasPrefix("#")) {
|
|
465
464
|
stringScanner.scanLocation = 1
|
|
466
465
|
}
|
|
467
466
|
var color: UInt32 = 0
|
|
468
467
|
stringScanner.scanHexInt32(&color)
|
|
469
|
-
|
|
468
|
+
|
|
470
469
|
let r = CGFloat(Int(color >> 16) & 0x000000FF)
|
|
471
470
|
let g = CGFloat(Int(color >> 8) & 0x000000FF)
|
|
472
471
|
let b = CGFloat(Int(color) & 0x000000FF)
|
|
473
|
-
|
|
472
|
+
|
|
474
473
|
return UIColor(red: r / 255.0, green: g / 255.0, blue: b / 255.0, alpha: 1)
|
|
475
474
|
}
|
|
476
|
-
|
|
475
|
+
|
|
477
476
|
internal func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
|
|
478
477
|
print("Planes detected: \(anchors.count)") // Debugging line
|
|
479
478
|
for anchor in anchors {
|
|
@@ -485,15 +484,15 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
485
484
|
}
|
|
486
485
|
}
|
|
487
486
|
}
|
|
488
|
-
|
|
487
|
+
|
|
489
488
|
func session(_ session: ARSession, didUpdate frame: ARFrame) {
|
|
490
489
|
// Handle AR frame updates
|
|
491
490
|
// You can perform actions here, such as updating the AR content based on the camera frame
|
|
492
491
|
}
|
|
493
|
-
|
|
492
|
+
|
|
494
493
|
func sessionWasInterrupted(_ session: ARSession) {
|
|
495
494
|
// Handle session interruption (e.g., app goes to the background)
|
|
496
|
-
|
|
495
|
+
|
|
497
496
|
// Pause the AR session to save resources
|
|
498
497
|
if (session.identifier == ReplateCameraView.sessionId) {
|
|
499
498
|
ReplateCameraView.arView.session.pause()
|
|
@@ -502,7 +501,7 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
502
501
|
ReplateCameraView.arView = nil
|
|
503
502
|
}
|
|
504
503
|
}
|
|
505
|
-
|
|
504
|
+
|
|
506
505
|
func sessionInterruptionEnded(_ session: ARSession) {
|
|
507
506
|
// Handle resuming session after interruption
|
|
508
507
|
if (session.identifier == ReplateCameraView.sessionId) {
|
|
@@ -510,8 +509,9 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
510
509
|
setupAR()
|
|
511
510
|
}
|
|
512
511
|
}
|
|
513
|
-
|
|
512
|
+
|
|
514
513
|
func reset() {
|
|
514
|
+
ReplateCameraView.arView.session.pause()
|
|
515
515
|
ReplateCameraView.anchorEntity = nil
|
|
516
516
|
ReplateCameraView.model = nil
|
|
517
517
|
ReplateCameraView.spheresModels = []
|
|
@@ -525,8 +525,9 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
525
525
|
ReplateCameraView.spheresHeight = Float(0.15)
|
|
526
526
|
ReplateCameraView.dragSpeed = CGFloat(7000)
|
|
527
527
|
ReplateCameraView.arView = nil
|
|
528
|
+
|
|
528
529
|
}
|
|
529
|
-
|
|
530
|
+
|
|
530
531
|
static func generateImpactFeedback(strength: UIImpactFeedbackGenerator.FeedbackStyle) {
|
|
531
532
|
do{
|
|
532
533
|
let impactFeedbackGenerator = UIImpactFeedbackGenerator(style: strength)
|
|
@@ -536,62 +537,67 @@ class ReplateCameraView: UIView, ARSessionDelegate {
|
|
|
536
537
|
print("Error when sending feedback")
|
|
537
538
|
}
|
|
538
539
|
}
|
|
539
|
-
|
|
540
|
+
|
|
540
541
|
}
|
|
541
542
|
|
|
542
543
|
@objc(ReplateCameraController)
|
|
543
544
|
class ReplateCameraController: NSObject {
|
|
544
|
-
|
|
545
|
+
|
|
545
546
|
static var completedTutorialCallback: RCTResponseSenderBlock?
|
|
546
547
|
static var anchorSetCallback: RCTResponseSenderBlock?
|
|
547
548
|
static var completedUpperSpheresCallback: RCTResponseSenderBlock?
|
|
548
549
|
static var completedLowerSpheresCallback: RCTResponseSenderBlock?
|
|
549
550
|
static var openedTutorialCallback: RCTResponseSenderBlock?
|
|
550
|
-
|
|
551
|
+
|
|
551
552
|
@objc(registerOpenedTutorialCallback:)
|
|
552
553
|
func registerOpenedTutorialCallback(_ myCallback: @escaping RCTResponseSenderBlock) {
|
|
553
554
|
ReplateCameraController.openedTutorialCallback = myCallback
|
|
554
555
|
}
|
|
555
|
-
|
|
556
|
+
|
|
556
557
|
@objc(registerCompletedTutorialCallback:)
|
|
557
558
|
func registerCompletedTutorialCallback(_ myCallback: @escaping RCTResponseSenderBlock) {
|
|
558
559
|
ReplateCameraController.completedTutorialCallback = myCallback
|
|
559
560
|
}
|
|
560
|
-
|
|
561
|
+
|
|
561
562
|
@objc(registerAnchorSetCallback:)
|
|
562
563
|
func registerAnchorSetCallback(_ myCallback: @escaping RCTResponseSenderBlock) {
|
|
563
564
|
ReplateCameraController.anchorSetCallback = myCallback
|
|
564
565
|
}
|
|
565
|
-
|
|
566
|
+
|
|
566
567
|
@objc(registerCompletedUpperSpheresCallback:)
|
|
567
568
|
func registerCompletedUpperSpheresCallback(_ myCallback: @escaping RCTResponseSenderBlock) {
|
|
568
569
|
ReplateCameraController.completedUpperSpheresCallback = myCallback
|
|
569
570
|
}
|
|
570
|
-
|
|
571
|
+
|
|
571
572
|
@objc(registerCompletedLowerSpheresCallback:)
|
|
572
573
|
func registerCompletedLowerSpheresCallback(_ myCallback: @escaping RCTResponseSenderBlock) {
|
|
573
574
|
ReplateCameraController.completedLowerSpheresCallback = myCallback
|
|
574
575
|
}
|
|
575
|
-
|
|
576
|
+
|
|
576
577
|
@objc(getPhotosCount:rejecter:)
|
|
577
578
|
func getPhotosCount(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) -> Void {
|
|
578
579
|
resolver(ReplateCameraView.totalPhotosTaken)
|
|
579
580
|
}
|
|
580
|
-
|
|
581
|
+
|
|
581
582
|
@objc(isScanComplete:rejecter:)
|
|
582
583
|
func isScanComplete(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) -> Void {
|
|
583
584
|
resolver(ReplateCameraView.photosFromDifferentAnglesTaken == 144)
|
|
584
585
|
}
|
|
585
|
-
|
|
586
|
+
|
|
586
587
|
@objc(getRemainingAnglesToScan:rejecter:)
|
|
587
588
|
func getRemainingAnglesToScan(_ resolver: RCTPromiseResolveBlock, rejecter: RCTPromiseRejectBlock) -> Void {
|
|
588
589
|
resolver(144 - ReplateCameraView.photosFromDifferentAnglesTaken)
|
|
589
590
|
}
|
|
591
|
+
|
|
592
|
+
@objc
|
|
593
|
+
func reset(){
|
|
594
|
+
ReplateCameraView.INSTANCE.setupAR()
|
|
595
|
+
}
|
|
590
596
|
|
|
591
597
|
@objc(takePhoto:resolver:rejecter:)
|
|
592
598
|
func takePhoto(_ unlimited: Bool = false, resolver: @escaping RCTPromiseResolveBlock, rejecter: @escaping RCTPromiseRejectBlock) {
|
|
593
599
|
var hasCalledBack = false
|
|
594
|
-
|
|
600
|
+
|
|
595
601
|
func safeResolver(_ result: Any) {
|
|
596
602
|
if !hasCalledBack {
|
|
597
603
|
hasCalledBack = true
|
|
@@ -600,7 +606,7 @@ class ReplateCameraController: NSObject {
|
|
|
600
606
|
print("resolver: Callback already invoked.")
|
|
601
607
|
}
|
|
602
608
|
}
|
|
603
|
-
|
|
609
|
+
|
|
604
610
|
func safeRejecter(_ code: String, _ message: String, _ error: NSError) {
|
|
605
611
|
if !hasCalledBack {
|
|
606
612
|
hasCalledBack = true
|
|
@@ -609,13 +615,13 @@ class ReplateCameraController: NSObject {
|
|
|
609
615
|
print("rejecter: Callback already invoked.")
|
|
610
616
|
}
|
|
611
617
|
}
|
|
612
|
-
|
|
618
|
+
|
|
613
619
|
do {
|
|
614
620
|
guard let anchorNode = ReplateCameraView.anchorEntity else {
|
|
615
621
|
safeRejecter("001", "[ReplateCameraController] No anchor set yet", NSError(domain: "ReplateCameraController", code: 001, userInfo: nil))
|
|
616
622
|
return
|
|
617
623
|
}
|
|
618
|
-
|
|
624
|
+
|
|
619
625
|
// Calculate anchor position and height-related constants once
|
|
620
626
|
let anchorPosition = anchorNode.position(relativeTo: nil)
|
|
621
627
|
let spheresHeight = ReplateCameraView.spheresHeight
|
|
@@ -632,7 +638,7 @@ class ReplateCameraController: NSObject {
|
|
|
632
638
|
let deviceDirection = normalize(SIMD3<Float>(-cameraTransform.columns.2.x, -cameraTransform.columns.2.y, -cameraTransform.columns.2.z))
|
|
633
639
|
let directionToAnchor = normalize(anchorPosition - cameraPosition)
|
|
634
640
|
let angleToAnchor = acos(dot(deviceDirection, directionToAnchor))
|
|
635
|
-
|
|
641
|
+
|
|
636
642
|
if angleToAnchor < angleThreshold {
|
|
637
643
|
let cameraHeight = relativeCameraTransform.columns.3.y
|
|
638
644
|
if cameraHeight < twoThirdsDistance {
|
|
@@ -650,9 +656,9 @@ class ReplateCameraController: NSObject {
|
|
|
650
656
|
safeRejecter("002", "[ReplateCameraController] Camera transform data not available", NSError(domain: "ReplateCameraController", code: 002, userInfo: nil))
|
|
651
657
|
return
|
|
652
658
|
}
|
|
653
|
-
|
|
659
|
+
|
|
654
660
|
if deviceTargetInFocus != -1 {
|
|
655
|
-
|
|
661
|
+
|
|
656
662
|
func setOpacityToCircle(circleId: Int, opacity: Float) {
|
|
657
663
|
DispatchQueue.main.async{
|
|
658
664
|
for i in 0..<72 {
|
|
@@ -682,30 +688,30 @@ class ReplateCameraController: NSObject {
|
|
|
682
688
|
safeRejecter("003", "[ReplateCameraController] Too many images and the last one's not from a new angle", NSError(domain: "ReplateCameraController", code: 003, userInfo: nil))
|
|
683
689
|
return
|
|
684
690
|
}
|
|
685
|
-
|
|
691
|
+
|
|
686
692
|
if let image = ReplateCameraView.arView?.session.currentFrame?.capturedImage {
|
|
687
693
|
let ciImage = CIImage(cvImageBuffer: image)
|
|
688
694
|
guard let cgImage = ReplateCameraController.cgImage(from: ciImage) else {
|
|
689
695
|
safeRejecter("004", "[ReplateCameraController] Error converting CIImage to CGImage", NSError(domain: "ReplateCameraController", code: 004, userInfo: nil))
|
|
690
696
|
return
|
|
691
697
|
}
|
|
692
|
-
|
|
698
|
+
|
|
693
699
|
let uiImage = UIImage(cgImage: cgImage)
|
|
694
700
|
let finImage = uiImage.rotate(radians: .pi / 2) // Adjust radians as needed
|
|
695
|
-
|
|
701
|
+
|
|
696
702
|
if let lightEstimate = ReplateCameraView.arView.session.currentFrame?.lightEstimate {
|
|
697
703
|
let ambientIntensity = lightEstimate.ambientIntensity
|
|
698
704
|
let ambientColorTemperature = lightEstimate.ambientColorTemperature
|
|
699
|
-
|
|
705
|
+
|
|
700
706
|
if ambientIntensity < 300 {
|
|
701
707
|
safeRejecter("005", "[ReplateCameraController] Image too dark", NSError(domain: "ReplateCameraController", code: 005, userInfo: nil))
|
|
702
708
|
return
|
|
703
709
|
}
|
|
704
|
-
|
|
710
|
+
|
|
705
711
|
print("Ambient Intensity: \(ambientIntensity)")
|
|
706
712
|
print("Color Temperature: \(ambientColorTemperature)")
|
|
707
713
|
}
|
|
708
|
-
|
|
714
|
+
|
|
709
715
|
if let url = ReplateCameraController.saveImageAsJPEG(finImage) {
|
|
710
716
|
safeResolver(url.absoluteString)
|
|
711
717
|
} else {
|
|
@@ -720,15 +726,15 @@ class ReplateCameraController: NSObject {
|
|
|
720
726
|
print("Unexpected error occurred")
|
|
721
727
|
}
|
|
722
728
|
}
|
|
723
|
-
|
|
724
|
-
|
|
729
|
+
|
|
730
|
+
|
|
725
731
|
static func cgImage(from ciImage: CIImage) -> CGImage? {
|
|
726
732
|
let context = CIContext(options: nil)
|
|
727
|
-
|
|
733
|
+
|
|
728
734
|
return context.createCGImage(ciImage, from: ciImage.extent)
|
|
729
735
|
}
|
|
730
|
-
|
|
731
|
-
|
|
736
|
+
|
|
737
|
+
|
|
732
738
|
static func saveImageAsJPEG(_ image: UIImage) -> URL? {
|
|
733
739
|
// Convert UIImage to Data with JPEG representation
|
|
734
740
|
guard let imageData = image.jpegData(compressionQuality: 1.0) else {
|
|
@@ -736,22 +742,22 @@ class ReplateCameraController: NSObject {
|
|
|
736
742
|
print("Error converting UIImage to JPEG data")
|
|
737
743
|
return nil
|
|
738
744
|
}
|
|
739
|
-
|
|
745
|
+
|
|
740
746
|
// UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil)
|
|
741
|
-
|
|
747
|
+
|
|
742
748
|
// Get the temporary directory URL
|
|
743
749
|
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
|
|
744
|
-
|
|
750
|
+
|
|
745
751
|
// Create a unique filename (you can use a UUID or any other method to generate a unique name)
|
|
746
752
|
let uniqueFilename = "image_\(Date().timeIntervalSince1970).jpg"
|
|
747
|
-
|
|
753
|
+
|
|
748
754
|
// Combine the temporary directory URL with the unique filename to get the full file URL
|
|
749
755
|
let fileURL = temporaryDirectoryURL.appendingPathComponent(uniqueFilename)
|
|
750
|
-
|
|
756
|
+
|
|
751
757
|
do {
|
|
752
758
|
// Write the JPEG data to the file
|
|
753
759
|
try imageData.write(to: fileURL, options: .atomic)
|
|
754
|
-
|
|
760
|
+
|
|
755
761
|
// Print the file URL for reference
|
|
756
762
|
print("Image saved at: \(fileURL.absoluteString)")
|
|
757
763
|
return fileURL
|
|
@@ -761,7 +767,7 @@ class ReplateCameraController: NSObject {
|
|
|
761
767
|
return nil
|
|
762
768
|
}
|
|
763
769
|
}
|
|
764
|
-
|
|
770
|
+
|
|
765
771
|
func updateSpheres(deviceTargetInFocus: Int, cameraTransform: simd_float4x4, completion: @escaping (Bool) -> Void) {
|
|
766
772
|
// Ensure the function handles a single completion call
|
|
767
773
|
var completionCalled = false
|
|
@@ -773,7 +779,7 @@ class ReplateCameraController: NSObject {
|
|
|
773
779
|
print("Completion already called")
|
|
774
780
|
}
|
|
775
781
|
}
|
|
776
|
-
|
|
782
|
+
|
|
777
783
|
// When the user pinches the screen, spheres are recreated,
|
|
778
784
|
// we have to make sure all spheres have been recreated before proceeding
|
|
779
785
|
if (ReplateCameraView.spheresModels.count < 144) {
|
|
@@ -781,49 +787,49 @@ class ReplateCameraController: NSObject {
|
|
|
781
787
|
callCompletion(false)
|
|
782
788
|
return
|
|
783
789
|
}
|
|
784
|
-
|
|
790
|
+
|
|
785
791
|
guard let anchorNode = ReplateCameraView.anchorEntity else {
|
|
786
792
|
print("[updateSpheres] No anchor entity found.")
|
|
787
793
|
callCompletion(false)
|
|
788
794
|
return
|
|
789
795
|
}
|
|
790
|
-
|
|
796
|
+
|
|
791
797
|
// Get the camera's pose
|
|
792
798
|
guard let frame = ReplateCameraView.arView.session.currentFrame else {
|
|
793
799
|
print("[updateSpheres] No current frame available.")
|
|
794
800
|
callCompletion(false)
|
|
795
801
|
return
|
|
796
802
|
}
|
|
797
|
-
|
|
803
|
+
|
|
798
804
|
// Calculate the angle between the camera and the anchor
|
|
799
805
|
let angleDegrees = ReplateCameraController.angleBetweenAnchorXAndCamera(anchor: anchorNode,
|
|
800
806
|
cameraTransform: cameraTransform)
|
|
801
807
|
let sphereIndex = max(Int(round(angleDegrees / 5.0)), 0) % 72 // Ensure sphereIndex stays within 0-71 bounds
|
|
802
|
-
|
|
808
|
+
|
|
803
809
|
var mesh: ModelEntity?
|
|
804
810
|
var newAngle = false
|
|
805
811
|
var callback: RCTResponseSenderBlock? = nil
|
|
806
812
|
print("Sphere index \(sphereIndex) - Spheres length \(ReplateCameraView.spheresModels.count)")
|
|
807
|
-
|
|
813
|
+
|
|
808
814
|
if deviceTargetInFocus == 1 {
|
|
809
815
|
if sphereIndex >= ReplateCameraView.upperSpheresSet.count {
|
|
810
816
|
print("[updateSpheres] Sphere index out of range. Index: \(sphereIndex), Count: \(ReplateCameraView.upperSpheresSet.count)")
|
|
811
817
|
callCompletion(false)
|
|
812
818
|
return
|
|
813
819
|
}
|
|
814
|
-
|
|
820
|
+
|
|
815
821
|
if !ReplateCameraView.upperSpheresSet[sphereIndex] {
|
|
816
822
|
ReplateCameraView.upperSpheresSet[sphereIndex] = true
|
|
817
823
|
ReplateCameraView.photosFromDifferentAnglesTaken += 1
|
|
818
824
|
newAngle = true
|
|
819
|
-
|
|
825
|
+
|
|
820
826
|
if 72 + sphereIndex >= ReplateCameraView.spheresModels.count {
|
|
821
827
|
print("[updateSpheres] Upper spheresModels index out of range. Index: \(72 + sphereIndex), Count: \(ReplateCameraView.spheresModels.count)")
|
|
822
828
|
callCompletion(false)
|
|
823
829
|
return
|
|
824
830
|
}
|
|
825
831
|
mesh = ReplateCameraView.spheresModels[72 + sphereIndex]
|
|
826
|
-
|
|
832
|
+
|
|
827
833
|
if ReplateCameraView.upperSpheresSet.allSatisfy({ $0 }) {
|
|
828
834
|
callback = ReplateCameraController.completedUpperSpheresCallback
|
|
829
835
|
ReplateCameraController.completedUpperSpheresCallback = nil
|
|
@@ -835,26 +841,26 @@ class ReplateCameraController: NSObject {
|
|
|
835
841
|
callCompletion(false)
|
|
836
842
|
return
|
|
837
843
|
}
|
|
838
|
-
|
|
844
|
+
|
|
839
845
|
if !ReplateCameraView.lowerSpheresSet[sphereIndex] {
|
|
840
846
|
ReplateCameraView.lowerSpheresSet[sphereIndex] = true
|
|
841
847
|
ReplateCameraView.photosFromDifferentAnglesTaken += 1
|
|
842
848
|
newAngle = true
|
|
843
|
-
|
|
849
|
+
|
|
844
850
|
if sphereIndex >= ReplateCameraView.spheresModels.count {
|
|
845
851
|
print("[updateSpheres] Lower spheresModels index out of range. Index: \(sphereIndex), Count: \(ReplateCameraView.spheresModels.count)")
|
|
846
852
|
callCompletion(false)
|
|
847
853
|
return
|
|
848
854
|
}
|
|
849
855
|
mesh = ReplateCameraView.spheresModels[sphereIndex]
|
|
850
|
-
|
|
856
|
+
|
|
851
857
|
if ReplateCameraView.lowerSpheresSet.allSatisfy({ $0 }) {
|
|
852
858
|
callback = ReplateCameraController.completedLowerSpheresCallback
|
|
853
859
|
ReplateCameraController.completedLowerSpheresCallback = nil
|
|
854
860
|
}
|
|
855
861
|
}
|
|
856
862
|
}
|
|
857
|
-
|
|
863
|
+
|
|
858
864
|
DispatchQueue.main.async {
|
|
859
865
|
if let mesh = mesh {
|
|
860
866
|
let material = SimpleMaterial(color: .green, roughness: 1, isMetallic: false)
|
|
@@ -862,45 +868,45 @@ class ReplateCameraController: NSObject {
|
|
|
862
868
|
ReplateCameraView.generateImpactFeedback(strength: .light)
|
|
863
869
|
}
|
|
864
870
|
}
|
|
865
|
-
|
|
871
|
+
|
|
866
872
|
// Ensure callback execution doesn't interfere with array access
|
|
867
873
|
callback?([])
|
|
868
874
|
callCompletion(newAngle)
|
|
869
875
|
}
|
|
870
|
-
|
|
876
|
+
|
|
871
877
|
static func getTransformRelativeToAnchor(anchor: AnchorEntity, cameraTransform: simd_float4x4) -> simd_float4x4{
|
|
872
878
|
// Transform the camera position to the anchor's local space
|
|
873
879
|
let anchorTransform = anchor.transformMatrix(relativeTo: nil)
|
|
874
880
|
let relativePosition = anchorTransform.inverse * cameraTransform
|
|
875
881
|
return relativePosition
|
|
876
882
|
}
|
|
877
|
-
|
|
883
|
+
|
|
878
884
|
static func angleBetweenAnchorXAndCamera(anchor: AnchorEntity, cameraTransform: simd_float4x4) -> Float {
|
|
879
885
|
// Extract the position of the anchor and the camera from their transforms, ignoring the y-axis
|
|
880
886
|
let anchorTransform = anchor.transformMatrix(relativeTo: nil)
|
|
881
887
|
let anchorPositionXZ = simd_float2(anchor.transform.translation.x, anchor.transform.translation.z)
|
|
882
888
|
let relativeCameraPositionXZ = simd_float2(cameraTransform.columns.3.x, cameraTransform.columns.3.z)
|
|
883
|
-
|
|
889
|
+
|
|
884
890
|
// Calculate the direction vector from the anchor to the camera in the XZ plane
|
|
885
891
|
let directionXZ = relativeCameraPositionXZ - anchorPositionXZ
|
|
886
|
-
|
|
892
|
+
|
|
887
893
|
// Extract the x-axis of the anchor's transform in the XZ plane
|
|
888
894
|
let anchorXAxisXZ = simd_float2(anchorTransform.columns.0.x, anchorTransform.columns.0.z)
|
|
889
|
-
|
|
895
|
+
|
|
890
896
|
// Use atan2 to calculate the angle between the anchor's x-axis and the direction vector in the XZ plane
|
|
891
897
|
let angle = atan2(directionXZ.y, directionXZ.x) - atan2(anchorXAxisXZ.y, anchorXAxisXZ.x)
|
|
892
|
-
|
|
898
|
+
|
|
893
899
|
// Convert the angle to degrees
|
|
894
900
|
var angleDegrees = angle * (180.0 / .pi)
|
|
895
|
-
|
|
901
|
+
|
|
896
902
|
// Ensure the angle is within the range [0, 360)
|
|
897
903
|
if angleDegrees < 0 {
|
|
898
904
|
angleDegrees += 360
|
|
899
905
|
}
|
|
900
|
-
|
|
906
|
+
|
|
901
907
|
return angleDegrees
|
|
902
908
|
}
|
|
903
|
-
|
|
909
|
+
|
|
904
910
|
}
|
|
905
911
|
|
|
906
912
|
extension ARView: ARCoachingOverlayViewDelegate {
|
|
@@ -926,7 +932,7 @@ extension ARView: ARCoachingOverlayViewDelegate {
|
|
|
926
932
|
ReplateCameraController.openedTutorialCallback = nil
|
|
927
933
|
}
|
|
928
934
|
}
|
|
929
|
-
|
|
935
|
+
|
|
930
936
|
// Example callback for the delegate object
|
|
931
937
|
public func coachingOverlayViewDidDeactivate(
|
|
932
938
|
_ coachingOverlayView: ARCoachingOverlayView
|
|
@@ -949,28 +955,28 @@ extension UIImage {
|
|
|
949
955
|
guard let cgImage = self.cgImage else {
|
|
950
956
|
return nil
|
|
951
957
|
}
|
|
952
|
-
|
|
958
|
+
|
|
953
959
|
// Get width and height of the image
|
|
954
960
|
let width = cgImage.width
|
|
955
961
|
let height = cgImage.height
|
|
956
|
-
|
|
962
|
+
|
|
957
963
|
// Create a data provider from CGImage
|
|
958
964
|
guard let dataProvider = cgImage.dataProvider else {
|
|
959
965
|
return nil
|
|
960
966
|
}
|
|
961
|
-
|
|
967
|
+
|
|
962
968
|
// Access pixel data
|
|
963
969
|
guard let pixelData = dataProvider.data else {
|
|
964
970
|
return nil
|
|
965
971
|
}
|
|
966
|
-
|
|
972
|
+
|
|
967
973
|
// Create a pointer to the pixel data
|
|
968
974
|
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
|
|
969
|
-
|
|
975
|
+
|
|
970
976
|
var totalRed: CGFloat = 0
|
|
971
977
|
var totalGreen: CGFloat = 0
|
|
972
978
|
var totalBlue: CGFloat = 0
|
|
973
|
-
|
|
979
|
+
|
|
974
980
|
// Loop through each pixel and calculate sum of RGB values
|
|
975
981
|
for y in 0..<height {
|
|
976
982
|
for x in 0..<width {
|
|
@@ -978,19 +984,19 @@ extension UIImage {
|
|
|
978
984
|
let red = CGFloat(data[pixelInfo]) / 255.0
|
|
979
985
|
let green = CGFloat(data[pixelInfo + 1]) / 255.0
|
|
980
986
|
let blue = CGFloat(data[pixelInfo + 2]) / 255.0
|
|
981
|
-
|
|
987
|
+
|
|
982
988
|
totalRed += red
|
|
983
989
|
totalGreen += green
|
|
984
990
|
totalBlue += blue
|
|
985
991
|
}
|
|
986
992
|
}
|
|
987
|
-
|
|
993
|
+
|
|
988
994
|
// Calculate average RGB values
|
|
989
995
|
let count = CGFloat(width * height)
|
|
990
996
|
let averageRed = totalRed / count
|
|
991
997
|
let averageGreen = totalGreen / count
|
|
992
998
|
let averageBlue = totalBlue / count
|
|
993
|
-
|
|
999
|
+
|
|
994
1000
|
// Create and return average color
|
|
995
1001
|
return UIColor(red: averageRed, green: averageGreen, blue: averageBlue, alpha: 1.0)
|
|
996
1002
|
}
|
|
@@ -1002,12 +1008,12 @@ extension UIColor {
|
|
|
1002
1008
|
var green: CGFloat = 0
|
|
1003
1009
|
var blue: CGFloat = 0
|
|
1004
1010
|
var alpha: CGFloat = 0
|
|
1005
|
-
|
|
1011
|
+
|
|
1006
1012
|
// Check if the color can be converted to RGB
|
|
1007
1013
|
guard self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
|
|
1008
1014
|
return nil
|
|
1009
1015
|
}
|
|
1010
|
-
|
|
1016
|
+
|
|
1011
1017
|
return (red, green, blue)
|
|
1012
1018
|
}
|
|
1013
1019
|
}
|
package/lib/commonjs/index.js
CHANGED
|
@@ -12,6 +12,7 @@ exports.registerCompletedLowerSpheresCallback = registerCompletedLowerSpheresCal
|
|
|
12
12
|
exports.registerCompletedTutorialCallback = registerCompletedTutorialCallback;
|
|
13
13
|
exports.registerCompletedUpperSpheresCallback = registerCompletedUpperSpheresCallback;
|
|
14
14
|
exports.registerOpenedTutorialCallback = registerOpenedTutorialCallback;
|
|
15
|
+
exports.reset = reset;
|
|
15
16
|
exports.takePhoto = takePhoto;
|
|
16
17
|
var _reactNative = require("react-native");
|
|
17
18
|
const LINKING_ERROR = `The package 'replate-camera' doesn't seem to be linked. Make sure: \n\n` + _reactNative.Platform.select({
|
|
@@ -54,4 +55,7 @@ function registerCompletedLowerSpheresCallback(callback) {
|
|
|
54
55
|
function registerOpenedTutorialCallback(callback) {
|
|
55
56
|
ReplateCameraModule.registerOpenedTutorialCallback(callback);
|
|
56
57
|
}
|
|
58
|
+
function reset() {
|
|
59
|
+
ReplateCameraModule.reset();
|
|
60
|
+
}
|
|
57
61
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +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","unlimited","getPhotosCount","getRemainingAnglesToScan","isScanComplete","registerCompletedTutorialCallback","callback","registerAnchorSetCallback","registerCompletedUpperSpheresCallback","registerCompletedLowerSpheresCallback","registerOpenedTutorialCallback"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":"
|
|
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","unlimited","getPhotosCount","getRemainingAnglesToScan","isScanComplete","registerCompletedTutorialCallback","callback","registerAnchorSetCallback","registerCompletedUpperSpheresCallback","registerCompletedLowerSpheresCallback","registerOpenedTutorialCallback","reset"],"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;AAEA,MAAMY,mBAAmB,GAAAL,OAAA,CAAAK,mBAAA,GAAGC,0BAAa,CAACC,uBAAuB,GACpED,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,CAACC,SAAkB,EAAmB;EAC7D,OAAON,mBAAmB,CAACK,SAAS,CAACC,SAAS,CAAC;AACjD;AAEO,SAASC,cAAcA,CAAA,EAAoB;EAChD,OAAOP,mBAAmB,CAACO,cAAc,CAAC,CAAC;AAC7C;AAEO,SAASC,wBAAwBA,CAAA,EAAoB;EAC1D,OAAOR,mBAAmB,CAACQ,wBAAwB,CAAC,CAAC;AACvD;AAEO,SAASC,cAAcA,CAAA,EAAqB;EACjD,OAAOT,mBAAmB,CAACS,cAAc,CAAC,CAAC;AAC7C;AAEO,SAASC,iCAAiCA,CAACC,QAAoB,EAAE;EACtEX,mBAAmB,CAACU,iCAAiC,CAACC,QAAQ,CAAC;AACjE;AAEO,SAASC,yBAAyBA,CAACD,QAAoB,EAAE;EAC9DX,mBAAmB,CAACY,yBAAyB,CAACD,QAAQ,CAAC;AACzD;AAEO,SAASE,qCAAqCA,CAACF,QAAoB,EAAE;EAC1EX,mBAAmB,CAACa,qCAAqC,CAACF,QAAQ,CAAC;AACrE;AAEO,SAASG,qCAAqCA,CAACH,QAAoB,EAAE;EAC1EX,mBAAmB,CAACc,qCAAqC,CAACH,QAAQ,CAAC;AACrE;AAEO,SAASI,8BAA8BA,CAACJ,QAAoB,EAAE;EACnEX,mBAAmB,CAACe,8BAA8B,CAACJ,QAAQ,CAAC;AAC9D;AAEO,SAASK,KAAKA,CAAA,EAAG;EACtBhB,mBAAmB,CAACgB,KAAK,CAAC,CAAC;AAC7B","ignoreList":[]}
|
package/lib/module/index.js
CHANGED
|
@@ -39,4 +39,7 @@ export function registerCompletedLowerSpheresCallback(callback) {
|
|
|
39
39
|
export function registerOpenedTutorialCallback(callback) {
|
|
40
40
|
ReplateCameraModule.registerOpenedTutorialCallback(callback);
|
|
41
41
|
}
|
|
42
|
+
export function reset() {
|
|
43
|
+
ReplateCameraModule.reset();
|
|
44
|
+
}
|
|
42
45
|
//# sourceMappingURL=index.js.map
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["requireNativeComponent","UIManager","Platform","NativeModules","LINKING_ERROR","select","ios","default","ComponentName","ReplateCameraView","getViewManagerConfig","Error","ReplateCameraModule","ReplateCameraController","Proxy","get","takePhoto","unlimited","getPhotosCount","getRemainingAnglesToScan","isScanComplete","registerCompletedTutorialCallback","callback","registerAnchorSetCallback","registerCompletedUpperSpheresCallback","registerCompletedLowerSpheresCallback","registerOpenedTutorialCallback"],"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,OAAO,MAAMQ,mBAAmB,GAAGT,aAAa,CAACU,uBAAuB,GACpEV,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,CAACC,SAAkB,EAAmB;EAC7D,OAAOL,mBAAmB,CAACI,SAAS,CAACC,SAAS,CAAC;AACjD;AAEA,OAAO,SAASC,cAAcA,CAAA,EAAoB;EAChD,OAAON,mBAAmB,CAACM,cAAc,CAAC,CAAC;AAC7C;AAEA,OAAO,SAASC,wBAAwBA,CAAA,EAAoB;EAC1D,OAAOP,mBAAmB,CAACO,wBAAwB,CAAC,CAAC;AACvD;AAEA,OAAO,SAASC,cAAcA,CAAA,EAAqB;EACjD,OAAOR,mBAAmB,CAACQ,cAAc,CAAC,CAAC;AAC7C;AAEA,OAAO,SAASC,iCAAiCA,CAACC,QAAoB,EAAE;EACtEV,mBAAmB,CAACS,iCAAiC,CAACC,QAAQ,CAAC;AACjE;AAEA,OAAO,SAASC,yBAAyBA,CAACD,QAAoB,EAAE;EAC9DV,mBAAmB,CAACW,yBAAyB,CAACD,QAAQ,CAAC;AACzD;AAEA,OAAO,SAASE,qCAAqCA,CAACF,QAAoB,EAAE;EAC1EV,mBAAmB,CAACY,qCAAqC,CAACF,QAAQ,CAAC;AACrE;AAEA,OAAO,SAASG,qCAAqCA,CAACH,QAAoB,EAAE;EAC1EV,mBAAmB,CAACa,qCAAqC,CAACH,QAAQ,CAAC;AACrE;AAEA,OAAO,SAASI,8BAA8BA,CAACJ,QAAoB,EAAE;EACnEV,mBAAmB,CAACc,8BAA8B,CAACJ,QAAQ,CAAC;AAC9D","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["requireNativeComponent","UIManager","Platform","NativeModules","LINKING_ERROR","select","ios","default","ComponentName","ReplateCameraView","getViewManagerConfig","Error","ReplateCameraModule","ReplateCameraController","Proxy","get","takePhoto","unlimited","getPhotosCount","getRemainingAnglesToScan","isScanComplete","registerCompletedTutorialCallback","callback","registerAnchorSetCallback","registerCompletedUpperSpheresCallback","registerCompletedLowerSpheresCallback","registerOpenedTutorialCallback","reset"],"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,OAAO,MAAMQ,mBAAmB,GAAGT,aAAa,CAACU,uBAAuB,GACpEV,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,CAACC,SAAkB,EAAmB;EAC7D,OAAOL,mBAAmB,CAACI,SAAS,CAACC,SAAS,CAAC;AACjD;AAEA,OAAO,SAASC,cAAcA,CAAA,EAAoB;EAChD,OAAON,mBAAmB,CAACM,cAAc,CAAC,CAAC;AAC7C;AAEA,OAAO,SAASC,wBAAwBA,CAAA,EAAoB;EAC1D,OAAOP,mBAAmB,CAACO,wBAAwB,CAAC,CAAC;AACvD;AAEA,OAAO,SAASC,cAAcA,CAAA,EAAqB;EACjD,OAAOR,mBAAmB,CAACQ,cAAc,CAAC,CAAC;AAC7C;AAEA,OAAO,SAASC,iCAAiCA,CAACC,QAAoB,EAAE;EACtEV,mBAAmB,CAACS,iCAAiC,CAACC,QAAQ,CAAC;AACjE;AAEA,OAAO,SAASC,yBAAyBA,CAACD,QAAoB,EAAE;EAC9DV,mBAAmB,CAACW,yBAAyB,CAACD,QAAQ,CAAC;AACzD;AAEA,OAAO,SAASE,qCAAqCA,CAACF,QAAoB,EAAE;EAC1EV,mBAAmB,CAACY,qCAAqC,CAACF,QAAQ,CAAC;AACrE;AAEA,OAAO,SAASG,qCAAqCA,CAACH,QAAoB,EAAE;EAC1EV,mBAAmB,CAACa,qCAAqC,CAACH,QAAQ,CAAC;AACrE;AAEA,OAAO,SAASI,8BAA8BA,CAACJ,QAAoB,EAAE;EACnEV,mBAAmB,CAACc,8BAA8B,CAACJ,QAAQ,CAAC;AAC9D;AAEA,OAAO,SAASK,KAAKA,CAAA,EAAG;EACtBf,mBAAmB,CAACe,KAAK,CAAC,CAAC;AAC7B","ignoreList":[]}
|
|
@@ -14,5 +14,6 @@ export declare function registerAnchorSetCallback(callback: () => void): void;
|
|
|
14
14
|
export declare function registerCompletedUpperSpheresCallback(callback: () => void): void;
|
|
15
15
|
export declare function registerCompletedLowerSpheresCallback(callback: () => void): void;
|
|
16
16
|
export declare function registerOpenedTutorialCallback(callback: () => void): void;
|
|
17
|
+
export declare function reset(): void;
|
|
17
18
|
export {};
|
|
18
19
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +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;AAER,eAAO,MAAM,mBAAmB,KAS3B,CAAC;AAEN,wBAAgB,SAAS,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7D;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhD;AAED,wBAAgB,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC,CAE1D;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAEjD;AAED,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,IAAI,QAErE;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,IAAI,QAE7D;AAED,wBAAgB,qCAAqC,CAAC,QAAQ,EAAE,MAAM,IAAI,QAEzE;AAED,wBAAgB,qCAAqC,CAAC,QAAQ,EAAE,MAAM,IAAI,QAEzE;AAED,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,IAAI,QAElE"}
|
|
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;AAER,eAAO,MAAM,mBAAmB,KAS3B,CAAC;AAEN,wBAAgB,SAAS,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7D;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhD;AAED,wBAAgB,wBAAwB,IAAI,OAAO,CAAC,MAAM,CAAC,CAE1D;AAED,wBAAgB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAEjD;AAED,wBAAgB,iCAAiC,CAAC,QAAQ,EAAE,MAAM,IAAI,QAErE;AAED,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,IAAI,QAE7D;AAED,wBAAgB,qCAAqC,CAAC,QAAQ,EAAE,MAAM,IAAI,QAEzE;AAED,wBAAgB,qCAAqC,CAAC,QAAQ,EAAE,MAAM,IAAI,QAEzE;AAED,wBAAgB,8BAA8B,CAAC,QAAQ,EAAE,MAAM,IAAI,QAElE;AAED,wBAAgB,KAAK,SAEpB"}
|
package/package.json
CHANGED
package/src/index.tsx
CHANGED
|
@@ -73,3 +73,7 @@ export function registerCompletedLowerSpheresCallback(callback: () => void) {
|
|
|
73
73
|
export function registerOpenedTutorialCallback(callback: () => void) {
|
|
74
74
|
ReplateCameraModule.registerOpenedTutorialCallback(callback);
|
|
75
75
|
}
|
|
76
|
+
|
|
77
|
+
export function reset() {
|
|
78
|
+
ReplateCameraModule.reset();
|
|
79
|
+
}
|