Zoom to fit user location and annotation map view swift - swift

My map view shows both the user location and annotation for the destination mural, but the zoom is off. How can I make it scale to fit the current location and the destination annotation based on how far apart they are and more centered?
This is how it zooms (so far away)
func mapPoints(){
let annotations = MKPointAnnotation()
annotations.title = muralModel.muralName!
muralModel.getMainArtistModel(completion: { (anArtistModel) in
annotations.subtitle = " \(anArtistModel!.firstName!) \(anArtistModel!.lastName!)"
})
annotations.coordinate = coordinates
muralLocation.addAnnotation(annotations)
self.muralLocation.showsUserLocation = true
var zoomRect: MKMapRect = MKMapRectNull
let mapEdgePadding = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
//convert CLLocationCoordinate2D to MKMapPointForCoordinate so you don't end up in Bering Sea
let userPoint = MKMapPointForCoordinate(muralLocation.userLocation.coordinate)
let destinationPoint = MKMapPointForCoordinate(coordinates)
let userPointRect = MKMapRectMake(userPoint.x, userPoint.y, 0.1, 0.1)
let destinationPointRect = MKMapRectMake(destinationPoint.x, destinationPoint.y, 0.1, 0.1)
zoomRect = userPointRect
zoomRect = MKMapRectUnion(zoomRect, destinationPointRect)
muralLocation.setVisibleMapRect(zoomRect, edgePadding: mapEdgePadding, animated: true)
}

You can use the 'func setRegion(_ region: MKCoordinateRegion, animated: Bool)'. MKCoordinateRegion has a center and also defines a span for the region. The center here can be a point at an equal distance from the userLocation and the destination. You can decide the span accordingly.

Related

Creating own marker with iconView on Google Maps

I created my own marker with iconView for showing my own position. As you can see it is the green one. But every time I move the screen it is reloading my green view and it seems lagging. I don't have the same problem with the other marker shown, which are simple png.
How can I solve that? I can solve that problem by removing the line mapView.clear() But the result is that every loaded marker don't go away if I zoom out. So the map gets more and more crowded.
func mapView(_ mapView: GMSMapView, didChange position: GMSCameraPosition) {
mapView.clear()
let fullCordinate = "\(mapView.camera.target.latitude),\(mapView.camera.target.longitude)"
networkGoogleApiConnect.fetchPoi(geoCordinate: fullCordinate)
networkGoogleApi.testVariable.forEach {
let marker1 = GMSMarker()
marker1.position = CLLocationCoordinate2D(latitude: $0.position.lat, longitude: $0.position.lng)
marker1.title = $0.title
marker1.icon = UIImage(named: "house")
var dict = [String:String]()
dict["id"] = $0.id
marker1.userData = dict
marker1.map = mapView
locationManager.stopUpdatingLocation()
}
locationManager.delegate=self
let neuLongitudeEigenerStandort = locationManager.location!.coordinate.longitude
let neuLatitudeEigenerStandort = locationManager.location!.coordinate.latitude
let fullCordinateEigenerStandort = "\(neuLatitudeEigenerStandort),\(neuLongitudeEigenerStandort)"
let ownMarker = GMSMarker()
ownMarker.iconView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
ownMarker.iconView?.backgroundColor = .green
ownMarker.position = CLLocationCoordinate2D(latitude: neuLatitudeEigenerStandort, longitude: neuLongitudeEigenerStandort)
ownMarker.title = "Eigene Position"
ownMarker.snippet = "GPS"
ownMarker.icon = GMSMarker.markerImage(with: .blue)
ownMarker.map = mapView
}

swift SceneKit calculate node angle

i trying to add a node (pin) to sphere node (when taping on sphere node), but can't correctly calculate an angle, can u help me pls ?
private func addPinToSphere(result: SCNHitTestResult) {
guard let scene = SCNScene(named: "art.scnassets/tree.scn") else { return }
guard let treeNode = scene.rootNode.childNode(withName: "Trunk", recursively: true) else { return }
let x = CGFloat(result.worldCoordinates.x)
let y = CGFloat(result.worldCoordinates.y)
treeNode.position = result.worldCoordinates
treeNode.eulerAngles = SCNVector3((x) * .pi / CGFloat(180), 0, (y - 90) * .pi / CGFloat(180)) // y axis is ignorable
result.node.addChildNode(treeNode)
}
when run code i have this
but want like this
You can do it similar to this code. This is a missile launcher, but it's basically the same thing. Your pin = my fireTube, so create a base node, then add a subnode with your materials to it and rotate it into place. You'll have to experiment with where to place the tube initially, but once you get it into the right place the lookat constraint will always point it in the right direction.
case .d1, .d2, .d3, .d4, .d5, .d6, .d7, .d8, .d9, .d10:
let BoxGeometry = SCNBox(width: 0.8, height: 0.8, length: 0.8, chamferRadius: 0.0)
let vNode = SCNNode(geometry: BoxGeometry)
BoxGeometry.materials = setDefenseTextures(vGameType: vGameType)
let tubeGeometry = SCNTube(innerRadius: 0.03, outerRadius: 0.05, height: 0.9)
let fireTube = SCNNode(geometry: tubeGeometry)
tubeGeometry.firstMaterial?.diffuse.contents = data.getTextureColor(vTheme: 0, vTextureType: .barrelColor)
fireTube.position = SCNVector3(0, 0.2, -0.3)
let vRotateX = SCNAction.rotateBy(x: CGFloat(Float(GLKMathDegreesToRadians(-90))), y: 0, z: 0, duration: 0)
fireTube.runAction(vRotateX)
vNode.addChildNode(fireTube)
return vNode
Then set target on your base node and your subnode will rotate with it:
func setTarget()
{
node.constraints = []
let vConstraint = SCNLookAtConstraint(target: targetNode)
vConstraint.isGimbalLockEnabled = true
node.constraints = [vConstraint]
}
In your case, target equals center mass of your sphere and the pin will always point to it, provided you built and aligned your box and pin correctly.

