Запустив демо-приложение ARkit, мой новый добавленный объект поворачивался в случайном направлении, когда два пальца просто надели на экран

Я играю с демо-приложением ARkit (с чашкой, свечой, стулом и вазой), я создаю это приложение в бета-версии Xcode10.

Когда я пытаюсь повернуть объект жестом двумя пальцами, когда я помещаю два пальца на экран, объект просто внезапно поворачивается в случайном направлении, это ошибка? И как это исправить?

// MARK: - Properties

var firstTouch = UITouch()
var secondTouch = UITouch()

let translationThreshold: CGFloat = 40
let translationThresholdHarder: CGFloat = 70
var translationThresholdPassed = false
var allowTranslation = false
var dragOffset = CGPoint()
var initialMidPoint = CGPoint(x: 0, y: 0)

let rotationThreshold: Float = .pi / 15 // (12°)
let rotationThresholdHarder: Float = .pi / 10 // (18°)
var rotationThresholdPassed = false
var allowRotation = false
var initialFingerAngle: Float = 0
var initialObjectAngle: Float = 0
var firstTouchedObject: VirtualObject?

let scaleThreshold: CGFloat = 50
let scaleThresholdHarder: CGFloat = 90
var scaleThresholdPassed = false

var initialDistanceBetweenFingers: CGFloat = 0
var baseDistanceBetweenFingers: CGFloat = 0
var objectBaseScale: Float = 1.0

// MARK: - Initialization

override init(_ touches: Set<UITouch>, _ sceneView: ARSCNView, _ lastUsedObject: VirtualObject?, _ objectManager: VirtualObjectManager) {
    super.init(touches, sceneView, lastUsedObject, objectManager)
    let touches = Array(touches)
    firstTouch = touches[0]
    secondTouch = touches[1]

    let firstTouchPoint = firstTouch.location(in: sceneView)
    let secondTouchPoint = secondTouch.location(in: sceneView)
    initialMidPoint = firstTouchPoint.midpoint(secondTouchPoint)

    // Compute the two other corners of the rectangle defined by the two fingers
    let thirdCorner = CGPoint(x: firstTouchPoint.x, y: secondTouchPoint.y)
    let fourthCorner = CGPoint(x: secondTouchPoint.x, y: firstTouchPoint.y)

    // Compute all midpoints between the corners and center of the rectangle.
    let midPoints = [
        thirdCorner.midpoint(firstTouchPoint),
        thirdCorner.midpoint(secondTouchPoint),
        fourthCorner.midpoint(firstTouchPoint),
        fourthCorner.midpoint(secondTouchPoint),
        initialMidPoint.midpoint(firstTouchPoint),
        initialMidPoint.midpoint(secondTouchPoint),
        initialMidPoint.midpoint(thirdCorner),
        initialMidPoint.midpoint(fourthCorner)
    ]

    // Check if any of the two fingers or their midpoint is touching the object.
    // Based on that, translation, rotation and scale will be enabled or disabled.
    let allPoints = [firstTouchPoint, secondTouchPoint, thirdCorner, fourthCorner, initialMidPoint] + midPoints
    firstTouchedObject = allPoints.lazy.compactMap { point in
        return self.virtualObject(at: point)
    }.first
    if let virtualObject = firstTouchedObject {
        objectBaseScale = virtualObject.scale.x

        allowTranslation = true
        allowRotation = true

        initialDistanceBetweenFingers = (firstTouchPoint - secondTouchPoint).length()

        initialFingerAngle = atan2(Float(initialMidPoint.x), Float(initialMidPoint.y))
        initialObjectAngle = virtualObject.eulerAngles.y
    } else {
        allowTranslation = false
        allowRotation = false
    }
}

// MARK: - Gesture Handling

override func updateGesture() {
    super.updateGesture()

    guard let virtualObject = firstTouchedObject else {
        return
    }

    // Two finger touch enables combined translation, rotation and scale.

    // First: Update the touches.
    let touches = Array(currentTouches)
    let newTouch1 = touches[0]
    let newTouch2 = touches[1]

    if newTouch1 == firstTouch {
        firstTouch = newTouch1
        secondTouch = newTouch2
    } else {
        firstTouch = newTouch2
        secondTouch = newTouch1
    }

    let loc1 = firstTouch.location(in: sceneView)
    let loc2 = secondTouch.location(in: sceneView)

    if allowTranslation {
        // 1. Translation using the midpoint between the two fingers.
        updateTranslation(of: virtualObject, midpoint: loc1.midpoint(loc2))
    }

    let spanBetweenTouches = loc1 - loc2
    if allowRotation {
        // 2. Rotation based on the relative rotation of the fingers on a unit circle.
        updateRotation(of: virtualObject, span: spanBetweenTouches)
    }
}

func updateTranslation(of virtualObject: VirtualObject, midpoint: CGPoint) {
    if !translationThresholdPassed {

        let initialLocationToCurrentLocation = midpoint - initialMidPoint
        let distanceFromStartLocation = initialLocationToCurrentLocation.length()

        // Check if the translate gesture has crossed the threshold.
        // If the user is already rotating and or scaling we use a bigger threshold.

        var threshold = translationThreshold
        if rotationThresholdPassed || scaleThresholdPassed {
            threshold = translationThresholdHarder
        }

        if distanceFromStartLocation >= threshold {
            translationThresholdPassed = true

            let currentObjectLocation = CGPoint(sceneView.projectPoint(virtualObject.position))
            dragOffset = midpoint - currentObjectLocation
        }
    }

    if translationThresholdPassed {
        let offsetPos = midpoint - dragOffset
        objectManager.translate(virtualObject, in: sceneView, basedOn: offsetPos, instantly: false, infinitePlane: true)
        lastUsedObject = virtualObject
    }
}

func updateRotation(of virtualObject: VirtualObject, span: CGPoint) {
    let midpointToFirstTouch = span / 2
    let currentAngle = atan2(Float(midpointToFirstTouch.x), Float(midpointToFirstTouch.y))

    let currentAngleToInitialFingerAngle = initialFingerAngle - currentAngle

    if !rotationThresholdPassed {
        var threshold = rotationThreshold

        if translationThresholdPassed || scaleThresholdPassed {
            threshold = rotationThresholdHarder
        }

        if abs(currentAngleToInitialFingerAngle) > threshold {

            rotationThresholdPassed = true

            // Change the initial object angle to prevent a sudden jump after crossing the threshold.
            if currentAngleToInitialFingerAngle > 0 {
                initialObjectAngle += threshold
            } else {
                initialObjectAngle -= threshold
            }
        }
    }

    if rotationThresholdPassed {
        // Note:
        // For looking down on the object (99% of all use cases), we need to subtract the angle.
        // To make rotation also work correctly when looking from below the object one would have to
        // flip the sign of the angle depending on whether the object is above or below the camera...
        virtualObject.eulerAngles.y = initialObjectAngle - currentAngleToInitialFingerAngle
        lastUsedObject = virtualObject
    }
}

    func finishGesture() {
        // Nothing to do here for two finger gestures.
    }
}

0 ответов

Другие вопросы по тегам