Skip to content

Commit

Permalink
Added Storyboard/nib support
Browse files Browse the repository at this point in the history
  • Loading branch information
scihant committed Oct 14, 2016
1 parent cfc7605 commit 9fab36a
Show file tree
Hide file tree
Showing 4 changed files with 113 additions and 66 deletions.
2 changes: 2 additions & 0 deletions CTPanoramaController.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = 38P3Q4228V;
INFOPLIST_FILE = CTPanoramaController/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
Expand All @@ -292,6 +293,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
DEVELOPMENT_TEAM = 38P3Q4228V;
INFOPLIST_FILE = CTPanoramaController/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
Expand Down
36 changes: 32 additions & 4 deletions CTPanoramaController/Base.lproj/Main.storyboard
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,46 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="YM3-Hu-R4S">
<frame key="frameInset" minX="164" minY="109" width="46" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" title="Button"/>
<containerView opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="4vR-OZ-owG">
<connections>
<segue destination="Bsz-FD-2Kg" kind="embed" identifier="segue" id="Hvk-vF-oqa"/>
</connections>
</containerView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="NdB-jE-HZg">
<state key="normal" title="Touch/Motion"/>
<connections>
<action selector="buttonTapped" destination="BYZ-38-t0r" eventType="touchUpInside" id="BBK-Vm-XNf"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailing" secondItem="NdB-jE-HZg" secondAttribute="trailing" id="3St-3t-V7Y"/>
<constraint firstItem="4vR-OZ-owG" firstAttribute="leading" secondItem="8bC-Xf-vdC" secondAttribute="leading" id="Ll4-so-6NL"/>
<constraint firstAttribute="trailing" secondItem="4vR-OZ-owG" secondAttribute="trailing" id="NQ9-ka-GoV"/>
<constraint firstItem="NdB-jE-HZg" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="OrN-Pp-ovw"/>
<constraint firstItem="4vR-OZ-owG" firstAttribute="top" secondItem="y3c-jy-aDJ" secondAttribute="bottom" id="bGc-lT-kX1"/>
<constraint firstItem="wfy-db-euE" firstAttribute="top" secondItem="4vR-OZ-owG" secondAttribute="bottom" id="yaD-Y0-XXs"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-294" y="1"/>
</scene>
<!--Panorama Controller-->
<scene sceneID="e9N-Uz-rFE">
<objects>
<viewController id="Bsz-FD-2Kg" customClass="CTPanoramaController" customModule="CTPanoramaController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="93F-s2-Iow">
<rect key="frame" x="0.0" y="0.0" width="375" height="647"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="vDa-1t-Mhk" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="489" y="0.0"/>
</scene>
</scenes>
</document>
112 changes: 50 additions & 62 deletions CTPanoramaController/CTPanoramaViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ import ImageIO

public var image: UIImage? {
didSet {
geometryNode?.geometry?.firstMaterial?.diffuse.contents = image
panaromaType = panoramaTypeForCurrentImage
createGeometryNode()
resetCameraAngles()
}
}
Expand All @@ -46,8 +47,9 @@ import ImageIO
}
}

private let cameraNode = SCNNode()
private let sceneView = SCNView()
private let scene = SCNScene()
private let cameraNode = SCNNode()
private var geometryNode: SCNNode?
private var prevLocation = CGPoint.zero
private var motionManger = CMMotionManager()
Expand All @@ -70,7 +72,7 @@ import ImageIO
}

public required init?(coder aDecoder: NSCoder) {
fatalError("Cannot be initialized from a storyboard or nib")
super.init(coder: aDecoder)
}

