How to get a tap position in ARKit? - swift

I am trying to tap the screen and get tap position then I can fire the bullet from the position I tap.
I searched and tried many ways such as below but it doesn't work
guard let pointOfView = sceneView.pointOfView else { return }
let transform = pointOfView.transform
let orientation = SCNVector3(-transform.m31, -transform.m32, -transform.m33)
let scnView = sender.view as! ARSCNView
let holdLocation = sender.location(in: scnView)
let estimatedPlane: ARRaycastQuery.Target = .existingPlaneInfinite
let alignment: ARRaycastQuery.TargetAlignment = .any
guard let query = scnView.raycastQuery(from: holdLocation,
allowing: estimatedPlane,
alignment: alignment)
else { return }
let results = scnView.session.raycast(query)
guard let pointResult = results.first else { return }
let pointTransform = SCNMatrix4(pointResult.worldTransform)
let pointLocation = SCNVector3(pointTransform.m41,
pointTransform.m42,
pointTransform.m43)
let pointPosition = orientation + pointLocation
Can anyone help to tell me how to do it? Highly appreciate it.

Related

(iOS SceneKit) Convert texture coordinate to xyz coordinate

I'm able to get the SCNHitTestResult with a long press gesture using the codes below, so that I can get the worldCoordinates(x,y,z) and textureCoordinates.
guard recognizer.state != .ended else { return }
let point = recognizer.location(in: self.panoramaView.sceneView)
guard let hitTest = self.panoramaView.sceneView.hitTest(point, options: nil).first else { return }
let textureCoordinates = hitTest.textureCoordinates(withMappingChannel: 0)
Now the problem is, with a given textureCoordinates, is it possible to convert it to worldCoordinates?
ps: I'm using CTPanoramaView library.

Remove complete .scn instead of individual nodes Swift ARKit

I am attempting to delete the .scn objects I placed down. However, with my current code, it is just deleting individual nodes. Here is how I handle the tap delete.
#objc func Erase(sender: UITapGestureRecognizer){
print("rendering")
//sharedVM.count = sharedVM.count + 1
guard let pointOfView = sceneView.pointOfView else {return}
guard let cameraPosition = getCameraPosition(in: sceneView) else {
return
}
let location = sender.location(in: view)
let currentPositionOfCamera = cameraPosition + getRay(for: location, in: sceneView)
DispatchQueue.main.async{
//guard let location = touches.first?.location(in: sceneView) else { return }
let results = self.sceneView.hitTest(location, options: [SCNHitTestOption.searchMode : 1])
for result in results { /// See if the beam hit the cube
let Node = result.node
Node.enumerateChildNodes { (node, stop) in
node.removeFromParentNode() }
Node.removeFromParentNode()
}
}
}
Here is how I place the object:
var objecttest = VirtualObject(url: referenceURL)!
//var objecttest = VirtualObject(url: URL(string: "Models.scnassets/cup/cup.scn")!)
objecttest.load()
self.sceneView.scene.rootNode.addChildNode(objecttest)
class VirtualObject: SCNReferenceNode {
...
}

Moving windows programmatically on MacOS in Swift

