iPhone手書き3D

落書きを3Dオブジェクトで表示するiPhoneアプリのサンプルコード

import UIKit

import SceneKit

private var myContext = 0

class ViewController: UIViewController {

    weak var sceneView : SCNView?

    weak var canvas : FreeHandView?

    

    override func viewDidLoad() {

        super.viewDidLoad()

        view.backgroundColor = UIColor.lightGrayColor()

        setupScene()

        createGround()

        createCamera()

        

        // freehand view

        createCanvas()

    }

    

    func createGround() {

        let ground = SCNBox(width: 20, height: 0.2, length: 20, chamferRadius: 0.1)

        ground.firstMaterial?.diffuse.contents = UIColor.brownColor()

        let groundNode = SCNNode(geometry: ground)

        groundNode.physicsBody = SCNPhysicsBody.staticBody()

        sceneView?.scene?.rootNode.addChildNode(groundNode)

    }

    

    func createCamera() {

        let camera = SCNNode()

        camera.camera = SCNCamera()

        camera.position = SCNVector3(x: 0, y: 10, z: 20)

        camera.rotation = SCNVector4(x: 1, y: 0, z: 0, w: –0.2)

        sceneView?.scene?.rootNode.addChildNode(camera)

    }

    

    func setupScene() {

        let sv = SCNView(frame: CGRect(x: 0, y: 0, width: CGRectGetMaxX(view.bounds), height: 300))

        sv.backgroundColor = UIColor.blackColor()

        sv.scene = SCNScene()

        sv.allowsCameraControl = true

        sv.autoenablesDefaultLighting = true

        view.addSubview(sv)

        sceneView = sv

    }

    func createCanvas() {

        let v = FreeHandView(frame: CGRectMake(5, 320, CGRectGetMaxX(view.bounds)-10, 300))

        view.addSubview(v)

        v.addObserver(self, forKeyPath: “objectPath”, options: .New, context: &myContext)

        canvas = v

    }

    

    override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {

        if context == &myContext {

            if let path = object.objectPath as UIBezierPath? {

                

                var transform = CGAffineTransformIdentity

                transform = CGAffineTransformScale(transform, 0.03, 0.03)

                transform = CGAffineTransformTranslate(transform, -(path.bounds.origin.x + path.bounds.size.width * 0.5), -(path.bounds.origin.y + path.bounds.size.height * 0.5))

                var pathTransformed = UIBezierPath(CGPath: CGPathCreateCopyByTransformingPath(path.CGPath, &transform))

                pathTransformed.usesEvenOddFillRule = true

                let shape = SCNShape(path: pathTransformed, extrusionDepth: 1.0)

                shape.firstMaterial?.diffuse.contents = UIColor.yellowColor()

                let shapeNode = SCNNode(geometry: shape)

                shapeNode.position = SCNVector3(x: 0, y: 12, z: 0)

                shapeNode.physicsBody = SCNPhysicsBody.dynamicBody()

                self.sceneView?.scene?.rootNode.addChildNode(shapeNode)

                self.sceneView?.playing = true

            }

        }

    }

    

    deinit {

        canvas?.removeObserver(self, forKeyPath: “objectPath”, context: &myContext)

    }

}

class FreeHandView : UIView {

    

    private var path : UIBezierPath = UIBezierPath()

    dynamic var objectPath : UIBezierPath?

    

    required init(coder aDecoder: NSCoder) {

        super.init(coder: aDecoder)

    }

    

    override init(frame: CGRect) {

        super.init(frame: frame)

        layer.borderWidth = 1

        layer.borderColor = UIColor.grayColor().CGColor

        layer.cornerRadius = 20.0

        layer.masksToBounds = true

        multipleTouchEnabled = false

        backgroundColor = UIColor.whiteColor()

        path.lineWidth = 4.0

    }

    

    override func drawRect(rect: CGRect) {

        UIColor.purpleColor().setStroke()

        path.stroke()

    }

    

    override func touchesBegan(touches: Set<NSObject>, withEvent event: UIEvent) {

        if let touch = touches.first as? UITouch {

            let p = touch.locationInView(self)

            path.moveToPoint(p)

        }

    }

    

    override func touchesMoved(touches: Set<NSObject>, withEvent event: UIEvent) {

        if let touch = touches.first as? UITouch {

            let p = touch.locationInView(self)

            path.addLineToPoint(p)

            setNeedsDisplay()

        }

    }

    

    override func touchesEnded(touches: Set<NSObject>, withEvent event: UIEvent) {

        touchesMoved(touches, withEvent: event)

        path.closePath()

        objectPath = UIBezierPath(CGPath: path.CGPath)

        path.removeAllPoints()

    }

    

    override func touchesCancelled(touches: Set<NSObject>!, withEvent event: UIEvent!) {

        touchesEnded(touches, withEvent: event)

    }

}