Tilt map in Mapkit programmatically using Swift - ios

I'd like to tilt the map at startup. (Same as the user does when scrolling up or down with 2 fingers)
Is this possible using Swift?

MKMapView Class Reference : http://goo.gl/djHXPn
Look at the camera property :
A camera object defines a point above the map’s surface from which to view the map. Applying a camera to a map has the effect of giving the map a 3D-like appearance. You can use a camera to rotate the map so that it is oriented to match the user’s heading or to apply a pitch angle to tilt the plane of the map.
Assigning a new camera to this property updates the map immediately and without animating the change. If you want to animate changes in camera position, use the setCamera:animated: method instead.
You must not set this property to nil. To restore the map to a flat appearance, apply a camera with a pitch angle of 0, which yields a camera looking straight down onto the map surface.
Try to create and set a camera (animated or not).
Edit :
I tried myself. Here is an example of how to use it :
let userCoordinate = CLLocationCoordinate2D(latitude: 58.592725, longitude: 16.185962)
let eyeCoordinate = CLLocationCoordinate2D(latitude: 58.571647, longitude: 16.234660)
let mapCamera = MKMapCamera(lookingAtCenterCoordinate: userCoordinate, fromEyeCoordinate: eyeCoordinate, eyeAltitude: 400.0)
let annotation = MKPointAnnotation()
annotation.setCoordinate(userCoordinate)
mapView.addAnnotation(annotation)
mapView.setCamera(mapCamera, animated: true)
You'll have to find your right eyeCoordinate depending on your location and tilt effect you want to have.

Swift 4
This is an easier way: you can set distance, pitch and heading:
let mapCamera = MKMapCamera(lookingAtCenter: userCoordinate, fromDistance: 10000, pitch: 65, heading: 0)
map.setCamera(mapCamera, animated: true)

Related

How to place a 3D model from a local file path on gps coordinates?

I'm using Project Dents ARKit + CoreLocation Pod to place a 3D model from a local file path at specific gps coordinates in the real world. I'm able to see my 3d model in AR. However, it seems like it's not fixed to the coordinates since the model moves with the camera and doesn't stick to the given gps location when I move away.
Here's what I've tried
sceneLocationView.run()
view?.addSubview(sceneLocationView)
// Config
self.sceneLocationView.autoenablesDefaultLighting = true
self.sceneLocationView.showsStatistics = true
// Coordinates of where the model should be placed
let coordinate = CLLocationCoordinate2D(latitude: arConfig?.positionValue?.latitude ?? 0, longitude: arConfig?.positionValue?.longitude ?? 0)
let location = CLLocation(coordinate: coordinate, altitude: -1.5)
// Load model
let model = MDLAsset(url: (self.arConfig?.models.first!)!)
model.loadTextures()
let modelNode: SCNNode = SCNNode(mdlObject: model.object(at: 0))
modelNode.scale = SCNVector3(x: 15, y: 15, z: 15)
// Rotate
let orientation = modelNode.orientation
var glQuaternion = GLKQuaternionMake(orientation.x, orientation.y, orientation.z, orientation.w)
let multiplier = GLKQuaternionMakeWithAngleAndAxis(90, 0, 1, 0)
glQuaternion = GLKQuaternionMultiply(glQuaternion, multiplier)
modelNode.orientation = SCNQuaternion(x: glQuaternion.x, y: glQuaternion.y, z: glQuaternion.z, w: glQuaternion.w)
// Create location node and add the model node to it
let locationNode = LocationNode(location: location)
locationNode.addChildNode(modelNode)
// Add the location node for a given location which includes the model to the scene
sceneLocationView.addLocationNodeWithConfirmedLocation(locationNode: locationNode)
Can anyone lead me in the right direction here?
The ARGeoAnchor seems very suited to your needs.
A geographic anchor (also known as location anchor) identifies a specific area in the world that the app can refer to in an AR experience. As a user moves around the scene, the session updates a location anchor’s transform based on the anchor’s coordinate and the device’s compass heading.
init(name: String, coordinate: CLLocationCoordinate2D, altitude: CLLocationDistance)
Initializes a named location anchor with the given coordinates and altitude.
Your Location Node is missing following configuration:
locationNode.continuallyUpdatePositionAndScale = true
locationNode.continuallyAdjustNodePositionWhenWithinRange = true
locationNode.scaleRelativeToDistance = true
This will allow the node to actually reduce its scale when it's further away or upscale it when it's closer.
In addition, adding the SCNNode containing the 3D model to the child nodes of your location node does not work because the child nodes do not inherit the configuration of its parent. To fix that the 3D model node has to be either of type LocationNode or of a type which inherits from LocationNode.

Get google map currently rotated angle by user in iOS

I am using google map in the application. When I do not rotate map everything works fine. But when I rotate map I am getting problem as shown in image. To solve that I need to get the google map currently rotated angle by the user. I need to get this so that I can place the marker back on the map at the same angle. Currently my map angle after rotation and my overlay seems to be different after placing plan image on map even when I am getting correct top left & bottom right corner coordinates.
My code
let topCoordinate = CLLocationCoordinate2D(latitude: topLattitude, longitude: topLongitude)//top
let bottomCoordinate = CLLocationCoordinate2D(latitude: bottomLattitude, longitude: bottomLongitude)//bottom
overlayBounds = GMSCoordinateBounds(coordinate: topCoordinate, coordinate:
bottomCoordinate)
let overlay = GMSGroundOverlay(bounds: overlayBounds, icon: planImage)
overlay.map = mapView
GMSMapViewDelegate
Bearing of the camera, in degrees clockwise from true north.
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
print(position.bearing)
}
I have solved my problem by changing the overlay method as
let zoomLevel = (object["image_zoom_level"] as? NSString)?.doubleValue
let overlay = GMSGroundOverlay(position: centreCoordinate, icon: planImage, zoomLevel: CGFloat(zoomLevel!))
overlay.map = mapView
if let angle = (object["rotation_angle"] as? NSString)?.doubleValue{
overlay.bearing = angle
}
Instead of using Overlay bounds I have just used center coordinate and placed overlay image using image zoom level and rotation angle. By this, my image is placing in proper angle and at a proper place. This works fine if the Image size is correct as you want place and the center point is accurate and precise.