I'm trying to move a window programmatically on my desktop. For this I've tried:
let options = CGWindowListOption(arrayLiteral: .excludeDesktopElements, .optionOnScreenOnly)
let windowsListInfo = CGWindowListCopyWindowInfo(options, CGWindowID(0))
let windowsList = windowsListInfo as NSArray? as? [[String: AnyObject]]
let visibleWindows = windowsList?.filter{ $0["kCGWindowLayer"] as! Int == 0 }
for window in visibleWindows! {
let windowTitle = window["kCGWindowOwnerName"] as! String
let windowNumber = window["kCGWindowNumber"] as! Int32
if windowNumber == 124 { // Safari
let nsWindow = NSApp.window(withWindowNumber: Int(windowNumber))
nsWindow?.cascadeTopLeft(from: NSPoint(x: 100.0, y: 100.0))
nsWindow?.setFrameTopLeftPoint(NSPoint(x: 100.0, y: 100.0))
}
}
}
but when I'm trying to get NSWindow by using windowNumber:
NSApp.window(withWindowNumber: Int(windowNumber))
I get nil.
So my question is, how can I move any window programmatically by knowing its windowNumber?
I've even tried to bring that window to front and
let pid = window["kCGWindowOwnerPID"] as? Int32 {
let app = NSRunningApplication(processIdentifier: pid)
app?.activate(options: .activateIgnoringOtherApps)
doing this but nothing helped me.
Could someone help me to find out the way how I can move the Safari window(for example) programmatically?
This should get the trick done:
let owner = entry[kCGWindowOwnerName as String] as! String
var bounds = entry[kCGWindowBounds as String] as? [String: Int]
let pid = entry[kCGWindowOwnerPID as String] as? Int32
if owner == "Safari"
{
let appRef = AXUIElementCreateApplication(pid!);
var value: AnyObject?
let result = AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute as CFString, &value)
if let windowList = value as? [AXUIElement] {
print ("windowList #\(windowList)")
if let window = windowList.first
{
var position : CFTypeRef
var size : CFTypeRef
var newPoint = CGPoint(x: 0, y: 0)
var newSize = CGSize(width: 300, height: 800)
position = AXValueCreate(AXValueType(rawValue: kAXValueCGPointType)!,&newPoint)!;
AXUIElementSetAttributeValue(windowList.first!, kAXPositionAttribute as CFString, position);
size = AXValueCreate(AXValueType(rawValue: kAXValueCGSizeType)!,&newSize)!;
AXUIElementSetAttributeValue(windowList.first!, kAXSizeAttribute as CFString, size);
}
}
}
By the way, I found this code in another discussion which I can't find at the moment, sorry about that
Oh and you need this code to request the accessibility access:
let options: NSDictionary = [kAXTrustedCheckOptionPrompt.takeUnretainedValue() as String : true]
let accessEnabled = AXIsProcessTrustedWithOptions(options)
if !accessEnabled {
print("Access Not Enabled")
}
Hope this helps, even if it's been a year and five days since you posted this question :)

Distance from Current Location to Annotation. (Firebase)