deinit {
Expand All @@ -82,12 +84,18 @@ import ImageIO
override public func viewDidLoad() {
super.viewDidLoad()

if panaromaType == nil {
panaromaType = panoramaTypeForCurrentImage
if geometryNode == nil {
createGeometryNode()
}

view.add(view: sceneView)

prepareUI()
createScene()
createCamera()

scene.rootNode.addChildNode(cameraNode)

sceneView.scene = scene
sceneView.backgroundColor = UIColor.black

if controlMethod == nil {
controlMethod = .Touch
Expand All @@ -96,14 +104,20 @@ import ImageIO

// MARK: Configuration helper methods

private func createScene() {
guard let image = image else {return}

private func createCamera() {
let camera = SCNCamera()
camera.zFar = 100
camera.xFov = 70
camera.yFov = 70
cameraNode.camera = camera
}

private func createGeometryNode() {
guard let image = image else {return}

panaromaType = panoramaTypeForCurrentImage

geometryNode?.removeFromParentNode()

let material = SCNMaterial()
material.diffuse.contents = image
Expand All @@ -112,12 +126,12 @@ import ImageIO
material.diffuse.contentsTransform = SCNMatrix4MakeScale(-1, 1, 1)
material.diffuse.wrapS = .repeat
material.cullMode = .front

if (panaromaType == .Spherical) {
let sphere = SCNSphere(radius: 50)
sphere.segmentCount = 300
sphere.firstMaterial = material

let sphereNode = SCNNode()
sphereNode.geometry = sphere
sphereNode.position = SCNVector3Make(0, 0, 0)
Expand All @@ -133,46 +147,16 @@ import ImageIO
tubeNode.geometry = tube
tubeNode.position = SCNVector3Make(0, 0, 0)
geometryNode = tubeNode

panSpeed.y = 0 // Prevent vertical movement in a cylindrical panorama
}

guard let geometryNode = geometryNode else {return}
cameraNode.position = geometryNode.position

let scene = SCNScene()

scene.rootNode.addChildNode(cameraNode)
scene.rootNode.addChildNode(geometryNode)

sceneView.scene = scene
sceneView.backgroundColor = UIColor.black
}

private func prepareUI() {
sceneView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(sceneView)

let button = UIButton(type: .custom)
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Touch/Motion", for: .normal)
button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)

view.addSubview(button)

let views = ["sceneView" : sceneView, "button": button]

view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|[sceneView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[sceneView]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))

view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "[button]-10-|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
view.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|-10-[button]", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
cameraNode.position = geometryNode!.position
scene.rootNode.addChildNode(geometryNode!)
}

private func replace(overlayView: UIView?, with newOverlayView: UIView?) {
overlayView?.removeFromSuperview()
guard let newOverlayView = newOverlayView else {return}
view.addSubview(newOverlayView)
view.add(view: newOverlayView)
newOverlayView.isUserInteractionEnabled = false
}

private func switchControlMethod(to method: CTPanaromaControlMethod) {
Expand All @@ -192,18 +176,17 @@ import ImageIO
motionManger.startDeviceMotionUpdates(to: OperationQueue.main, withHandler: {[unowned self] (motionData, error) in
if let motionData = motionData {
self.cameraNode.orientation = motionData.look(at: UIApplication.shared.statusBarOrientation)
/*

if (self.panaromaType == .Cylindrical) {
self.cameraNode.eulerAngles.x = 0
self.cameraNode.eulerAngles.z = 0
}*/
}
}
else {
print("\(error?.localizedDescription)")
self.motionManger.stopDeviceMotionUpdates()
}
})

}
}

Expand Down Expand Up @@ -231,26 +214,22 @@ import ImageIO
tube.height = CGFloat(unprojectedTop.y - unprojectedBottom.y)
}

// MARK: Event handling methods

@objc private func buttonTapped() {
if controlMethod == .Touch {
controlMethod = .Motion
}
else {
controlMethod = .Touch
}
}
// MARK: Gesture handling

@objc private func handlePan(panRec: UIPanGestureRecognizer) {
if (panRec.state == .began) {
prevLocation = CGPoint.zero
}
else if (panRec.state == .changed) {
var modifiedPanSpeed = panSpeed
if (panaromaType == .Cylindrical) {
modifiedPanSpeed.y = 0 // Prevent vertical movement in a cylindrical panorama
}

let location = panRec.translation(in: sceneView)
let orientation = cameraNode.eulerAngles
var newOrientation = SCNVector3Make(orientation.x + Float(location.y - prevLocation.y) * Float(panSpeed.y),
orientation.y + Float(location.x - prevLocation.x) * Float(panSpeed.x),
var newOrientation = SCNVector3Make(orientation.x + Float(location.y - prevLocation.y) * Float(modifiedPanSpeed.y),
orientation.y + Float(location.x - prevLocation.x) * Float(modifiedPanSpeed.x),
orientation.z)

if (controlMethod == .Touch) {
Expand All @@ -267,7 +246,6 @@ import ImageIO
updateGeometrySize()
prevBounds = view.bounds
}

}
}

Expand Down Expand Up @@ -311,3 +289,13 @@ fileprivate extension CMDeviceMotion {
return result
}
}

fileprivate extension UIView {
func add(view: UIView) {
view.translatesAutoresizingMaskIntoConstraints = false
addSubview(view)
let views = ["view": view]
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "|[view]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
addConstraints(NSLayoutConstraint.constraints(withVisualFormat: "V:|[view]|", options: NSLayoutFormatOptions(rawValue: 0), metrics: nil, views: views))
}
}
29 changes: 29 additions & 0 deletions CTPanoramaController/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,44 @@ import UIKit

class ViewController: UIViewController {

private var pc: CTPanoramaController?

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "segue" {
pc = segue.destination as? CTPanoramaController
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

let image = UIImage(named: "normal.jpg")
pc?.image = image

let deadlineTime = DispatchTime.now() + .seconds(3)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {[unowned self] in
self.pc?.image = UIImage(named: "spherical.png")
}

/*
let p = CTPanoramaController(image: image!)

self.addChildViewController(p)
view.addSubview(p.view)
p.view.frame = view.bounds

let deadlineTime = DispatchTime.now() + .seconds(3)
DispatchQueue.main.asyncAfter(deadline: deadlineTime) {
p.image = UIImage(named: "spherical.png")
}
*/
}

@IBAction func buttonTapped() {
if pc!.controlMethod == .Touch {
pc!.controlMethod = .Motion
}
else {
pc!.controlMethod = .Touch
}
}
}

0 comments on commit 9fab36a

Please sign in to comment.