I'm showing marker and drawing circle using the same coordinates. Don't know why but my marker is offset a little bit to the top. How do you think what is the problem?
override func viewDidLoad() {
super.viewDidLoad()
let camera = GMSCameraPosition.camera(withLatitude: 37.36, longitude: -122.0, zoom: 13.0)
setupMapWith(cameraPosition: camera)
showMarker(position: camera.target)
circleWith(position: camera.target)
}
func showMarker(position: CLLocationCoordinate2D) {
let marker = GMSMarker()
marker.position = position
marker.title = "Palo Alto"
marker.snippet = "San Francisco"
let markerView = UIView(frame: CGRect(x: 0, y: 0, width: 20, height: 20))
markerView.backgroundColor = .red
marker.iconView = markerView
marker.map = mapView
}
func circleWith(position: CLLocationCoordinate2D) {
let circ = GMSCircle(position: position, radius: 1000)
circ.fillColor = UIColor.MapAreaFilter.areaFilterColor
circ.map = mapView
}
Try setting your marker's groundAnchor property:
marker.groundAnchor = CGPoint(x: 0.5, y: 0.5)
Related
I'm trying to create a map that will show the route of a workout, but I can't find anywhere in MapKit documentation as to how to customize the background, i.e. here I want the map itself to be transparent so that only the route (annotations) are visible. How can I do this?
struct MapOverlay: View {
#ObservedObject var workoutDetailViewModel: WorkoutDetailViewModel
var body: some View {
if let unwrappedWorkoutLocations = workoutDetailViewModel.fullyLoadedWorkout?.workoutLocations {
Map(
coordinateRegion: .constant(
MKCoordinateRegion(
center: unwrappedWorkoutLocations.map {$0.coordinate}.center(), // Use the midpoint of the workout as the centre of the map.
span: MKCoordinateSpan(latitudeDelta: 0.02, longitudeDelta: 0.02)
)
),
annotationItems: unwrappedWorkoutLocations.map {$0.coordinate}
) { routeLocation in
MapAnnotation(coordinate: routeLocation) {
Circle().fill(TrackerConstants.AppleFitnessOrange)
}
}
.cornerRadius(10)
}
}
}
struct MapOverlay_Previews: PreviewProvider {
static var previews: some View {
MapOverlay(workoutDetailViewModel: WorkoutDetailViewModel())
}
}
Don't use MKMapView. You want to take the coordinates and make a UIBezierPath from them, and render that into your own view, or a UIImage. Something like this playground:
import CoreLocation
import MapKit
let myCoords: [CLLocationCoordinate2D] = [
.init(latitude: 42.42, longitude: 42.42),
.init(latitude: 42.43, longitude: 42.425),
.init(latitude: 42.425, longitude: 42.427),
.init(latitude: 42.422, longitude: 42.426),
]
let r = MKPolylineRenderer(polyline: .init(coordinates: myCoords, count: myCoords.count))
let path = r.path!
let bezier = UIBezierPath(cgPath: path)
bezier.apply(.init(scaleX: 0.05, y: 0.05))
let renderer = UIGraphicsImageRenderer(bounds: .init(x: 0, y: 0, width: 640, height: 480))
let image = renderer
.image { context in
let size = renderer.format.bounds.size
UIColor.darkGray.setFill()
context.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))
UIColor.black.setStroke()
bezier.lineWidth = 5
bezier.stroke()
}
I would like to draw a Octagonal shape.
I don't know how to achieve this. Here is my code -
func drawOctagonalShape(){
let camera = GMSCameraPosition.camera(withLatitude: 37.4, longitude:-122.0, zoom: 10)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
mapView.isMyLocationEnabled = true
mapView.settings.myLocationButton = true;
self.view = mapView
// Creates a marker in the center of the map.
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: 37.36, longitude: -122.0)
marker.title = "India"
//marker.snippet = "Malaysia"
marker.map = mapView
let rect = GMSMutablePath()
rect.add(CLLocationCoordinate2D(latitude: 37.36, longitude: -122.0))
rect.add(CLLocationCoordinate2D(latitude: 37.45, longitude: -122.0))
rect.add(CLLocationCoordinate2D(latitude: 37.45, longitude: -122.2))
rect.add(CLLocationCoordinate2D(latitude: 37.36, longitude: -122.2))
// Create the polygon, and assign it to the map.
let polygon = GMSPolygon(path: rect)
polygon.fillColor = UIColor(red: 0.25, green: 0, blue: 0, alpha: 0.05);
polygon.strokeColor = UIColor.init(hue: 210, saturation: 88, brightness: 84, alpha: 1)
//polygon.strokeColor = .black
polygon.strokeWidth = 2
polygon.map = mapView
}
Octagon is basically 8 points distributed equally on a circle. You can create a method like the following:
func generateCircle(around center: CLLocationCoordinate2D, radius: Double, pointCount: Int = 8, rotation: Double = 0) -> [CLLocationCoordinate2D] {
(0..<count).map { index in
let angle = rotation + (Double(index)/Double(pointCount))*Double.pi*2.0
return .init(latitude: center.latitude + cos(angle)*radius, longitude: center.longitude + sin(angle)*radius)
}
}
I hope the code speaks for itself. You would use it in your code like
let rect = GMSMutablePath()
generateCircle(around center: myCenter, radius: someSmallRadius, pointCount: 8, rotation: 0).forEach { coordinate in
rect.add(coordinate)
}
I would expect this to work in most cases. There are 2 potential problems however:
I am unsure how this would behave around edges of both longitude and latitude.
Radius expressed in degrees may be a bit incorrect at some points
Would it not be easier to simply generate an image and place that on your map?
I am trying to compare a saved region with another region, whether it's inside of that region or not. The region is going to be changed each time the user zoom in on the map; when the function below is called:
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated:
Bool) {
You can easily define your own function for checking if an MKCoordinateRegion contains another one. One way to do this is to calculate the min/max latitude and longitudes of the region, then compare all 4 extremities between the 2 regions you want to compare.
extension MKCoordinateRegion {
var maxLongitude: CLLocationDegrees {
center.longitude + span.longitudeDelta / 2
}
var minLongitude: CLLocationDegrees {
center.longitude - span.longitudeDelta / 2
}
var maxLatitude: CLLocationDegrees {
center.latitude + span.latitudeDelta / 2
}
var minLatitude: CLLocationDegrees {
center.latitude - span.latitudeDelta / 2
}
func contains(_ other: MKCoordinateRegion) -> Bool {
maxLongitude >= other.maxLongitude && minLongitude <= other.minLongitude && maxLatitude >= other.maxLatitude && minLatitude <= other.minLatitude
}
}
let largerRegion = MKCoordinateRegion(MKMapRect(x: 50, y: 50, width: 100, height: 100))
let smallerRegion = MKCoordinateRegion(MKMapRect(x: 70, y: 50, width: 30, height: 80))
let otherRegion = MKCoordinateRegion(MKMapRect(x: -100, y: 0, width: 100, height: 80))
largerRegion.contains(smallerRegion) // true
largerRegion.contains(otherRegion) // false
smallerRegion.contains(otherRegion) // false
I'm playing with spriteKit to create a little game and I'm getting blocked trying to draw a cross (like and X) at a point where i've touched the screen. As i want to draw an X I thought in rotate two rectangles, one Pi/4 and the other one -Pi/4.
I've the following code, i've been playing with node position adding 10 or 20px on both axis. But I cannot understand how the rects intersect on their center for create a cross (like an X).
That's the code I have :
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
{
guard let touch = touches.first
else
{
return
}
let location = touch.location(in: self)
let touchedNode = nodes(at: location)
_ = atPoint(location).name
print("PosiciĆ³n touch: \(touchedNode)")
// Draw the cross in the touched point
let redSprite1 = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 10, height: 40))
redSprite1.fillColor = .green
redSprite1.position = CGPoint(x: location.x - 10.0, y: location.y)
redSprite1.zRotation = CGFloat(-Pi/4)
addChild(redSprite1)
// 2
let redSprite2 = SKShapeNode(rect: CGRect(x: 0, y: 0, width: 10, height: 40))
redSprite2.fillColor = .red
redSprite2.position = CGPoint(x: location.x + 10.0, y: location.y)
redSprite2.zRotation = CGFloat(Pi/4)
addChild(redSprite2)
}
I've noted that the rotation is made not from the center of the shape but in their bottom.
Is there any option to rotate a shape or tile from their center ?
Thanks to #bg2b for the solution.
Looking to the apple doc linked on #bg2b answer and applied give the following code.
// 1
let redSprite1 = SKShapeNode(rectOf: CGSize(width: 10.0, height: 40.0))
redSprite1.fillColor = .green
redSprite1.position = CGPoint(x: location.x, y: location.y)
redSprite1.zRotation = CGFloat(-Pi/4)
redSprite1.name = "cruz1"
addChild(redSprite1)
// 2
let redSprite2 = SKShapeNode(rectOf: CGSize(width: 10.0, height: 40.0))
redSprite2.fillColor = .red
redSprite2.position = CGPoint(x: location.x, y: location.y)
redSprite2.zRotation = CGFloat(Pi/4)
redSprite2.name = "cruz2"
addChild(redSprite2)
I got some issue with my GMSMarker it seems its not properly aligned to user. See image below: marker doesn't aligned
How can I align the center to the user location perspective?
Code below:
self.contractorMarker.iconView = self.markerImageView(image: UIImage(named: "contractor-marker")!, size: CGSize(width: 30, height: 30))
CATransaction.begin()
CAAnimation.init().duration = 0.5
self.contractorMarker.position = contractorCoordinate
CATransaction.commit()
self.contractorMarker.map = self.mapView
You can do it with groundAnchor property
self.contractorMarker.groundAnchor = CGPoint(x:0.5, y: 0.5)