I would like to draw a route using Mapbox. I've tried adding polyline:
let polyline = MGLPolyline(coordinates: &coords, count: UInt(coords.count))
mapView?.add(polyline)
But it keeps drawing on top of street names. How can I move below street names?
If you add an MGLPolyline directly to an MGLMapView, you’re adding it as an annotation; currently the Mapbox iOS SDK only supports adding annotations on top of everything.
However, the SDK has a separate API called runtime styling, which allows you to place data under or above any layer of the map. From this example, you can use code like the following to add a shape source to the map’s style and a line layer that renders the shape source. (MGLLineStyleLayer is reminiscent of MapKit’s MKOverlayPathRenderer.)
let routeFeature = MGLPolylineFeature(coordinates: &coords, count: UInt(coords.count))
let routeSource = MGLShapeSource(identifier: "route", shape: routeFeature, options: nil)
mapView.style?.addSource(routeSource)
let routeLayer = MGLLineStyleLayer(identifier: "route", source: routeSource)
// Set properties like lineColor, lineWidth, lineCap, and lineJoin
mapView.style?.insertLayer(routeLayer, above: roadLayer) // or below: labelLayer
The code above works if you know the identifier of the road or label layer. You can obtain the identifier by opening the style in Mapbox Studio. For something more robust, you could iterate over all the layers in the map style, inserting the route layer above the first non-symbol layer you find. (Labels and icons are rendered using symbol layers.)
for layer in style.layers.reversed() {
if !(layer is MGLSymbolStyleLayer) {
style.insertLayer(routeLayer, above: layer)
break
}
}
By the way, if you need more than just a route line, Mapbox Navigation SDK for iOS comes with a complete turn-by-turn navigation UI, including a map that’s optimized for displaying a route.
Related
I'm using the following code to see when markers enter the screen :
let visibleRegion = mapView.projection.visibleRegion()
let bounds = GMSCoordinateBounds(region: visibleRegion)
for i in stride(from: 0, to: markers.count, by: 1){
let marker = markers[i]
if bounds.contains(marker.position) {
print("Is present on screen")
print(marker.position)
} else {
// Marker not on the screen
}
}
This works and when I scroll the map on top of a marker I get the printout.
I've got 30k markers that I'm needing to potentially place onto the map. The markers show up at different zoom levels, and only need to be loaded once the user is able to see them.
The marker is a rounded image view, so as you an imagine loading 30 thousand pictures into a map is a huge task.
I have JSON that I am loading in the Lon/Lat/ImageURL.
Do I need to deinit markers as they leave the screen and init them as they come onto the screen? Are google map annotations reused like a tableview cell? Should I only create the marker once a location from my JSON is in the bounds of the map, or can I create them and only add them to the map once they're in the bounds? What sort of optimization tools should I use?
Thanks for any tips here
Important: please note that this question is about VECTOR map. Not height map.
I'm trying to implement Vector displacement in Scenekit, as described on apple presentation:
https://www.youtube.com/watch?v=uli814Qugm8&app=desktop
Apple presentation on Scenekit vector displacement
My code is:
material?.diffuse.contents = UIImage(named: "\(materialFilePrefix)-albedo.jpg")
material?.displacement.contents = UIImage(named: "(materialFilePrefix)-displacement.exr")
material?.displacement.textureComponents = .all
My Xcode project:
enter image description here
But I don't get the displacement... Anything wrong with the code?
From checking out SCNMaterial’s header and the presentation, it looks like you might need to enable tessellation on your node’s geometry for displacement to work. That’d look like this:
let tessellator = SCNGeometryTesselator()
tessellator.edgeTessellationFactor = 2 // may not need this line (default is 1), or may need to set it higher to get a smooth result
tessellator.edgeTessellationFactor = 2 // ditto
sphereNode.geometry?.tessellator = tessellator
I just started looking at ARKitExample from apple and I am still studying. I need to do like interactive guide. For example, we can detect something (like QRCode), in that area, can I show with 1 label ?
Is it possible to add custom view (like may be UIVIew, UIlabel) to surface?
Edit
I saw some example to add line. I will need to find how to add additional view or image.
let mat = SCNMatrix4FromMat4(currentFrame.camera.transform)
let dir = SCNVector3(-1 * mat.m31, -1 * mat.m32, -1 * mat.m33)
let currentPosition = pointOfView.position + (dir * 0.1)
if button!.isHighlighted {
if let previousPoint = previousPoint {
let line = lineFrom(vector: previousPoint, toVector: currentPosition)
let lineNode = SCNNode(geometry: line)
lineNode.geometry?.firstMaterial?.diffuse.contents = lineColor
sceneView.scene.rootNode.addChildNode(lineNode)
}
}
I think this code should be able to add custom image. But I need to find the whole sample.
func updateRenderer(_ frame: ARFrame){
drawCameraImage(withPixelBuffer:frame.capturedImage)
let viewMatrix = simd_inverse(frame.came.transform)
let prijectionMatrix = frame.camera.prijectionMatrix
updateCamera(viewMatrix, projectionMatrix)
updateLighting(frame.lightEstimate?.ambientIntensity)
drawGeometry(forAnchors: frame.anchors)
}
ARKit isn't a rendering engine — it doesn't display any content for you. ARKit provides information about real-world spaces for use by rendering engines such as SceneKit, Unity, and any custom engine you build (with Metal, etc), so that they can display content that appears to inhabit real-world space. Thus, any "how do I show" question for ARKit is actually a question for whichever rendering engine you use with ARKit.
SceneKit is the easy out-of-the-box, no-additional-software-required way to display 3D content with ARKit, so I presume you're asking about that.
SceneKit can't render a UIView as part of a 3D scene. But it can render planes, cubes, or other shapes, and texture-map 2D content onto them. If you want to draw a text label on a plane detected by ARKit, that's the direction to investigate — follow the example's, um, example to create SCNPlane objects corresponding to detected ARPlaneAnchors, get yourself an image of some text, and set that image as the plane geometry's diffuse contents.
Yes you can add custom view in ARKit Scene.
Just make image of your view and add it wherever you want.
You can use following code to get image for UIView
func image(with view: UIView) -> UIImage? {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0.0)
defer { UIGraphicsEndImageContext() }
if let context = UIGraphicsGetCurrentContext() {
view.layer.render(in: context)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
return nil
}
I have created NMAMapView object using storyboard and I am using the reference of that NMAMapView object in view controller code and added markers to it. In this case, the markers are visible on the screen
To set the zoom automatically I created NMABoundingBox, added markers to it and then set the bounding box to NMAMapView using setBoundingBox::withAnimation method.
But if I create the NMAPMapView object dynamically, set the view controller view frame to the NMAMapView and add it as a subview to view controller view and then added the markers to the view, then the markers are visible out of the map. I have to do a manual zoom out on the map to see the markers.
I have also tried using setBoundingBox::insideRect::withAnimation method of NMAMapView for the above dynamically created map scenario to set the zoom automatically. But the maps is being pointed to some random portion of the world with some inappropriate zoom.
Need resolution for this issue. Thanks
In my case, I see a marker on the map only if some image is set as an icon of NMAMapMarker. Looks like there's no default marker available.
let coordinates: NMAGeoCoordinates = ...
let image: UIImage = ...
let marker = NMAMapMarker(geoCoordinates: coordinates, image: image)
or
let coordinates: NMAGeoCoordinates = ...
let marker = NMAMapMarker(geoCoordinates: coordinates)
let image: UIImage = ...
marker.icon = NMAImage(uiImage: image)
Hopefully, it helps.
Creating an iOS mapping app using Skobbler's SDK (installed via CocoaPods. v2.5). I'm adding annotations to my Skobbler mapview, using custom views for my pins instead of using one of Skobbler's defaults. My pins will just be colored circles.
The problem is that my circles seem to be drawn with borders, but they shouldn't be.
My code is similar to the following:
let pin = UIView()
pin.layer.frame = CGRectMake(0, 0, 18, 18)
pin.layer.backgroundColor = UIColor.lightGrayColor().CGColor
pin.layer.cornerRadius = diameter/2
//Just for good measure... NO BORDER
pin.layer.borderColor = UIColor.clearColor().CGColor
pin.layer.borderWidth = 0
let annotation = SKAnnotation()
annotation.annotationView = SKAnnotationView(view: pin, reuseIdentifier: "viewID")
annotation.identifier = 1234
annotation.location = CLLocationCoordinate2DMake(44.1234, -111.1234)
mapView.addAnnotation(annotation, withAnimationSettings: animationSettings)
How can I avoid having borders drawn around my pins?
Turns out that a light border is added by the framework, and I'm told there is nothing I can do.
Here's a snippet from an email from Skobbler:
"Indeed we can see a light border (see attach)- that’s the way is
generated at our core level and we cannot change this. We’ve checked
also if we set a simple view on the map and if we add that view to an
annotation indeed the border appears (screenshot 2)."