How to draw line node keep same size in camera as Measure App in iPhone?

I try make an AR app as a Measure default app in iPhone. ( I base on project TBXark/Ruler on github)
I draw startNode, endNode, cylinder line, and SCNText. But I can't manage the scale of size, it only readable in near, and so small when measure far plane detect.
I have 2 question:
How to keep size node, cylinder and text same when draw near or far as Measure App
How to draw scntext with background and align the same direction cylinder line as Measure App.
Here is my Line Node class:
class LineNode: NSObject {
let startNode: SCNNode
let endNode: SCNNode
var lineNode: SCNNode?
let textNode: SCNNode
let sceneView: ARSCNView?
// init func
init(startPos: SCNVector3,
sceneV: ARSCNView,
color: (start: UIColor, end: UIColor) = (UIColor(hexCss: 0xF1B426), UIColor(hexCss: 0xD43278)),
font: UIFont = UIFont.boldSystemFont(ofSize: 8) ) {
sceneView = sceneV
let scale = 1 / 400.0
let scaleVector = SCNVector3(scale, scale, scale)
func buildSCNSphere(color: UIColor) -> SCNSphere {
let dot = SCNSphere(radius: 1)
dot.firstMaterial?.diffuse.contents = color
dot.firstMaterial?.lightingModel = .constant
dot.firstMaterial?.isDoubleSided = true
return dot
}
// startNode
startNode = SCNNode(geometry: buildSCNSphere(color: color.start))
startNode.scale = scaleVector
startNode.position = startPos
sceneView?.scene.rootNode.addChildNode(startNode)
// endNode
endNode = SCNNode(geometry: buildSCNSphere(color: color.end))
endNode.scale = scaleVector
// line with start to end
lineNode = CylinderLine(parent: sceneView!.scene.rootNode,
v1: startNode.position,
v2: endNode.position,
radius: 0.001,
radSegmentCount: 16,
color: UIColor.white)
sceneView?.scene.rootNode.addChildNode(lineNode!)
// text show measure line length
let text = SCNText (string: "--", extrusionDepth: 0.1)
text.font = font
text.firstMaterial?.diffuse.contents = UIColor(hexCss: 0xffa800)
text.firstMaterial?.lightingModel = .constant
text.alignmentMode = CATextLayerAlignmentMode.center.rawValue
text.truncationMode = CATextLayerTruncationMode.middle.rawValue
text.firstMaterial?.isDoubleSided = true
textNode = SCNNode(geometry: text)
textNode.scale = SCNVector3(1 / 500.0, 1 / 500.0, 1 / 500.0)
super.init()
}
// update end node realtime
public func updatePosition(pos: SCNVector3, camera: ARCamera?, unit: MeasurementUnit.Unit = MeasurementUnit.Unit.centimeter) -> Float {
// update endNode
let posEnd = updateTransform(for: pos, camera: camera)
if endNode.parent == nil {
sceneView?.scene.rootNode.addChildNode(endNode)
}
endNode.position = posEnd
// caculate new mid
let posStart = startNode.position
let middle = SCNVector3((posStart.x + posEnd.x) / 2.0, (posStart.y + posEnd.y) / 2.0 + 0.002, (posStart.z + posEnd.z) / 2.0)
// update text measure
let text = textNode.geometry as! SCNText
let length = posEnd.distanceFromPos(pos: startNode.position)
text.string = MeasurementUnit(meterUnitValue: length).roundUpstring(type: unit)
text.materials.first?.diffuse.contents = UIColor.orange
textNode.setPivot()
textNode.position = middle
if textNode.parent == nil {
sceneView?.scene.rootNode.addChildNode(textNode)
}
lineNode?.removeFromParentNode()
lineNode = lineBetweenNodeA(nodeA: startNode, nodeB: endNode)
sceneView?.scene.rootNode.addChildNode(lineNode!)
return length
}
}
I use this to update scale if even if you stay far away it still readable
func updateScaleFromCameraForNodes(_ nodes: [SCNNode], fromPointOfView pointOfView: SCNNode , useScaling: Bool){
nodes.forEach { (node) in
//1. Get The Current Position Of The Node
let positionOfNode = SCNVector3ToGLKVector3(node.worldPosition)
//2. Get The Current Position Of The Camera
let positionOfCamera = SCNVector3ToGLKVector3(pointOfView.worldPosition)
//3. Calculate The Distance From The Node To The Camera
let distanceBetweenNodeAndCamera = GLKVector3Distance(positionOfNode, positionOfCamera)
let a = distanceBetweenNodeAndCamera*1.75
if(useScaling) {
node.simdScale = simd_float3(a,a,a)
}
}
SCNTransaction.flush()
}
then called it in the renderer updateAtTime
self.updateScaleFromCameraForNodes(self.nodesAdded, fromPointOfView:
self.cameraNode, useScaling: true)

