ios - Centering MKMapView on spot N-pixels below pin -
want center mkmapview on point n-pixels below given pin (which may or may not visible in current maprect).
i've been trying solve using various plays -(cllocationcoordinate2d)convertpoint:(cgpoint)point tocoordinatefromview:(uiview *)view
no success.
anyone been down road (no pun intended)?
the easiest technique shift map down, 40% coordinate
be, taking advantage of span
of region
of mkmapview
. if don't need actual pixels, need move down cllocationcoordinate2d
in question near top of map (say 10% away top):
cllocationcoordinate2d center = coordinate; center.latitude -= self.mapview.region.span.latitudedelta * 0.40; [self.mapview setcentercoordinate:center animated:yes];
if want account rotation , pitch of camera, above technique may not adequate. in case, could:
identify position in view want shift user location;
convert
cllocation
;calculate distance of current user location new desired location;
move camera distance in direction 180° current heading of map's camera.
e.g. in swift 3, like:
var point = mapview.convert(mapview.centercoordinate, topointto: view) point.y -= offset let coordinate = mapview.convert(point, tocoordinatefrom: view) let offsetlocation = coordinate.location let distance = mapview.centercoordinate.location.distance(from: offsetlocation) / 1000.0 let camera = mapview.camera let adjustedcenter = mapview.centercoordinate.adjust(by: distance, at: camera.heading - 180.0) camera.centercoordinate = adjustedcenter
where cllocationcoordinate2d
has following extension
:
extension cllocationcoordinate2d { var location: cllocation { return cllocation(latitude: latitude, longitude: longitude) } private func radians(from degrees: cllocationdegrees) -> double { return degrees * .pi / 180.0 } private func degrees(from radians: double) -> cllocationdegrees { return radians * 180.0 / .pi } func adjust(by distance: cllocationdistance, @ bearing: cllocationdegrees) -> cllocationcoordinate2d { let distanceradians = distance / 6_371.0 // 6,371 = earth's radius in km let bearingradians = radians(from: bearing) let fromlatradians = radians(from: latitude) let fromlonradians = radians(from: longitude) let tolatradians = asin( sin(fromlatradians) * cos(distanceradians) + cos(fromlatradians) * sin(distanceradians) * cos(bearingradians) ) var tolonradians = fromlonradians + atan2(sin(bearingradians) * sin(distanceradians) * cos(fromlatradians), cos(distanceradians) - sin(fromlatradians) * sin(tolatradians)) // adjust tolonradians in range -180 +180... tolonradians = fmod((tolonradians + 3.0 * .pi), (2.0 * .pi)) - .pi let result = cllocationcoordinate2d(latitude: degrees(from: tolatradians), longitude: degrees(from: tolonradians)) return result } }
so, camera pitched , @ heading other due north, moves user's location (which centered, lower crosshair is) 150 pixels (where upper crosshair is), yielding like:
obviously, should conscious degenerate situations (e.g. you're 1 km south pole , try shift map 2 km meters; you're using camera angle pitched far desired screen location past horizon; etc.), practical, real-world scenarios, above might sufficient. obviously, if don't let user change pitch of camera, answer easier.
original answer: moving annotation n
pixels
if have cllocationcoordinate2d
, can convert cgpoint
, move x pixels, , convert cllocationcoordinate2d
:
- (void)movecenterbyoffset:(cgpoint)offset from:(cllocationcoordinate2d)coordinate { cgpoint point = [self.mapview convertcoordinate:coordinate topointtoview:self.mapview]; point.x += offset.x; point.y += offset.y; cllocationcoordinate2d center = [self.mapview convertpoint:point tocoordinatefromview:self.mapview]; [self.mapview setcentercoordinate:center animated:yes]; }
you can call by:
[self movecenterbyoffset:cgpointmake(0, 100) from:coordinate];
unfortunately, works if coordinate
visible before start, might have go original coordinate first, , adjust center.
Comments
Post a Comment