Centering a scaled SCNNode on top of another SCNNode

Viewed 374

in my new ARKit app the user can place objects on the detected plane. The plane is detected just fine and when the user touches the plane, a new node (a SCNBox) is created and dropped on the plane. This step works just fine.

However, I would like that the newly generated box (a more complex model later) is dropped at the exact center of the model.

Here is my code:

fileprivate func pasteModel(hitResult: ARHitTestResult)
{
    guard let model = self.model else { return }

    // Get the tapped plane.
    if let anchor = hitResult.anchor
    {
        if let plane = self.planes[anchor.identifier]
        {
            // Get the dimensions of the model.
            let widthModel = CGFloat(0.20)
            let lengthModel = CGFloat(0.20)

            let box = SCNBox(width: widthModel, height: widthModel, length: widthModel, chamferRadius: 0.0)
            box.firstMaterial = SCNMaterial()
            box.firstMaterial?.diffuse.contents = UIColor.cyan

            let node = SCNNode(geometry: box)
            plane.addChildNode(node)

            // Get the dimensions of the tapped plane.
            let width = plane.width
            let length = plane.length

            // Calculate the scale (i.e. how much bigger the model is). Keep the ratio, so use the bigger side.
            let scaleWidth = widthModel / width
            let scaleHeight = lengthModel / length

            let scale: Float = Float(1.0 / max(scaleWidth, scaleHeight))

            node.scale = SCNVector3Make(scale, scale, scale)
            node.position = plane.position

            // Check how much the model is away from the center point.
            let centerPlane = self.getCenter(ofNode: plane)
            let centerNode = self.getCenter(ofNode: node)

            let distanceX = centerPlane.x - centerPlane.z
            let distanceZ = centerNode.x - centerNode.z

            let translation = SCNVector3Make(distanceX, self.MODEL_OFFSET, distanceZ)
            node.localTranslate(by: translation)

            // After the model has been scaled and positoned properly, the physics body is added.
            node.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.dynamic, shape: nil)
            node.physicsBody?.mass = self.MODEL_MASS
            node.physicsBody?.angularVelocityFactor = SCNVector3Zero // Prevent model rotation.
        }
    }
}

fileprivate func getCenter(ofNode node: SCNNode) -> SCNVector3
{
    let widthNode = node.boundingBox.max.x - node.boundingBox.min.x
    let lengthNode = node.boundingBox.max.z - node.boundingBox.min.z
    let centerNode = SCNVector3Make(node.position.x + Float(widthNode / 2), node.position.y, node.position.z + Float(lengthNode / 2))

    return centerNode
}

Here is a short overview of my approach:

  • Get the plane detected by ARKit.
  • Create a cube and scale it to the dimensions of the plane - the bigger side is used for scaling.
  • Get the center point of both the plane and the cube.
  • Translate the cube so the center points align.

Unfortunately the model is not centered. Where is my error?

0 Answers
Related