CAEmitterLayer doesn't work in MacOS with Swift - swift

I just simply create a storyboard program, and change the main ViewController code to the code below which works well in others' example. but it appears nothing on the view? seeking help.
What I did:
create an project with storyboard, and I got 'AppDelegate.swift' and 'ViewController.swift'
paste 'Ball_green.png' to my project and see it under the file tree of my project.
paste the code below in 'ViewController.swift'
import Cocoa
class ViewController: NSViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do view setup here.
self.view.wantsLayer = true
self.addLayer()
}
func addLayer(){
let rootLayer = self.view.layer
let snowEmitter = CAEmitterLayer()
snowEmitter.drawsAsynchronously = true
snowEmitter.name = "snowEmitter"
snowEmitter.zPosition = 10.0
snowEmitter.emitterPosition = CGPoint(x: 0, y: 0)
snowEmitter.renderMode = CAEmitterLayerRenderMode.backToFront
snowEmitter.emitterShape = CAEmitterLayerEmitterShape.circle
snowEmitter.emitterZPosition = -43.00
snowEmitter.emitterSize = CGSize(width: 160, height: 160)
snowEmitter.velocity = 20.57
snowEmitter.emitterMode = CAEmitterLayerEmitterMode.points
snowEmitter.birthRate = 10
let snowFlakesCell2 = CAEmitterCell()
snowFlakesCell2.emissionRange = .pi
snowFlakesCell2.lifetime = 10.0
snowFlakesCell2.birthRate = 4.0
snowFlakesCell2.velocity = 2.0
snowFlakesCell2.velocityRange = 100.0
snowFlakesCell2.yAcceleration = 300.0
snowFlakesCell2.contents = NSImage(named: "Ball_green.png")!.cgImage
snowFlakesCell2.magnificationFilter = convertFromCALayerContentsFilter(CALayerContentsFilter.nearest)
snowFlakesCell2.scale = 0.72
snowFlakesCell2.scaleRange = 0.14
snowFlakesCell2.spin = 0.38
snowFlakesCell2.spinRange = 0
snowEmitter.emitterCells = [snowFlakesCell2]
rootLayer!.addSublayer(snowEmitter)
}
}
fileprivate func convertFromCALayerContentsFilter(_ input: CALayerContentsFilter) -> String {
return input.rawValue
}

extension NSImage {
var cgImage: CGImage {
get {
let imageData = self.tiffRepresentation
let source = CGImageSourceCreateWithData(imageData as! CFData, nil)
let maskRef = CGImageSourceCreateImageAtIndex(source!, 0, nil)
return maskRef!
}
}
}
I've solved the problem after adding the code.

Related

Get snapshot from AVCaptureSession contaning Visionkit face detection elements