How to move annotation with animation in mapbox map?

I am using mapbox map in my iOS app. I added annotation in mapbox map by using this class MGLPointAnnotation.
Now the problem is i am unable to change its location. This is how i changing annotation location. But it is not moving. I need to remove first old one and again need to add new annotation but i don't want to do this.Please let me know how can i do this.
car.coordinate = CLLocationCoordinate2D(latitude: lat, longitude: lng)
I want the movement of annotation when location changed of annotation with smooth animation.
Also when there is a change in location i'm changing center of my mapbox map with camera. Let me know i am doing right or not.
// Optionally set a starting point.
bMbMapView.setCenter(cord, zoomLevel: 7, direction: bearing, animated: true)
bMbMapView.setDirection(bearing, animated: true)
// Create a camera that rotates around the same center point, rotating 180°.
// `fromDistance:` is meters above mean sea level that an eye would have to be in order to see what the map view is showing.
let camera = MGLMapCamera(lookingAtCenter: cord, fromDistance: 1000, pitch: 7, heading: 90)
// Animate the camera movement over 5 seconds.
bMbMapView.setCamera(camera, withDuration: 1, animationTimingFunction: CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut))
A MGLAnnotationView is a UIView, so you should be able to animate changes with Core Animation: https://github.com/mapbox/mapbox-gl-native/issues/8378#issuecomment-287910768
Another option is to use a style source and layer, then update the source using a timer. This would likely be less smooth than using an animated annotation view.

MKMapView not staying rotated

Easy to reproduce:
- create a new project
- put an MKMapView on the screen
- try to rotate it with 2 fingers
It rotates a little and stops, and when you release the fingers, it goes back to the original position.
How do I make it stay rotated?
And rotate as much as I want?
I'm using latest iOS (8.something), iPhone 6 simulator and Swift.
I figured out the problem.
Actually there is no solution, what was happening is that MKMapView does not allow you to stay rotated if the map region is too big.
If you zoom in you can rotate normally.
Please try this
Gloabally declare :
let regionRadius: CLLocationDistance = 1000
And in viewdidload:
let initialLocation = CLLocation(latitude: 21.282778, longitude: -157.829444)
centerMapOnLocation(initialLocation)
And then create a helper class:
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
mapview.setRegion(coordinateRegion, animated: true)
}
Try with rotateEnabled property of MKMapView :
rotateEnabled -
A Boolean value indicating whether the map camera’s heading information is used.
Declaration
SWIFT
var rotateEnabled: Bool
When this property is set to YES and a valid camera is associated with the map, the camera’s heading angle is used to rotate the plane of the map around its center point. When this property is set to NO, the camera’s heading angle is ignored and the map is always oriented so that true north is situated at the top of the map view.
You have to override CLLocationManager.didUpdateLocations (part of CLLocationManagerDelegate) to get notified when the location manager retrieves the current location and don't do anything there:
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
// Don't do update the map to the new location
}

How to zoom in or out a MKMapView in Swift?

Objective
I need my app to zoom in or out a MKMapView.
Code
I thought of animating the value of the altitude of a MKMapCamera. Though, this doesn't zoom in or out the map.
let mapCamera = MKMapCamera()
mapCamera.altitude = 1000000
mapView.camera = mapCamera
UIView.animateWithDuration(10, delay: 0., options: UIViewAnimationOptions.CurveLinear, animations: {
mapCamera.altitude = 6000000
}, completion: {(finished: Bool) in
})
mapView.camera = mapCamera
Question
How do I zoom in or out a MKMapView? Are there any other ways to do so?
Here is an extension based on kevins answer https://stackoverflow.com/a/20129379/1488696
With it you'll be able to zoom in and out as required
extension MKMapView {
// delta is the zoom factor
// 2 will zoom out x2
// .5 will zoom in by x2
func setZoomByDelta(delta: Double, animated: Bool) {
var _region = region;
var _span = region.span;
_span.latitudeDelta *= delta;
_span.longitudeDelta *= delta;
_region.span = _span;
setRegion(_region, animated: animated)
}
}
Use it like so: myMapView.setZoomByDelta(0.5, animated: true)
MKMapCamera is used for 3D maps. So its likely not what you're looking for
Apple Docs
An MKMapCamera object describes a virtual camera that you use to define the appearance of the map. A camera object creates a virtual viewpoint above the map surface and affects how the map renders its tiles and other content. You use a camera object to specify the location of the camera on the map, the compass heading that corresponds to the camera’s viewing direction, the pitch of the camera relative to the map perpendicular, and the camera’s altitude above the map. These factors let you create a map view that is not just flat but offers a more 3D-like experience."
Use the method setRegion:animated:. It takes an MKCoordinateRegion parameter. The region includes a span, which determines the range of north-to-south latitude shown on the screen.

Resources