Как рассчитать расстояние от точки 2 до точки 3 и от 3 до 4, используя ARKit? - PullRequest
1 голос
/ 24 апреля 2019

Я делаю приложение для расчета расстояния и площади, теперь проблема в том, что я создал массив и добавляю туда свои узлы.

func calculate () {
    let start = dotNodes[0]
    let end = dotNodes[1]

    let a = end.position.x - start.position.x
    let b = end.position.y - start.position.y
    let c = end.position.z - start.position.z

    let distance =  sqrt(pow(a,2) + pow(b,2) + pow(c, 2))

    updateText(text:"\(abs( distance))", atPosition: (end.position))
}

Теперь начальной точкой является индекс 0, а конечной является индекс 1, но это только две точки. Как я могу рассчитать расстояние от 2 до 3 и от 3 до 4 и так далее, и в конце, когда последняя точка касается точки 1, она должна дать мне площадь?

Ответы [ 2 ]

1 голос
/ 27 апреля 2019

Как сказал @Maxim, вы можете начать с упрощения своих расчетов ^ ______ ^.

Однако я попытаюсь ответить на ваш вопрос, используя методы GLK Math Helper, которые, если вам интересно, вы можете прочитать больше об этом здесь: Документация GLK .

ВСуть в том, что вам нужно сделать, это выполнить итерацию массива позиций и вычислить расстояние между ними в сегментах по 2. Когда ваша последняя итерация имеет только один элемент, вы должны рассчитать позицию между этим и первым.

Поскольку я не очень хорошо разбираюсь в математике, я быстро выполнил поиск в StackOverflow, чтобы найти решение, и воспользовался ответом, предоставленным @Gasim в сообщении Выполнить итерацию по двум коллекциям за один раз.Свифт .

Поскольку моя попытка довольно продолжительна, вместо того, чтобы проходить каждую часть пошагово, я предоставил ответ, который полностью прокомментирован, и надежда укажет вам правильное направление.

Как всегда, если кто-то другой может помочь в рефакторинге или улучшении кода, пожалуйста, не стесняйтесь:

//
//  ViewController.swift
//  Measuring Example
//
//  Created By Josh Robbins (∩`-´)⊃━☆゚.*・。゚* on 27/04/2019.
//  Copyright © 2019 BlackMirrorz. All rights reserved.
//

import UIKit
import ARKit

class ViewController: UIViewController {

  @IBOutlet weak var augmentedRealityView: ARSCNView!
  var augmentedRealityConfiguration = ARWorldTrackingConfiguration()
  var augmentedRealitySession = ARSession()

  var markerNodes = [SCNNode]()
  typealias NodeNameData = (name: String, node: SCNNode)
  typealias DistanceData = (distance: Float, positionA: GLKVector3, positionB: GLKVector3)

  //---------------------
  //MARK:- Initialization
  //---------------------

  override func viewDidLoad() {

    super.viewDidLoad()
    setupARSession()

  }

  /// Sets Up Our ARSession
  func setupARSession(){

    augmentedRealityView.session = augmentedRealitySession
    augmentedRealitySession.run(augmentedRealityConfiguration, options: [.removeExistingAnchors, .resetTracking])

  }

  /// Creates A Node To Mark The Touch Position In The Scene
  ///
  /// - Returns: SCNNode
  func markerNode() -> SCNNode{

    let node = SCNNode(geometry: SCNSphere(radius: 0.01))
    node.geometry?.firstMaterial?.diffuse.contents = UIColor.cyan
    return node

  }

  //------------------------
  //MARK:- Marker Placemenet
  //------------------------

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {

    //1. Get The Users Current Touch Point & Check We Have A Valid HitTest Result
    guard let touchPoint = touches.first?.location(in: self.augmentedRealityView),
          let hitTest = self.augmentedRealityView.hitTest(touchPoint, types: .featurePoint).first
    else { return }

    //2. Get The World Transorm & Create An SCNNode At The Converted Touch Position
    let transform = hitTest.worldTransform
    let node = markerNode()
    node.position = SCNVector3(transform.columns.3.x, transform.columns.3.y, transform.columns.3.z)
    self.augmentedRealityView.scene.rootNode.addChildNode(node)

    //3. Add The Node To Our Markers Array So We Can Calculate The Distance Later
    markerNodes.append(node)

    //4. If We Have 5 Marker Nodes Then Calculate The Distances Between Them & Join Them Together
    if markerNodes.count == 5{
      calculateMarkerNodeDistances()
      markerNodes.removeAll()
    }

  }

  //-------------------
  //MARK:- Calculations
  //-------------------