I use AVCaptureSession to setup a camera view and using vision kit to detect and add a rectangular on the face.
Here is how I can do it
override func viewDidLoad() {
super.viewDidLoad()
self.prepareVisionRequest()
}
fileprivate func prepareVisionRequest() {
//self.trackingRequests = []
var requests = [VNTrackObjectRequest]()
let faceDetectionRequest = VNDetectFaceRectanglesRequest(completionHandler: { (request, error) in
if error != nil {
print("FaceDetection error: \(String(describing: error)).")
}
guard let faceDetectionRequest = request as? VNDetectFaceRectanglesRequest,
let results = faceDetectionRequest.results else {
return
}
DispatchQueue.main.async {
// Add the observations to the tracking list
for observation in results {
let faceTrackingRequest = VNTrackObjectRequest(detectedObjectObservation: observation)
faceTrackingRequest.trackingLevel = .fast
requests.append(faceTrackingRequest)
}
self.trackingRequests = requests
}
})
// Start with detection. Find face, then track it.
self.detectionRequests = [faceDetectionRequest]
self.sequenceRequestHandler = VNSequenceRequestHandler()
self.setupVisionDrawingLayers()
}
// MARK: Drawing Vision Observations
fileprivate func setupVisionDrawingLayers() {
let captureDeviceResolution = self.captureDeviceResolution
let captureDeviceBounds = CGRect(x: 0,
y: 0,
width: captureDeviceResolution.width,
height: captureDeviceResolution.height)
let captureDeviceBoundsCenterPoint = CGPoint(x: captureDeviceBounds.midX,
y: captureDeviceBounds.midY)
let normalizedCenterPoint = CGPoint(x: 0.5, y: 0.5)
guard let rootLayer = self.rootLayer else {
self.presentErrorAlert(message: "view was not property initialized")
return
}
let overlayLayer = CALayer()
overlayLayer.name = "DetectionOverlay"
overlayLayer.masksToBounds = true
overlayLayer.anchorPoint = normalizedCenterPoint
overlayLayer.bounds = captureDeviceBounds
overlayLayer.position = CGPoint(x: rootLayer.bounds.midX, y: rootLayer.bounds.midY)
let faceRectangleShapeLayer = CAShapeLayer()
faceRectangleShapeLayer.name = "RectangleOutlineLayer"
faceRectangleShapeLayer.bounds = captureDeviceBounds
faceRectangleShapeLayer.anchorPoint = normalizedCenterPoint
faceRectangleShapeLayer.position = captureDeviceBoundsCenterPoint
faceRectangleShapeLayer.fillColor = UIColor.white.withAlphaComponent(0.9).cgColor
// faceLandmarksShapeLayer.strokeColor = UIColor.white.withAlphaComponent(0.7).cgColor
faceRectangleShapeLayer.lineWidth = 5
faceRectangleShapeLayer.shadowOpacity = 0.7
faceRectangleShapeLayer.shadowRadius = 5
let faceLandmarksShapeLayer = CAShapeLayer()
faceLandmarksShapeLayer.name = "FaceLandmarksLayer"
faceLandmarksShapeLayer.bounds = captureDeviceBounds
faceLandmarksShapeLayer.anchorPoint = normalizedCenterPoint
faceLandmarksShapeLayer.position = captureDeviceBoundsCenterPoint
faceLandmarksShapeLayer.fillColor = nil
faceLandmarksShapeLayer.strokeColor = nil
//
overlayLayer.addSublayer(faceRectangleShapeLayer)
faceRectangleShapeLayer.addSublayer(faceLandmarksShapeLayer)
rootLayer.addSublayer(overlayLayer)
self.detectionOverlayLayer = overlayLayer
self.detectedFaceRectangleShapeLayer = faceRectangleShapeLayer
self.detectedFaceLandmarksShapeLayer = faceLandmarksShapeLayer
self.updateLayerGeometry()
}
Now, I'm trying three ways to take snapshots
1- using UIGraphicsImageRenderer, it shows only the rectangular on the face and the camera view in not visible - it's black
2- Take image from captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) - the image from the buffer shows only the camera view, no rectangular
3- use AVCapturePhotoCaptureDelegate to capture photo from AVCaptureSession, the captured photo shows only the camera view, no rectangular
Could you please help me to take snapshot that contains both camera view and the rectangular! Thanks

How to use CAEmitterLayer on macOS in a SwiftUI app using NSViewRepresentable

