replate-camera 0.1.7 → 0.1.8
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.swift +116 -17
- package/package.json +1 -1
|
@@ -274,17 +274,17 @@ class ReplateCameraController: RCTEventEmitter {
|
|
|
274
274
|
|
|
275
275
|
//DEVICE ORIENTATION
|
|
276
276
|
guard let anchorNode = ReplateCameraView.anchorEntity else {
|
|
277
|
-
rejecter("[ReplateCameraController]", "
|
|
277
|
+
rejecter("[ReplateCameraController]", "No anchor set yet", NSError(domain: "ReplateCameraController", code: 001, userInfo: nil));
|
|
278
278
|
return
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
// Assuming you have two points
|
|
282
|
-
let point1 = SIMD3<Float>(anchorNode.position.x,
|
|
283
|
-
anchorNode.position.y,
|
|
284
|
-
anchorNode.position.z)
|
|
285
|
-
let point2 = SIMD3<Float>(anchorNode.position.x,
|
|
286
|
-
anchorNode.position.y + 0.3,
|
|
287
|
-
anchorNode.position.z)
|
|
282
|
+
let point1 = SIMD3<Float>(anchorNode.position(relativeTo: nil).x,
|
|
283
|
+
anchorNode.position(relativeTo: nil).y,
|
|
284
|
+
anchorNode.position(relativeTo: nil).z)
|
|
285
|
+
let point2 = SIMD3<Float>(anchorNode.position(relativeTo: nil).x,
|
|
286
|
+
anchorNode.position(relativeTo: nil).y + 0.3,
|
|
287
|
+
anchorNode.position(relativeTo: nil).z)
|
|
288
288
|
|
|
289
289
|
// Function to calculate the angle between two vectors
|
|
290
290
|
func angleBetweenVectors(_ vector1: SIMD3<Float>, _ vector2: SIMD3<Float>) -> Float {
|
|
@@ -293,22 +293,33 @@ class ReplateCameraController: RCTEventEmitter {
|
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
// Threshold angle for considering if the device is pointing towards a point
|
|
296
|
-
let thresholdAngle: Float = 0.3 // Adjust this threshold as needed
|
|
297
296
|
var deviceTargetInFocus = -1
|
|
298
297
|
// Check if the device is pointing towards one of the two points
|
|
299
298
|
if let cameraTransform = ReplateCameraView.arView.session.currentFrame?.camera.transform {
|
|
300
299
|
let deviceDirection = SIMD3<Float>(-cameraTransform.columns.2.x, -cameraTransform.columns.2.y, -cameraTransform.columns.2.z)
|
|
301
300
|
|
|
302
301
|
let cameraPosition = SIMD3<Float>(cameraTransform.columns.3.x, cameraTransform.columns.3.y, cameraTransform.columns.3.z)
|
|
303
|
-
|
|
304
302
|
let directionToFirstPoint = normalize(point1 - cameraPosition)
|
|
305
303
|
let directionToSecondPoint = normalize(point2 - cameraPosition)
|
|
306
304
|
|
|
305
|
+
let point1Distance = distance(point1, cameraPosition)
|
|
306
|
+
let point2Distance = distance(point2, cameraPosition)
|
|
307
|
+
let averageDistance = (point1Distance + point2Distance) / 2.0
|
|
308
|
+
|
|
309
|
+
let baseThreshold: Float = 0.6 // adjust as needed
|
|
310
|
+
let distanceFactor: Float = 0.2 // adjust as needed
|
|
311
|
+
|
|
312
|
+
let dynamicThreshold = baseThreshold + distanceFactor * sqrt(averageDistance)
|
|
313
|
+
|
|
314
|
+
|
|
307
315
|
let angleToFirstPoint = angleBetweenVectors(deviceDirection, directionToFirstPoint)
|
|
308
316
|
let angleToSecondPoint = angleBetweenVectors(deviceDirection, directionToSecondPoint)
|
|
309
|
-
print("Camera
|
|
310
|
-
|
|
311
|
-
|
|
317
|
+
print("Camera: \(cameraPosition)")
|
|
318
|
+
print("Point 1 position: \(point1) Point 2 position: \(point2)")
|
|
319
|
+
print("Angle to first: ", angleToFirstPoint, " Angle to second: ", angleToSecondPoint)
|
|
320
|
+
print("Threshold \(dynamicThreshold)")
|
|
321
|
+
let isPointingAtFirstPoint = angleToFirstPoint < dynamicThreshold && cameraPosition.y < anchorNode.position.y + 0.20
|
|
322
|
+
let isPointingAtSecondPoint = angleToSecondPoint < dynamicThreshold && cameraPosition.y >= anchorNode.position.y + 0.20
|
|
312
323
|
if (isPointingAtFirstPoint) {
|
|
313
324
|
deviceTargetInFocus = 0
|
|
314
325
|
}else if(isPointingAtSecondPoint){
|
|
@@ -332,6 +343,18 @@ class ReplateCameraController: RCTEventEmitter {
|
|
|
332
343
|
let uiImage = UIImage(cgImage: cgImage)
|
|
333
344
|
let finImage = uiImage.rotate(radians: .pi/2) // Adjust radians as needed
|
|
334
345
|
|
|
346
|
+
guard let components = finImage.averageColor()?.getRGBComponents()
|
|
347
|
+
else {
|
|
348
|
+
rejecter("[ReplateCameraController]", "Cannot get color components", NSError(domain: "ReplateCameraController", code: 003, userInfo: nil))
|
|
349
|
+
return
|
|
350
|
+
}
|
|
351
|
+
let averagePixelColor = components.red + components.blue + components.green / 3
|
|
352
|
+
print("Average pixel color: \(averagePixelColor)")
|
|
353
|
+
if ((components.red + components.blue + components.green) / 3 < 0.15){
|
|
354
|
+
rejecter("[ReplateCameraController]", "Image too dark", NSError(domain: "ReplateCameraController", code: 004, userInfo: nil))
|
|
355
|
+
return
|
|
356
|
+
}
|
|
357
|
+
|
|
335
358
|
print("Saving photo")
|
|
336
359
|
if let url = ReplateCameraController.saveImageAsJPEG(finImage) {
|
|
337
360
|
resolver(url.absoluteString)
|
|
@@ -396,6 +419,11 @@ class ReplateCameraController: RCTEventEmitter {
|
|
|
396
419
|
self.sendEvent(withName: "arTutorialCompleted", body: true)
|
|
397
420
|
}
|
|
398
421
|
|
|
422
|
+
@objc
|
|
423
|
+
override func supportedEvents() -> [String]! {
|
|
424
|
+
return ["arTutorialCompleted"]
|
|
425
|
+
}
|
|
426
|
+
|
|
399
427
|
|
|
400
428
|
func updateSpheres(deviceTargetInFocus: Int) {
|
|
401
429
|
guard let anchorNode = ReplateCameraView.anchorEntity else { return }
|
|
@@ -405,9 +433,9 @@ class ReplateCameraController: RCTEventEmitter {
|
|
|
405
433
|
let cameraTransform = frame.camera.transform
|
|
406
434
|
|
|
407
435
|
// Calculate the angle between the camera and the anchor
|
|
408
|
-
let anchorPosition = SCNVector3(anchorNode.position.x,
|
|
409
|
-
anchorNode.position.y,
|
|
410
|
-
anchorNode.position.z)
|
|
436
|
+
let anchorPosition = SCNVector3(anchorNode.position(relativeTo: nil).x,
|
|
437
|
+
anchorNode.position(relativeTo: nil).y,
|
|
438
|
+
anchorNode.position(relativeTo: nil).z)
|
|
411
439
|
let cameraPosition = SCNVector3(cameraTransform.columns.3.x,
|
|
412
440
|
cameraTransform.columns.3.y,
|
|
413
441
|
cameraTransform.columns.3.z)
|
|
@@ -436,9 +464,9 @@ class ReplateCameraController: RCTEventEmitter {
|
|
|
436
464
|
}
|
|
437
465
|
}
|
|
438
466
|
|
|
439
|
-
func calculateAngle(_
|
|
467
|
+
func calculateAngle(_ camera: SCNVector3, _ anchor: SCNVector3) -> Float {
|
|
440
468
|
// Calculate the angle in 2D plane (x-z plane) using atan2
|
|
441
|
-
let angle = atan2(
|
|
469
|
+
let angle = atan2(camera.z - anchor.z, camera.x - anchor.x)
|
|
442
470
|
|
|
443
471
|
// Convert from radians to degrees
|
|
444
472
|
var angleInDegrees = GLKMathRadiansToDegrees(Float(angle))
|
|
@@ -448,6 +476,14 @@ class ReplateCameraController: RCTEventEmitter {
|
|
|
448
476
|
angleInDegrees += 360
|
|
449
477
|
}
|
|
450
478
|
|
|
479
|
+
// Rotate by 2.5 degrees to consider sphere-center, not sphere-begin
|
|
480
|
+
angleInDegrees += 2.5
|
|
481
|
+
|
|
482
|
+
// If rotating resulted in angle > 360 degrees, subtract 360
|
|
483
|
+
if angleInDegrees >= 360 {
|
|
484
|
+
angleInDegrees -= 360
|
|
485
|
+
}
|
|
486
|
+
|
|
451
487
|
return angleInDegrees
|
|
452
488
|
}
|
|
453
489
|
|
|
@@ -491,3 +527,66 @@ extension ARView: ARCoachingOverlayViewDelegate {
|
|
|
491
527
|
print("CRASHED")
|
|
492
528
|
}
|
|
493
529
|
}
|
|
530
|
+
|
|
531
|
+
extension UIImage {
|
|
532
|
+
func averageColor() -> UIColor? {
|
|
533
|
+
// Convert UIImage to CGImage
|
|
534
|
+
guard let cgImage = self.cgImage else { return nil }
|
|
535
|
+
|
|
536
|
+
// Get width and height of the image
|
|
537
|
+
let width = cgImage.width
|
|
538
|
+
let height = cgImage.height
|
|
539
|
+
|
|
540
|
+
// Create a data provider from CGImage
|
|
541
|
+
guard let dataProvider = cgImage.dataProvider else { return nil }
|
|
542
|
+
|
|
543
|
+
// Access pixel data
|
|
544
|
+
guard let pixelData = dataProvider.data else { return nil }
|
|
545
|
+
|
|
546
|
+
// Create a pointer to the pixel data
|
|
547
|
+
let data: UnsafePointer<UInt8> = CFDataGetBytePtr(pixelData)
|
|
548
|
+
|
|
549
|
+
var totalRed: CGFloat = 0
|
|
550
|
+
var totalGreen: CGFloat = 0
|
|
551
|
+
var totalBlue: CGFloat = 0
|
|
552
|
+
|
|
553
|
+
// Loop through each pixel and calculate sum of RGB values
|
|
554
|
+
for y in 0..<height {
|
|
555
|
+
for x in 0..<width {
|
|
556
|
+
let pixelInfo: Int = ((width * y) + x) * 4
|
|
557
|
+
let red = CGFloat(data[pixelInfo]) / 255.0
|
|
558
|
+
let green = CGFloat(data[pixelInfo + 1]) / 255.0
|
|
559
|
+
let blue = CGFloat(data[pixelInfo + 2]) / 255.0
|
|
560
|
+
|
|
561
|
+
totalRed += red
|
|
562
|
+
totalGreen += green
|
|
563
|
+
totalBlue += blue
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// Calculate average RGB values
|
|
568
|
+
let count = CGFloat(width * height)
|
|
569
|
+
let averageRed = totalRed / count
|
|
570
|
+
let averageGreen = totalGreen / count
|
|
571
|
+
let averageBlue = totalBlue / count
|
|
572
|
+
|
|
573
|
+
// Create and return average color
|
|
574
|
+
return UIColor(red: averageRed, green: averageGreen, blue: averageBlue, alpha: 1.0)
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
extension UIColor {
|
|
579
|
+
func getRGBComponents() -> (red: CGFloat, green: CGFloat, blue: CGFloat)? {
|
|
580
|
+
var red: CGFloat = 0
|
|
581
|
+
var green: CGFloat = 0
|
|
582
|
+
var blue: CGFloat = 0
|
|
583
|
+
var alpha: CGFloat = 0
|
|
584
|
+
|
|
585
|
+
// Check if the color can be converted to RGB
|
|
586
|
+
guard self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
|
|
587
|
+
return nil
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
return (red, green, blue)
|
|
591
|
+
}
|
|
592
|
+
}
|