I want to have a the distance from my Currentlocation to a annotation that's in the FireData Base. I tried to make it word but i can't ;(. I would like to have the distance between the two locations in a var. I hope you guys can help me.
func reload(){
//get data
Database.database().reference().child("Rollerbanken").observe(.value, with: { (snapshot) in
for item in snapshot.children{
if let value = snapshot.value as? Dictionary<String, Any> {
for key in value.keys {
if let itemDict = value[key] as? Dictionary<String, AnyObject> {
let annotation = MKPointAnnotation()
annotation.title = itemDict["TypeControle"] as! String
let tijd = itemDict["Tijd"] as! String
annotation.subtitle = "Geplaatst om \(tijd)"
let getLatitude = itemDict["Latitude"] as? String
let getLongitude = itemDict["Longitude"] as? String
if let lat = getLatitude, let long = getLongitude {
annotation.coordinate = CLLocationCoordinate2D(latitude: Double(lat)!, longitude: Double(long)!)
self.map.addAnnotation(annotation)
let directionRequest = MKDirectionsRequest()
directionRequest.source = MKMapItem.forCurrentLocation()
if #available(iOS 10.0, *) {
directionRequest.destination = MKMapItem(placemark: MKPlacemark.init(coordinate: CLLocationCoordinate2DMake(Double(lat)!, Double(long)!)))
} else {
// Fallback on earlier versions
}
directionRequest.transportType = .walking
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: { (response, error) in
if error != nil {
print("Error while build route")
} else {
let route = response?.routes.last
let distance = route?.distance
print(distance)
}
})
}
}
}
}
}
})
}
Here is my Structure:
Try to use this code. Don't forget to enable your current location on map
let directionRequest = MKDirectionsRequest()
directionRequest.source = MKMapItem.forCurrentLocation()
directionRequest.destination = MKMapItem(placemark: MKPlacemark.init(coordinate: CLLocationCoordinate2DMake(YOURPOINTLATITUDE, YOURPOINTLONGITUDE)))
directionRequest.transportType = .walking
let direction = MKDirections(request: directionRequest)
direction.calculate(completionHandler: { (response, error) in
if error != nil {
print("Error while build route")
} else {
let route = response?.routes.last
let distance = route?.distance
I have used similar function, NOTE this was my function therefore it has rider and driver.. however you can change it to use annotation and location from firebase.
if let rideRequestDictionary = snapshot.value as? [String:AnyObject] {
// Getting the rider location and email
if let email = rideRequestDictionary["email"] as? String {
if let lat = rideRequestDictionary["lat"] as? Double{
if let lon = rideRequestDictionary["lon"] as? Double{
// Getting the Driver location and email
let driverCLLocation = CLLocation(latitude: driverLocation.latitude, longitude: driverLocation.longitude)
let riderCLLocation = CLLocation(latitude: lat, longitude: lon)
// getting the distance between the two people
let distance = driverCLLocation.distance(from: riderCLLocation) / 1000
// rounding the distances
let roundedDistance = round(distance * 100) / 100
// putting the rounded distance and email in label
cell.textLabel?.text = "\(email) - \(roundedDistance)km away"
}
}
}

Error "Optional type" when converting to Swift 3 syntax

When converting my project to the Swift 3 syntax I ran into several errors and was able to solve all but one.
The error message I'm getting is:
"Initializer for conditional binding must have Optional type, not 'UIView'"
Here is the code(I'm using Yalatis cocoapod ColorMatchTabs):
public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
self.transitionContext = transitionContext
guard let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to),
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
let containerView = transitionContext.containerView else {
return
}
containerView.addSubview(toViewController.view)
let needShow = mode == .show
if !needShow {
containerView.addSubview(fromViewController.view)
}
let animatedViewController = needShow ? toViewController : fromViewController
let initialRect = CGRect(origin: startPoint, size: CGSize.zero)
let initialCircleMaskPath = UIBezierPath(ovalIn: initialRect)
let extremePoint = CGPoint(x: startPoint.x, y: animatedViewController.view.bounds.height)
let radius = hypot(extremePoint.x, extremePoint.y)
let finalCircleMaskPath = UIBezierPath(ovalIn: initialRect.insetBy(dx: -radius, dy: -radius))
let maskLayer = CAShapeLayer()
maskLayer.path = needShow ? finalCircleMaskPath.cgPath : initialCircleMaskPath.cgPath
animatedViewController.view.layer.mask = maskLayer
let maskLayerAnimation = CABasicAnimation(keyPath: "path")
maskLayerAnimation.fromValue = initialCircleMaskPath.cgPath
maskLayerAnimation.fromValue = needShow ? initialCircleMaskPath.cgPath : finalCircleMaskPath.cgPath
maskLayerAnimation.toValue = needShow ? finalCircleMaskPath.cgPath : initialCircleMaskPath.cgPath
maskLayerAnimation.duration = transitionDuration(using: transitionContext)
maskLayer.add(maskLayerAnimation, forKey: "path")
}
This is were it fails:
guard let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to),
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
let containerView = transitionContext.containerView else {
return
}
And the error message appears here:
let containerView = transitionContext.containerView else {
return
}
I'm not very good at swift yet, obviously not good enough to solve this error. I'm grateful for all the help I can get!
transitionContext.containerView is not an optional, you don't need to put it inside a guard-let statement because it will always have a value
Replace this:
guard let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to),
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
let containerView = transitionContext.containerView else {
return
}
with
guard let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to),
let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from) else {
return
}
let containerView = transitionContext.containerView