I want to use a CAEmitterLayer within a macOS app that is based on SwiftUI.
Problem: The layer itself is perfectly visible, but it doesn’t emit any particles.
→ Here’s my demo project on GitHub
I basically built a NSViewRepresentable for a custom class EmitterNSView: NSView that handles the emitter layer itself.
final class EmitterNSView: NSView {
private let emitterLayer: CAEmitterLayer = {
let layer = CAEmitterLayer()
layer.backgroundColor = NSColor.green.withAlphaComponent(0.33).cgColor
return layer
}()
private let emitterCells: [CAEmitterCell] = {
// https://developer.apple.com/documentation/quartzcore/caemitterlayer
let cell = CAEmitterCell()
cell.name = "someParticle"
cell.birthRate = 10
cell.lifetime = 5.0
cell.velocity = 100
cell.velocityRange = 50
cell.emissionLongitude = 0.0
cell.emissionRange = CGFloat.pi * 2.0
cell.spinRange = 5
cell.scale = 1.0
cell.scaleRange = 0.25
cell.alphaSpeed = 0.25
cell.contents = NSImage(named: "whiteParticle.png")!.cgImage
cell.color = NSColor.systemPink.cgColor
cell.xAcceleration = 4
cell.yAcceleration = 3
cell.zAcceleration = 2
return [cell]
}()
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
self.wantsLayer = true
self.layer = CALayer()
self.layer?.autoresizingMask = [.layerWidthSizable, .layerHeightSizable]
self.configureEmitterLayer()
self.layer?.addSublayer(self.emitterLayer)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func layout() {
super.layout()
self.configureEmitterLayer()
}
override func updateLayer() {
super.updateLayer()
self.configureEmitterLayer()
}
func configureEmitterLayer() {
self.emitterLayer.frame = self.frame
self.emitterLayer.autoresizingMask = [.layerHeightSizable, .layerWidthSizable]
self.emitterLayer.masksToBounds = false
self.emitterLayer.drawsAsynchronously = true
self.emitterLayer.emitterMode = .points
self.emitterLayer.birthRate = 2
self.emitterLayer.emitterShape = CAEmitterLayerEmitterShape.line
self.emitterLayer.emitterSize = CGSize(width: frame.width * 0.5, height: frame.height * 0.5)
self.emitterLayer.emitterPosition = CGPoint.zero
self.emitterLayer.renderMode = CAEmitterLayerRenderMode.additive
self.emitterLayer.emitterCells = self.emitterCells
self.emitterLayer.zPosition = 10
self.emitterLayer.beginTime = CACurrentMediaTime()
self.emitterLayer.speed = 1.5
self.emitterLayer.emitterCells = self.emitterCells
}
}
The fact that I can clearly see the green background of the layer within the app indicates that something is wrong with the cells? Feeling lost at this point.
Very similar implementations in UIKit work just fine.
How can I use CAEmitterLayer on macOS within a SwiftUI based app?
Use cgImage(forProposedRect:context:hints:) while casting NSImage to a CGImage.
cell.contents = NSImage(named:"whiteParticle.png").flatMap {
return $0.cgImage(forProposedRect: nil, context: nil, hints: nil)
}

Multiple scatterplots using Core Plot and Swift