How can I include all the coordinates in the MapBox by adjusting the zoom level?

The code I have used is:
let bounds = MGLCoordinateBounds(
sw: CLLocationCoordinate2D(latitude: 40.7115, longitude: 10.3725),
ne: CLLocationCoordinate2D(latitude: 40.7318, longitude: 10.4222))
mapView.setVisibleCoordinateBounds(bounds, animated: false)
I have 3 annotation and I want to see the 3 annotaion in the mapBox by adjusting the zoom level. Please help me to find it out.
There is method on MGLMapView that you can use:
func showAllAnnotations() {
guard let annotations = mapView.annotations else { return }
// Either this...
mapView.showAnnotations(annotations, edgePadding: UIEdgeInsets(top: 40, left: 35, bottom: 35, right: 35), animated: true)
// or this.
mapView.showAnnotations(annotations, animated: true)
}

MKMapView (MapKit) - Trying to zoom out to see the entire globe

Edit: I found a solution. MKMapView won't show the entire globe if you build it in Xcode's simulator, but it will if you build it on an actual device.
Existing versions of the question haven't worked - Need Swift 4, Xcode 10 solution:
I'm trying to zoom an MKMapView out to show the entire globe in my app. I can zoom out to see a map of the whole world, but not the entire globe.
​
Here's what I know:
-It has to be satellite, hybrid, satelliteFlyover, or hybridFlyover
-3D must be enabled.
​
Here is what I've tried:
-Adjusting the span of the region (no matter how big I make the span, it never zooms out enough to see the globe)
-Adjusting the altitude of the camera (no matter how high I make it, it never zooms out enough to see the globe)
​
I have googled and stack-overflowed, and I can't find any solutions that work. I am reduced to posting this question myself, violating my lurker principals, but I am totally stuck.
Here is some code I've tried from tutorials, etc. (several attempts commented out):
import UIKit
import MapKit
class ViewController: UIViewController {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
mapView.mapType = .standard
mapView.isPitchEnabled = true
// mapView.showsBuildings = true // displays buildings
let eiffelTowerCoordinates = CLLocationCoordinate2DMake(48.85815, 2.29452)
mapView.region = MKCoordinateRegion(center: eiffelTowerCoordinates, latitudinalMeters: 1000, longitudinalMeters: 100) // sets the visible region of the map
// create a 3D Camera
let mapCamera = MKMapCamera()
mapCamera.centerCoordinate = eiffelTowerCoordinates
mapCamera.pitch = 45
mapCamera.altitude = 50000000 // example altitude
mapCamera.heading = 45
// set the camera property
mapView.camera = mapCamera
// var ausCenter = CLLocationCoordinate2D(latitude: -25.354917, longitude: 134.347407)
// let camera = MKMapCamera(lookingAtCenter: ausCenter, fromDistance: 300, pitch: 10, heading: 0)
// mapView.camera = camera
// var ausCenter = CLLocationCoordinate2D(latitude: -25.354917, longitude: 134.347407)
// var ausSpan = MKCoordinateSpan(latitudeDelta: 5, longitudeDelta: 5)
// var region = MKCoordinateRegion(center: ausCenter, span: ausSpan)
// mapView.setRegion(region, animated: true)
// let camera = MKMapCamera()
// camera.centerCoordinate = mapView.centerCoordinate
// camera.pitch = 90.0
// camera.altitude = 30000000
// camera.heading = 0
// mapView.setCamera(camera, animated: true)
// var ausCenter = CLLocationCoordinate2D(latitude: -25.354917, longitude: 134.347407)
//
//// mapView.setCenter(ausCenter, animated: true)
//
// let span = MKCoordinateSpan(latitudeDelta: 150, longitudeDelta: 150)
// let region = MKCoordinateRegion(center: ausCenter, span: span)
// mapView.setRegion(region, animated: true)
//
// //add an annotation
// let annotation = MKPointAnnotation()
// annotation.coordinate = ausCenter
// annotation.title = "Australia"
// annotation.subtitle = "Details Forthcoming"
// mapView.addAnnotation(annotation)
}
}