Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Scenekit - Centering SCNText - the getBoundingBoxMin:Max issue

Having fun with the alignmentMode option on SCNText. Been googling around and it looks like there is a problem with alignmentMode and containerFrame. The alternatives I've found suggest using the get bounding box function to find the text size and then manually adjust accordingly. Great except I cant get the function to work. When I try to get the two vectors I get an error:

'SCNVector3' is not convertible to 'UnsafeMutablePointer < SCNVector3>'

I get that both on the geometry and the node. example of the code is below

func setCounterValue(counterValue:Int) {

    var v1 = SCNVector3(x: 0,y: 0,z: 0)
    var v2 = SCNVector3(x: 0,y: 0,z: 0)


    _counterValue = counterValue

    let newText = SCNText(string: String(format: "%06d", counterValue), extrusionDepth:sDepth)
    newText.font = UIFont (name: "Arial", size: 3)
    newText.firstMaterial!.diffuse.contents = UIColor.whiteColor()
    newText.firstMaterial!.specular.contents = UIColor.whiteColor()

    newText.getBoundingBoxMin(v1, max: v2)

    _textNode = SCNNode(geometry: newText)
    _textNode.getBoundingBoxMin(v1, max: v2)

}

Any suggestions greatly appreciated.

like image 779
Matthew Baker Avatar asked Dec 21 '14 15:12

Matthew Baker


3 Answers

OK so my final code solution looks like:

func setCounterValue(counterValue:Int) {

    var v1 = SCNVector3(x: 0,y: 0,z: 0)
    var v2 = SCNVector3(x: 0,y: 0,z: 0)

    _textNode.removeFromParentNode()
    _counterValue = counterValue

    let newText = SCNText(string: String(format: "%08d", counterValue), extrusionDepth:sDepth)
    newText.font = UIFont (name: "Arial", size: 3)
    newText.firstMaterial!.diffuse.contents = UIColor.whiteColor()
    newText.firstMaterial!.specular.contents = UIColor.whiteColor()

    _textNode = SCNNode(geometry: newText)
    _textNode.getBoundingBoxMin(&v1, max: &v2)

    let dx:Float = Float(v1.x - v2.x)/2.0
    let dy:Float = Float(v1.y - v2.y)
    _textNode.position = SCNVector3Make(dx, dy, Float(sDepth/2))

    node.addChildNode(_textNode)

}

I've left in my couple of global variables, but should make sense.

Thanks for the help all.

like image 145
Matthew Baker Avatar answered Nov 15 '22 08:11

Matthew Baker


EDIT: Functions with out-pointer arguments suck in Swift, so in Swift 3 Apple replaced this method (and the corresponding setter method) with a property whose type is a tuple:

var boundingBox: (min: SCNVector3, max: SCNVector3) { get set }

So you can just write something like:

let (min, max) = textNode.boundingBox

More generally...

Functions that take an out-parameter of UnsafeMutablePointer type in Swift can be called by passing an inout reference as the parameter. So for the Swift 2 version of this method, or for similar methods elsewhere:

_textNode.getBoundingBoxMin(&v1, max: &v2)
like image 44
rickster Avatar answered Nov 15 '22 07:11

rickster


You can add text by using this code, it is written in Swift 5

import ARKit

class ARSceneViewController: UIViewController {

    @IBOutlet var sceneView: ARSCNView!
    let config = ARWorldTrackingConfiguration()

    private func addTextToTheWorld() {
        let text = SCNText(string: "HELLO WORLD", extrusionDepth: 0.02)
        let font = UIFont(name: "Futura", size: 0.22)
        text.font = font
        text.alignmentMode = CATextLayerAlignmentMode.center.rawValue
        text.firstMaterial?.diffuse.contents = UIColor.red
        text.firstMaterial?.specular.contents = UIColor.white
        text.firstMaterial?.isDoubleSided = true
        text.chamferRadius = 0.01

        let (minBound, maxBound) = text.boundingBox
        let textNode = SCNNode(geometry: text)
        textNode.pivot = SCNMatrix4MakeTranslation( (maxBound.x - minBound.x)/2, minBound.y, 0.02/2)
        textNode.scale = SCNVector3Make(0.1, 0.1, 0.1)
        textNode.position = SCNVector3(0.1, 0.1, -0.1)
        sceneView.scene.rootNode.addChildNode(textNode)
    }


    // MARK: - View lifeCycle methods
    override func viewDidLoad() {
        super.viewDidLoad()

        //ARKit Debugging:
        // Show Axis and feature points
        sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints, ARSCNDebugOptions.showWorldOrigin]
        sceneView.session.run(config)
        self.addTextToTheWorld()
    }
}
like image 22
Kampai Avatar answered Nov 15 '22 08:11

Kampai