I'm trying to find a way to add two different scatterplots to a single graph but i wasn't able so far. I've found some examples in Objective-C but nothing in Swift, just the Scatterplot example in the CorePlot 2.1 release, but it plots the same data in two different line colors.
This is what i have so far (only one scatter plot is plotted):
import UIKit
import CorePlot
class ViewController : UIViewController, CPTScatterPlotDataSource {
private var scatterGraph : CPTXYGraph? = nil
typealias plotDataType = [CPTScatterPlotField : Double]
private var dataForPlot = [plotDataType]()
#IBOutlet var graphView: UIView!
// MARK: Initialization
override func viewDidAppear(animated : Bool)
{
super.viewDidAppear(animated)
// Create graph from theme
let newGraph = CPTXYGraph(frame: CGRectZero)
newGraph.applyTheme(CPTTheme(named: kCPTDarkGradientTheme))
let hostingView = graphView as! CPTGraphHostingView
hostingView.hostedGraph = newGraph
// Paddings
newGraph.paddingLeft = 10.0
newGraph.paddingRight = 10.0
newGraph.paddingTop = 10.0
newGraph.paddingBottom = 10.0
// Plot space
let plotSpace = newGraph.defaultPlotSpace as! CPTXYPlotSpace
//plotSpace.allowsUserInteraction = true
plotSpace.yRange = CPTPlotRange(location:0, length:10)
plotSpace.xRange = CPTPlotRange(location:0, length:10)
// Axes
let axisSet = newGraph.axisSet as! CPTXYAxisSet
if let x = axisSet.xAxis {
x.majorIntervalLength = 2
x.orthogonalPosition = 2.0
x.minorTicksPerInterval = 2
}
if let y = axisSet.xAxis {
y.majorIntervalLength = 2
y.minorTicksPerInterval = 5
y.orthogonalPosition = 2.0
y.delegate = self
}
// Create a blue plot area
let boundLinePlot = CPTScatterPlot(frame: CGRectZero)
let blueLineStyle = CPTMutableLineStyle()
blueLineStyle.miterLimit = 1.0
blueLineStyle.lineWidth = 3.0
blueLineStyle.lineColor = CPTColor.blueColor()
boundLinePlot.dataLineStyle = blueLineStyle
boundLinePlot.identifier = "Blue Plot"
boundLinePlot.dataSource = self
newGraph.addPlot(boundLinePlot)
// Add plot symbols
let symbolLineStyle = CPTMutableLineStyle()
symbolLineStyle.lineColor = CPTColor.blackColor()
let plotSymbol = CPTPlotSymbol.ellipsePlotSymbol()
plotSymbol.fill = CPTFill(color: CPTColor.blueColor())
plotSymbol.lineStyle = symbolLineStyle
plotSymbol.size = CGSize(width: 10.0, height: 10.0)
// Put an area gradient under the plot above
let areaColor = CPTColor(componentRed: 0.3, green: 1.0, blue: 0.3, alpha: 0.8)
let areaGradient = CPTGradient(beginningColor: areaColor, endingColor: CPTColor.clearColor())
areaGradient.angle = -90.0
let areaGradientFill = CPTFill(gradient: areaGradient)
// Add some initial data
var contentArray = [plotDataType]()
let plotData1: plotDataType = [.X: 0, .Y: 5]
let plotData2: plotDataType = [.X: 5, .Y: 0]
contentArray.append(plotData1)
contentArray.append(plotData2)
self.dataForPlot = contentArray
self.scatterGraph = newGraph
}
// MARK: - Plot Data Source Methods
func numberOfRecordsForPlot(plot: CPTPlot) -> UInt
{
return UInt(self.dataForPlot.count)
}
func numberForPlot(plot: CPTPlot, field: UInt, recordIndex: UInt) -> AnyObject?
{
let plotField = CPTScatterPlotField(rawValue: Int(field))
if let num = self.dataForPlot[Int(recordIndex)][plotField!] {
return num as NSNumber
}
else {
return nil
}
}
// MARK: - Axis Delegate Methods
func axis(axis: CPTAxis, shouldUpdateAxisLabelsAtLocations locations: NSSet!) -> Bool
{
if let formatter = axis.labelFormatter {
let labelOffset = axis.labelOffset
var newLabels = Set<CPTAxisLabel>()
for tickLocation in locations {
if let labelTextStyle = axis.labelTextStyle?.mutableCopy() as? CPTMutableTextStyle {
if tickLocation.doubleValue >= 0.0 {
labelTextStyle.color = CPTColor.greenColor()
}
else {
labelTextStyle.color = CPTColor.redColor()
}
let labelString = formatter.stringForObjectValue(tickLocation)
let newLabelLayer = CPTTextLayer(text: labelString, style: labelTextStyle)
let newLabel = CPTAxisLabel(contentLayer: newLabelLayer)
newLabel.tickLocation = tickLocation as! NSNumber
newLabel.offset = labelOffset
newLabels.insert(newLabel)
}
axis.axisLabels = newLabels
}
}
return false
}
}
This gives me a single line, but i want to add an additional line with a different data.
Any suggestions?
For a starter, create two CPTScatterPlots (e.g. boundLinePlot1 & boundLinePlot2)and configure them with different colors and different identifier then add them
boundLinePlot1.identifier = "Blue Plot"
boundLinePlot2.identifier = "Green Plot"
newGraph.addPlot(boundLinePlot1)
newGraph.addPlot(boundLinePlot2)
Now in the Plot Data Source Methods (numberOfRecordsForPlot & numberForPlot) calculate return value based on plot.identifier
if plot.identifier == "Blue Plot" {
return dataForPlot1[Int(recordIndex)][plotField!]
} else {
return dataForPlot2[Int(recordIndex)][plotField!]
}

How to build a well working Overlay SK Panel(HUD) on a SCNScene