  /// Enemurates Our Marker Nodes & Creates A Joining Node Between Them
  func calculateMarkerNodeDistances(){

    var index = 0;

    while index < markerNodes.count {

      let nodeA = markerNodes[index];
      var nodeB : SCNNode? = nil;

      if index + 1 < markerNodes.count {
         nodeB = markerNodes[index+1];
      }

      //1. Create A Joining Node Between The Two Nodes And Calculate The Distance
      if let lastNode = nodeB{
        let nodeA = NodeNameData("Node \(index)", nodeA)
        let nodeB = NodeNameData("Node \(index+1)", lastNode)
        self.augmentedRealityView.scene.rootNode.addChildNode(joiningNode(between: [nodeA, nodeB]))

      }else{

        //2. Here We Can Assume The We Have Reached The Last Node So We Calculate The Distance Between The 1st & Last Nodes
        guard let initialNode = markerNodes.first, let lastNode = markerNodes.last else { return }
        let nodeA = NodeNameData("Node 0 ", initialNode)
        let nodeB = NodeNameData("Node \(markerNodes.count)", lastNode)
        self.augmentedRealityView.scene.rootNode.addChildNode(joiningNode(between: [nodeA, nodeB]))
      }

      //Increment By 1 So We Join The Nodes Together In The Correct Sequence e.g. (1, 2), (3, 4) And Not (1, 2), (3, 4)
      index += 1;
    }

  }


  /// Creates A Joining Node Between Two Names
  ///
  /// - Parameter nodes: [NodeNameData]
  /// - Returns: MeasuringLineNode
  func joiningNode(between nodes: [NodeNameData]) -> MeasuringLineNode{

    let distance = calculateDistanceBetweenNodes([nodes[0], nodes[1]])
    let joiner = MeasuringLineNode(startingVector: distance.positionA, endingVector: distance.positionB)
    return joiner

  }

  /// Calculates The Distance Between Two SCNNodes
  ///
  /// - Parameter nodes: [NodeNameData]
  /// - Returns: DistanceData
  func calculateDistanceBetweenNodes(_ nodes: [NodeNameData]) -> DistanceData{

    //1. Calculate The Distance
    let positionA = GLKVectorThreeFrom(nodes[0].node.position)
    let positionB = GLKVectorThreeFrom(nodes[1].node.position)
    let distance = GLKVector3Distance(positionA, positionB)
    let meters = Measurement(value: Double(distance), unit: UnitLength.meters)
    print("Distance Between Markers [ \(nodes[0].name) & \(nodes[1].name) ]  = \(String(format: "%.2f", meters.value))m")

    //2. Return The Distance A Positions Of The Nodes
    return (distance, positionA, positionB)

  }

  /// Creates A GLKVector3 From An SCNVectore3
  ///
  /// - Parameter vector3: SCNVector3
  /// - Returns: GLKVector3
  func GLKVectorThreeFrom(_ vector3: SCNVector3) -> GLKVector3 { return GLKVector3Make(vector3.x, vector3.y, vector3.z) }

}

//-------------------------
//MARK:- Mesuring Line Node
//-------------------------

class MeasuringLineNode: SCNNode{

  /// Creates A Line Between Two SCNNodes
  ///
  /// - Parameters:
  ///   - vectorA: GLKVector3
  ///   - vectorB: GLKVector3
  init(startingVector vectorA: GLKVector3, endingVector vectorB: GLKVector3) {

    super.init()

    let height = CGFloat(GLKVector3Distance(vectorA, vectorB))

    self.position = SCNVector3(vectorA.x, vectorA.y, vectorA.z)

    let nodeVectorTwo = SCNNode()
    nodeVectorTwo.position = SCNVector3(vectorB.x, vectorB.y, vectorB.z)

    let nodeZAlign = SCNNode()
    nodeZAlign.eulerAngles.x = Float.pi/2

    let box = SCNBox(width: 0.001, height: height, length: 0.001, chamferRadius: 0)
    let material = SCNMaterial()
    material.diffuse.contents = UIColor.white
    box.materials = [material]

    let nodeLine = SCNNode(geometry: box)
    nodeLine.position.y = Float(-height/2)
    nodeZAlign.addChildNode(nodeLine)

    self.addChildNode(nodeZAlign)

    self.constraints = [SCNLookAtConstraint(target: nodeVectorTwo)]
  }

  required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) }

}

Исходя из этого простого (и, надеюсь, точного ответа), результат был примерно таким:

Distance Between Markers [ Node 0 & Node 1 ]  = 0.14m
Distance Between Markers [ Node 1 & Node 2 ]  = 0.09m
Distance Between Markers [ Node 2 & Node 3 ]  = 0.09m
Distance Between Markers [ Node 3 & Node 4 ]  = 0.05m
Distance Between Markers [ Node 0  & Node 5 ]  = 0.36m

В моем примере я вычисляю расстояния пяти узлов, но вы можете назвать это любой точкой.И, конечно, вам нужно будет использовать формулу для расчета самой площади.Однако этого должно быть более чем достаточно, чтобы указать вам правильное направление.

Надеюсь, это поможет ...

1 голос
/ 25 апреля 2019

Лучшим (а также и самым простым) способом является использование SIMD - https://developer.apple.com/documentation/accelerate/simd/working_with_vectors

let dist = simd_distance(start, end)

где векторы, вероятно, следует переопределить как simd_float3 (или SIMD3<Float>, если вы используете Swift 5).

P.S. Сначала вам нужно импортировать simd framework.

...