Need to move to current location in Esri Map when user clicked on current location button. I try to find out but not able to find anything about it for Esri map
I do following code but it is not working
//MARK:
//MARK: current location button clicked
func btnCurLoc_Clicked(_ sender:UIButton)
{
arcGISMapView.locationDisplay.startDataSource()
}
If you want the map to automatically zoom to the current location you need to also set the autopan modeon the locationDisplay
to one of the options here
The most basic centering one is AGSLocationDisplayAutoPanModeRecenter.
swift 4 and Esri ios SDK 100.1 examples;
func locationOpen(){
self.mapView.locationDisplay.start { _ in
let x:Double = (self.mapView.locationDisplay.mapLocation?.x)!
let y:Double = (self.mapView.locationDisplay.mapLocation?.y)!
DispatchQueue.main.async {
if (self.mapView.locationDisplay.started == false)
{
// permission location
}
else
{ // zoom to geometry
self.mapView.setViewpointCenter(AGSPoint(x: x, y: y, spatialReference: AGSSpatialReference.webMercator()), scale: self.mapView.mapScale, completion: nil)
}
}
}
}
Related
I have got the Location function of my app working but I want to add a custom image for the Location Button. How do I go about doing that?
I created a whole new button and made it serve as a location button with this code:
#IBAction func myLocationButton(_ sender: UIButton) {
guard let lat = self.mapView.myLocation?.coordinate.latitude, let lng = self.mapView.myLocation?.coordinate.longitude else {
return
}
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: lng, zoom: 16)
self.mapView.animate(to: camera)
}
The final outcome:
I'm trying to persist a model in ARKit using the ARWorldMap. I can save and load the models, but the orientation I apply to the objects before I save is not persisted with the object.
What I'm currently doing
Objects are saved and loaded:
/// - Tag: GetWorldMap
#objc func saveExperience(_ button: UIButton) {
sceneView.session.getCurrentWorldMap { worldMap, error in
guard let map = worldMap
else { self.showAlert(title: "Can't get current world map", message: error!.localizedDescription); return }
// Add a snapshot image indicating where the map was captured.
guard let snapshotAnchor = SnapshotAnchor(capturing: self.sceneView) else {
fatalError("Can't take snapshot")
}
map.anchors.append(snapshotAnchor)
do {
let data = try NSKeyedArchiver.archivedData(withRootObject: map, requiringSecureCoding: true)
try data.write(to: self.mapSaveURL, options: [.atomic])
DispatchQueue.main.async {
self.loadExperienceButton.isHidden = false
self.loadExperienceButton.isEnabled = true
}
} catch {
fatalError("Can't save map: \(error.localizedDescription)")
}
}
}
/// - Tag: RunWithWorldMap
#objc func loadExperience(_ button: UIButton) {
/// - Tag: ReadWorldMap
let worldMap: ARWorldMap = {
guard let data = mapDataFromFile
else { fatalError("Map data should already be verified to exist before Load button is enabled.") }
do {
guard let worldMap = try NSKeyedUnarchiver.unarchivedObject(ofClass: ARWorldMap.self, from: data)
else { fatalError("No ARWorldMap in archive.") }
return worldMap
} catch {
fatalError("Can't unarchive ARWorldMap from file data: \(error)")
}
}()
// Display the snapshot image stored in the world map to aid user in relocalizing.
if let snapshotData = worldMap.snapshotAnchor?.imageData,
let snapshot = UIImage(data: snapshotData) {
self.snapshotThumbnail.image = snapshot
} else {
print("No snapshot image in world map")
}
// Remove the snapshot anchor from the world map since we do not need it in the scene.
worldMap.anchors.removeAll(where: { $0 is SnapshotAnchor })
let configuration = self.defaultConfiguration // this app's standard world tracking settings
configuration.initialWorldMap = worldMap
sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
isRelocalizingMap = true
virtualObjectAnchor = nil
}
Rotation:
#objc func didRotate(_ gesture: UIRotationGestureRecognizer) {
sceneView.scene.rootNode.eulerAngles.y = objectRotation
gesture.rotation = 0
}
And then it's rendered:
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard anchor.name == virtualObjectAnchorName else {
return
}
// save the reference to the virtual object anchor when the anchor is added from relocalizing
if virtualObjectAnchor == nil {
virtualObjectAnchor = anchor
}
node.addChildNode(virtualObject)
}
How can I do this?
How can I go about doing this? I have tried multiple solutions, but the orientation is never kept. It loads the object at the correct position, but rotation and scaling is never kept, even if I apply it to the rootnode. The only option I can see is to also store the transform as a seperate data object, and load that and apply it. But seems like it should be possible to store this data with the object.
Apple Documentation for ARWorldMap shows that the properties for an ARWorldMap class are:
When you archive a world map, these are the only information that get saved. Any information about the nodes added to the anchors during the session (e.g. changing node scale and orientation) are not saved along with the world map during the archiving.
I remember watching a WWDC session where they demoed a multiplayer AR game called SwiftShot where players hit different objects with balls. They provided the source code and I noticed they used a custom ARAnchor subclass called BoardAnchor which they used to store additional information in the anchor class such as the size of the game board.
See: SwiftShot: Creating a Game for Augmented Reality.
You can use the same approach to store, for example, the scale and orientation of a node, so that when you unarchive the world map and it get's relocalized, you can use ARSCNViewDelegate's renderer(_:didAdd:for:) to resize and scale the node based on the information stored in your custom ARAnchor.
I'm implementing a custom style for my google maps view for a bus transit app I'm developing in XCode 9 w/ Swift 4. Whenever I load a map view, it always takes a little less than a second to load the custom style and I'm not sure what's causing this to happen.
Here's the effect I'm describing:
As you can see, the tan background is the default style for google's mapview, and it's visible for only a small period of time.
Here's my code that implements the map view:
class StopPredictionVC: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
setUpMapView()
}
private func setUpMapView() {
let stopLatitude = Double(stop!.lat)
let stopLongitude = Double(stop!.lon)
let camera = GMSCameraPosition.camera(withLatitude: stopLatitude!, longitude: stopLongitude!, zoom: 16.4)
let frame = CGRect(x: 0, y: 0, width: self.view.bounds.width, height: self.view.bounds.height)
mapView = GMSMapView.map(withFrame: frame, camera: camera)
let nightModeEnabled = APIWrapper.sharedInstance.settings.nightMode!
if nightModeEnabled {
mapView.mapStyle(withFilename: "nightStyle", andType: "json")
} else {
mapView.mapStyle(withFilename: "mapStyle", andType: "json")
}
let marker = GMSMarker()
marker.icon = #imageLiteral(resourceName: "marker")
marker.appearAnimation = .pop
marker.position = CLLocationCoordinate2D(latitude: stopLatitude!, longitude: stopLongitude!)
marker.title = "Bus Stop Name"
marker.snippet = "Example description"
marker.map = mapView
buildRoute(routePath: routeConfig!.path)
view.addSubview(mapView)
}
}
extension GMSMapView {
func mapStyle(withFilename name: String, andType type: String) {
do {
if let styleURL = Bundle.main.url(forResource: name, withExtension: type) {
self.mapStyle = try GMSMapStyle(contentsOfFileURL: styleURL)
} else {
NSLog("Unable to find style.json")
}
} catch {
NSLog("One or more of the map styles failed to load. \(error)")
}
}
}
buildRoute(routePath:) is a function that builds the blue colored path on the road if anyone was wondering.
Obviously this isn't a huge bug, but it's quite frustrating to see every time I load a map view. Anyone see anything in my code that could be causing this?
You call it inside viewWillAppear it has 2 problems , first it's called after viewDidLoad (has some delay) , second it may be called every time the VC is shown such as returning from a push / dismiss Modal
so call setUpMapView inside viewDidLoad
note this buildRoute(routePath: routeConfig!.path) should be in a background queue if it calls any web service or do any long job inside mainQueue
BTW i may also try to load
GMSMapStyle(contentsOfFileURL: styleURL)
in background thread and after load set in mainQueue and that only if using GMSMapStyle is allowed inside a back thread
For an AR experience I'm working on, I want to have a "camera view" that shows annotations based on the user's location. If the user is in a certain area, show the annotation.
I'm able to do something like this using below
extension ViewController: AnnotationManagerDelegate {
func session(_ session: ARSession, cameraDidChangeTrackingState camera: ARCamera) {
print("camera did change tracking state: \(camera.trackingState)")
let annotationLocation = CLLocation()
let point = CGPoint(x: annotationLocation.coordinate.longitude, y: annotationLocation.coordinate.latitude)
let features = mapView.visibleFeatures(at: point);
if let score = features.first(where: { $0.attributes["score"] as! Int >= 5 }) {
// ...
But in my AR view, I want to hide the map - not show it. When I try setting mapView.isHidden = true - the query always fails.
This makes sense because the query is for visible features. How can instead hide the map, but still query tiles for features?
Go into Mapbox Studio https://www.mapbox.com/studio/ and create a new map style and remove all of the layers. You can style a Mapbox map to be a single solid color (land, water, roads, etc.), which is what you need. If you need to toggle between a map and a blank map, simply toggle between styles.
let basicMap = URL(string: "mapbox://styles/mapbox/outdoors-v9")
let blankMap = URL(string: "yourCustomURLFromMapboxStudio")
let mapView = MGLMapView(frame: view.bounds, styleURL: blankMap)
In my camera app, I'm thinking of supporting tap to focus and meter. I have found, as a user, that my finger sometimes accidentally touches the screen somewhere, and it focuses there, so I want to undo it. In my app, I'm thinking of adding a Reset Focus button, which would undo the tap to focus: it would tell iOS to focus whereever it thinks is best (as it was before the tap to focus).
Does iOS offer an API for this?
When the user taps at a point, I can assign to focusPointOfInterest and exposurePointOfInterest in AVCaptureDevice. But I don't see functions clearFocusPointOfInterest() and clearExposurePointOfInterest(). How do I do this?
You need to set the focus to .continousAutoFocus, the exposure to .continuousAutoExposure, and the focal point to CGPoint(x:0.5,y:0.5). The following focus and autofocus code works for me.
#IBAction private func doFocusAndExpose(_ gestureRecognizer: UITapGestureRecognizer) {
let devicePoint = previewView.videoPreviewLayer.captureDevicePointConverted(fromLayerPoint: gestureRecognizer.location(in: gestureRecognizer.view))
focus(with: .autoFocus, exposureMode: .autoExpose, at: devicePoint)
}
#IBAction private func doAutofocus(_ gestureRecognizer: UITapGestureRecognizer) {
let devicePoint = CGPoint(x:0.5,y:0.5)
focus(with: .continuousAutoFocus, exposureMode: .continuousAutoExposure, at: devicePoint)
}
private func focus(with focusMode: AVCaptureDevice.FocusMode,
exposureMode: AVCaptureDevice.ExposureMode,
at devicePoint: CGPoint) {
sessionQueue.async {
let device = self.videoDeviceInput.device
do {
try device.lockForConfiguration()
if device.isFocusPointOfInterestSupported && device.isFocusModeSupported(focusMode) {
device.focusPointOfInterest = devicePoint
device.focusMode = focusMode
}
if device.isExposurePointOfInterestSupported && device.isExposureModeSupported(exposureMode) {
device.exposurePointOfInterest = devicePoint
device.exposureMode = exposureMode
}
device.unlockForConfiguration()
} catch {
print("Could not lock device for configuration: \(error)")
}
}
}