the app I'm working on is supposed to show a 3D object and the user can pick a color to color it. I have a SCNScene with multiple mesh creating a 3D model. I need to build a side interactive panel with colors the user can use to color the 3D model. The code is here on github.
I show you my code (for now on one class only, that's bad i know)
import UIKit
import QuartzCore
import SceneKit
import SpriteKit
class GameViewController: UIViewController {
var cameraOrbit = SCNNode()
let cameraNode = SCNNode()
let camera = SCNCamera()
let floorNode = SCNNode()
var wallNode = SCNNode()
var lateralWallRight = SCNNode()
var lateralWallLeft = SCNNode()
var spotLightNode = SCNNode()
//HANDLE PAN CAMERA
var initialPositionCamera = SCNVector3(x: -25, y: 70, z: 1450)
var translateEnabled = false
var lastXPos:Float = 0.0
var lastYPos:Float = 0.0
var xPos:Float = 0.0
var yPos:Float = 0.0
var lastWidthRatio: Float = 0
var lastHeightRatio: Float = 0.1
var widthRatio: Float = 0
var heightRatio: Float = 0.1
var fingersNeededToPan = 1 //change this from GUI
var panAttenuation: Float = 10 //5.0: very fast ---- 40.0 very slow
let maxWidthRatioRight: Float = 0.2
let maxWidthRatioLeft: Float = -0.2
let maxHeightRatioXDown: Float = 0.065
let maxHeightRatioXUp: Float = 0.4
//HANDLE PINCH CAMERA
var pinchAttenuation = 1.0 //1.0: very fast ---- 100.0 very slow
var lastFingersNumber = 0
let maxPinch = 146.0
let minPinch = 40.0
//OVERLAY
var colorPanelScene = SKScene()
var pickedColor: UIColor = UIColor.whiteColor()
var NodesToColors = [SKSpriteNode: UIColor]()
var didPickColor = false
var OverlayBackground: SKSpriteNode = SKSpriteNode()
func setColors() {
//Color Setup
let ColorWhite = colorPanelScene.childNodeWithName("ColorWhite") as! SKSpriteNode
let ColorRed = colorPanelScene.childNodeWithName("ColorRed") as! SKSpriteNode
let ColorBrown = colorPanelScene.childNodeWithName("ColorBrown")as! SKSpriteNode
let ColorDarkBrown = colorPanelScene.childNodeWithName("ColorDarkBrown")as! SKSpriteNode
let white = UIColor(red:1, green:0.95, blue:0.71, alpha:1)
let brown = UIColor(red:0.49, green:0.26, blue:0.17, alpha:1)
let red = UIColor(red:0.67, green:0.32, blue:0.21, alpha:1)
let darkBrown = UIColor(red:0.27, green:0.25, blue:0.21, alpha:1)
NodesToColors = [
ColorWhite: white,
ColorRed: red,
ColorBrown: brown,
ColorDarkBrown: darkBrown
]
OverlayBackground = colorPanelScene.childNodeWithName("OverlayBackground")as! SKSpriteNode
}
func blur(image image: UIImage) -> UIImage {
let radius: CGFloat = 20;
let context = CIContext(options: nil);
let inputImage = CIImage(CGImage: image.CGImage!);
let filter = CIFilter(name: "CIGaussianBlur");
filter?.setValue(inputImage, forKey: kCIInputImageKey);
filter?.setValue("\(radius)", forKey:kCIInputRadiusKey);
let result = filter?.valueForKey(kCIOutputImageKey) as! CIImage;
let rect = CGRectMake(radius * 2, radius * 2, image.size.width - radius * 4, image.size.height - radius * 4)
let cgImage = context.createCGImage(result, fromRect: rect);
let returnImage = UIImage(CGImage: cgImage);
return returnImage;
}
override func viewDidLoad() {
super.viewDidLoad()
// create a new scene
let scene = SCNScene(named: "art.scnassets/Figure.scn")!
// MARK: Lights
//create and add a light to the scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 1000, z: 1000)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = UIColor.darkGrayColor()
scene.rootNode.addChildNode(ambientLightNode)
//MARK: Camera
camera.usesOrthographicProjection = true
camera.orthographicScale = 100
camera.zNear = 10
camera.zFar = 3000
cameraNode.position = initialPositionCamera
cameraNode.camera = camera
cameraOrbit = SCNNode()
cameraOrbit.addChildNode(cameraNode)
scene.rootNode.addChildNode(cameraOrbit)
//initial camera setup
self.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * lastWidthRatio
self.cameraOrbit.eulerAngles.x = Float(-M_PI) * lastHeightRatio
lastXPos = self.cameraNode.position.x
lastYPos = self.cameraNode.position.y
//MARK: Floor
let floor = SCNFloor()
floor.reflectionFalloffEnd = 0
floor.reflectivity = 0
floorNode.geometry = floor
floorNode.name = "Floor"
floorNode.geometry!.firstMaterial!.diffuse.contents = "art.scnassets/floor.png"
floorNode.geometry!.firstMaterial!.locksAmbientWithDiffuse = true
floorNode.geometry!.firstMaterial!.diffuse.wrapS = SCNWrapMode.Repeat
floorNode.geometry!.firstMaterial!.diffuse.wrapT = SCNWrapMode.Repeat
floorNode.geometry!.firstMaterial!.diffuse.mipFilter = SCNFilterMode.Nearest
floorNode.geometry!.firstMaterial!.doubleSided = false
floorNode.castsShadow = true
scene.rootNode.addChildNode(floorNode)
//MARK: Walls
// create the wall geometry
let wallGeometry = SCNPlane.init(width: 500.0, height: 300.0)
wallGeometry.firstMaterial!.diffuse.contents = "art.scnassets/background.jpg"
wallGeometry.firstMaterial!.diffuse.mipFilter = SCNFilterMode.Nearest
wallGeometry.firstMaterial!.diffuse.wrapS = SCNWrapMode.Repeat
wallGeometry.firstMaterial!.diffuse.wrapT = SCNWrapMode.Repeat
wallGeometry.firstMaterial!.doubleSided = false
wallGeometry.firstMaterial!.locksAmbientWithDiffuse = true
wallNode = SCNNode.init(geometry: wallGeometry)
wallNode.name = "FrontWall"
wallNode.position = SCNVector3Make(0, 120, -300) //this moves all 3 walls
wallNode.castsShadow = true
// RIGHT LATERAL WALL
lateralWallRight = SCNNode.init(geometry: wallGeometry)
lateralWallRight.name = "lateralWallRight"
lateralWallRight.position = SCNVector3Make(-300, -20, 150);
lateralWallRight.rotation = SCNVector4(x: 0, y: 1, z: 0, w: Float(M_PI/3))
lateralWallRight.castsShadow = true
wallNode.addChildNode(lateralWallRight)
// LEFT LATERAL WALL
lateralWallLeft = SCNNode.init(geometry: wallGeometry)
lateralWallLeft.name = "lateralWallLeft"
lateralWallLeft.position = SCNVector3Make(300, -20, 150);
lateralWallLeft.rotation = SCNVector4(x: 0, y: -1, z: 0, w: Float(M_PI/3))
lateralWallLeft.castsShadow = true
wallNode.addChildNode(lateralWallLeft)
//front walls
scene.rootNode.addChildNode(wallNode)
// retrieve the SCNView
let scnView = self.view as! SCNView
// set the scene to the view
scnView.scene = scene
// allows the user to manipulate the camera
scnView.allowsCameraControl = false //not needed
// configure the view
scnView.backgroundColor = UIColor.grayColor()
//MARK: Gesture Recognizer in SceneView
// add a pan gesture recognizer
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(GameViewController.handlePan(_:)))
scnView.addGestureRecognizer(panGesture)
// add a tap gesture recognizer
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(GameViewController.handleTap(_:)))
scnView.addGestureRecognizer(tapGesture)
// add a pinch gesture recognizer
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(GameViewController.handlePinch(_:)))
scnView.addGestureRecognizer(pinchGesture)
//MARK: OverLay
colorPanelScene = SKScene(fileNamed: "art.scnassets/ColorPanelScene")!
scnView.overlaySKScene = colorPanelScene
scnView.overlaySKScene!.userInteractionEnabled = true;
didPickColor = false
setColors()
//let OverlayBackground = colorPanelScene.childNodeWithName("OverlayBackground")as! SKSpriteNode
}
func handlePan(gestureRecognize: UIPanGestureRecognizer) {
let numberOfTouches = gestureRecognize.numberOfTouches()
let translation = gestureRecognize.translationInView(gestureRecognize.view!)
if (numberOfTouches==fingersNeededToPan) {
widthRatio = Float(translation.x) / Float(gestureRecognize.view!.frame.size.width) + lastWidthRatio
heightRatio = Float(translation.y) / Float(gestureRecognize.view!.frame.size.height) + lastHeightRatio
// HEIGHT constraints
if (heightRatio >= maxHeightRatioXUp ) {
heightRatio = maxHeightRatioXUp
}
if (heightRatio <= maxHeightRatioXDown ) {
heightRatio = maxHeightRatioXDown
}
// WIDTH constraints
if(widthRatio >= maxWidthRatioRight) {
widthRatio = maxWidthRatioRight
}
if(widthRatio <= maxWidthRatioLeft) {
widthRatio = maxWidthRatioLeft
}
self.cameraOrbit.eulerAngles.y = Float(-2 * M_PI) * widthRatio
self.cameraOrbit.eulerAngles.x = Float(-M_PI) * heightRatio
lastFingersNumber = fingersNeededToPan
//TRANSLATION pan
} else if numberOfTouches == (fingersNeededToPan+1) {
if translateEnabled {
xPos = (lastXPos + Float(-translation.x))/(panAttenuation)
yPos = (lastYPos + Float(translation.y))/(panAttenuation)
self.cameraNode.position.x = xPos
self.cameraNode.position.y = yPos
}
lastFingersNumber = fingersNeededToPan+1
}
if (lastFingersNumber == fingersNeededToPan && numberOfTouches != fingersNeededToPan) {
lastWidthRatio = widthRatio
lastHeightRatio = heightRatio
}
if lastFingersNumber != (fingersNeededToPan+1) && numberOfTouches != (fingersNeededToPan+1) {
lastXPos = xPos
lastYPos = yPos
}
if (gestureRecognize.state == .Ended) {
if (lastFingersNumber==fingersNeededToPan) {
lastWidthRatio = widthRatio
lastHeightRatio = heightRatio
//print("lastHeight: \(round(lastHeightRatio*100))")
//print("lastWidth: \(round(lastWidthRatio*100))")
}
if lastFingersNumber==(fingersNeededToPan+1) {
lastXPos = xPos
lastYPos = yPos
print("lastX: \(xPos)")
print("lastY: \(yPos)")
}
print("Pan with \(lastFingersNumber) finger\(lastFingersNumber>1 ? "s" : "")")
}
}
func handlePinch(gestureRecognize: UIPinchGestureRecognizer) {
let pinchVelocity = Double.init(gestureRecognize.velocity)
//print("PinchVelocity \(pinchVelocity)")
camera.orthographicScale -= (pinchVelocity/pinchAttenuation)
if camera.orthographicScale <= minPinch {
camera.orthographicScale = minPinch
}
if camera.orthographicScale >= maxPinch {
camera.orthographicScale = maxPinch
}
if (gestureRecognize.state == .Ended) {
print("\nPinch: \(round(camera.orthographicScale))\n")
}
}
func handleTap(gestureRecognize: UIGestureRecognizer) {
print("---------------TAP-----------------")
// retrieve the SCNView
let scnView = self.view as! SCNView
let touchedPointInScene = gestureRecognize.locationInView(scnView)
let hitResults = scnView.hitTest(touchedPointInScene, options: nil)
let OverlayView = colorPanelScene.view! as SKView
let touchedPointInOverlay = gestureRecognize.locationInView(OverlayView)
// if button color are touched
if OverlayBackground.containsPoint(touchedPointInOverlay) {
print("OVERLAY: tap in \(touchedPointInOverlay)")
for (node, color) in NodesToColors {
// Check if the location of the touch is within the button's bounds
if node.containsPoint(touchedPointInOverlay) {
print("\(node.name!) -> color picked \(color.description)")
pickedColor = color
didPickColor = true
}
}
} else {//if figure is touched
// check that we clicked on at least one object
if hitResults.count > 0 && didPickColor {
// retrieved the first clicked object
let result: AnyObject! = hitResults[0]
print("OBJECT tap: \(result.node.name!)")
//Exclude floor and wall from color
if result.node! != floorNode && result.node! != wallNode && result.node! != lateralWallRight && result.node! != lateralWallLeft {
// get its material
let material = result.node!.geometry!.firstMaterial!
print("material: \(material.name!)")
// begin coloration
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.5)
// on completion - keep color
SCNTransaction.setCompletionBlock {
SCNTransaction.begin()
SCNTransaction.setAnimationDuration(0.3)
material.diffuse.contents = self.pickedColor
SCNTransaction.commit()
}
SCNTransaction.commit()
material.diffuse.contents = pickedColor
}
}
}
print("-----------------------------------\n")
}
override func prefersStatusBarHidden() -> Bool {
return true
}
override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
return .Landscape
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Release any cached data, images, etc that aren't in use.
}
The code starts with a setColor function that catch images from ColorPanelScene.sks (this SKScene has a strange y-axis movement, i don't know why).
func setColors() {
//Color Setup
let ColorWhite = colorPanelScene.childNodeWithName("ColorWhite") as! SKSpriteNode
let ColorRed = colorPanelScene.childNodeWithName("ColorRed") as! SKSpriteNode
let ColorBrown = colorPanelScene.childNodeWithName("ColorBrown")as! SKSpriteNode
let ColorDarkBrown = colorPanelScene.childNodeWithName("ColorDarkBrown")as! SKSpriteNode
let white = UIColor(red:1, green:0.95, blue:0.71, alpha:1)
let brown = UIColor(red:0.49, green:0.26, blue:0.17, alpha:1)
let red = UIColor(red:0.67, green:0.32, blue:0.21, alpha:1)
let darkBrown = UIColor(red:0.27, green:0.25, blue:0.21, alpha:1)
NodesToColors = [
ColorWhite: white,
ColorRed: red,
ColorBrown: brown,
ColorDarkBrown: darkBrown
]
OverlayBackground = colorPanelScene.childNodeWithName("OverlayBackground")as! SKSpriteNode
}
Then, you can see a blur effect function that I would like to add to the panel background. Do you know how to do it to a SKNode? That would be easy if I use UIView instead, but i don't know how to back layer Views.
func blur(image image: UIImage) -> UIImage {
let radius: CGFloat = 20;
let context = CIContext(options: nil);
let inputImage = CIImage(CGImage: image.CGImage!);
let filter = CIFilter(name: "CIGaussianBlur");
filter?.setValue(inputImage, forKey: kCIInputImageKey);
filter?.setValue("\(radius)", forKey:kCIInputRadiusKey);
let result = filter?.valueForKey(kCIOutputImageKey) as! CIImage;
let rect = CGRectMake(radius * 2, radius * 2, image.size.width - radius * 4, image.size.height - radius * 4)
let cgImage = context.createCGImage(result, fromRect: rect);
let returnImage = UIImage(CGImage: cgImage);
return returnImage;
}
If you look at the buttons on ColorPanelScene.sks they have wrong names because I used a workaround to make that panel works. It seems to match color nodes, textures and nodes names in a inverse way.
That's obviously a bad implementation of a side panel. Please, can you help me to build a better interactive panel? Thank You.

Cannot change the size of a popover

I've been trying to create my own code, as well as copy and paste examples, but my popover seems to fill the entire screen. Generally my code looks like below, but like I said, I've tried at least two other examples (some with CGSizeMake(), sourceRect, sourceView), and the results are always the same.
Class TableView: UITableViewController, UIPopoverPresentationControllerDelegate {
let popover = UIViewController()
func someButton() {
popover.modalPresentationStyle = .Popover
popover.preferredContentSize = CGSize(1, 1)
let menu = popover.popoverPresentationController
menu!.delegate = self
menu!.barButtonItem = someOtherCorrectButton
self.presentViewController(popover, animated: true, completion: nil)
}
}
What's the problem?
Try below code
popover.modalPresentationStyle = .Popover
var popupHeight:CGFloat = 542
let popupWidth = 400 as CGFloat
popover.preferredContentSize = CGSizeMake(400,popupHeight)
let window = UIApplication.sharedApplication().delegate!.window!!
let screenSize: CGRect = window.bounds
var XCordinate = (screenSize.width - popupWidth) / 2
var YCordinate = (screenSize.height / 2) + 20
let menu = popover.popoverPresentationController
menu!.delegate = self
menu!.sourceView = window
menu!.sourceRect = CGRect( x: XCordinate, y: YCordinate, width: 1, height: 1)
self.presentViewController(popover, animated: true, completion: nil)
May be it works for you.