2013-12-16 5 views
9

Sto utilizzando le API MapKit di iOS 7 per produrre movimenti di telecamere 3D su una mappa che visualizza un percorso di MKDirectionsRequest. Il percorso è reso da MKOverlayRenderer in questo modo:MKPolylineRenderer produce percorsi irregolari e frastagliati

-(void)showRoute:(MKDirectionsResponse *)response 
{ 
for (MKRoute *route in response.routes) 
{ 
    [self.map 
    addOverlay:route.polyline level:MKOverlayLevelAboveRoads]; 
} 
} 

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id <MKOverlay>)overlay 
{ 
MKPolylineRenderer *renderer = 
[[MKPolylineRenderer alloc] initWithOverlay:overlay]; 
UIColor *mapOverlayColor = [UIColor colorWithRed:((float)22/255.0f) green:((float)126/255.0f) blue:((float)251/255.0f) alpha:0.8]; 
renderer.strokeColor = mapOverlayColor; 
renderer.lineWidth = 13.0; 
return renderer; 
} 

Si sta lavorando bene tranne per un problema. Quando a ingrandire o pan intorno al percorso con MKMapCameras (e senza di loro, se faccio semplicemente così come l'utente), il percorso è frastagliato come mostrato in questa schermata:

screen shot http://f.cl.ly/items/3L0s3h0B1v113y3O2p3K/iPhone%20Dec%2015,%202013,%207%3A26%3A33%20PM.png

Ho testato per vedere se commutazione a MKOverlayLevelAboveLabels fa la differenza ma purtroppo il risultato è stato lo stesso.

Qualcuno ha suggerimenti su come migliorare il rendering? Il passaggio a un percorso geodetico fa la differenza e, in caso affermativo, come potrei implementarlo qui?

+0

commutazione a MKGeodesicPolyline non fa differiscono ENCE ma è creato nello stesso modo come MKPolyline eccezione si chiama polylineWithXXX sul MKGeodesicPolyline tuttavia il renderer è ancora MKPolylineRenderer. – Anna

risposta

2

una volta che la linea viene disegnata sulla mappa, potrebbe non essere rieseguita se l'utente zooma. Oppure, se lo fa, potrebbe essere rieseguito prima che l'utente completi lo zoom. In questo caso la larghezza dopo lo zoom non rifletterà più la larghezza desiderata in metri. Un modo per affrontare questo è di ignorare regionDidChangeAnimated e rimuovere la sovrapposizione e aggiungerlo indietro.

3

sottoclasse MKPolylineRenderer e sovrascrivere applyStrokePropertiesToContext: atZoomScale: in modo che ignora la scala, e disegna linee a larghezza costante:

@interface ConstantWidthPolylineRenderer : MKPolylineRenderer 
@end 

@implementation ConstantWidthPolylineRenderer 

- (void)applyStrokePropertiesToContext:(CGContextRef)context 
          atZoomScale:(MKZoomScale)zoomScale 
{ 
    [super applyStrokePropertiesToContext:context atZoomScale:zoomScale]; 
    CGContextSetLineWidth(context, self.lineWidth); 
} 

@end 

Ora lo usano e ammirare la sua liscia resa:

- (MKOverlayRenderer *)mapView:(MKMapView *)mapView rendererForOverlay:(id<MKOverlay>)overlay 
{ 
    MKPolyline *polyline = (MKPolyline *)overlay; 
    ConstantWidthPolylineRenderer *renderer = [[ConstantWidthPolylineRenderer alloc] initWithPolyline:polyline]; 
    renderer.strokeColor = [UIColor redColor]; 
    renderer.lineWidth = 40; 
    return renderer; 
} 
+1

questa soluzione avrà solo la larghezza della linea statica, quindi ci sarebbe un problema relativo allo zoom- Quando facciamo zoom/pizzico la linea non sarà visibile dopo un livello. – Kumar

1

MKPolylineRenderer è seriamente rotti a non ridisegna offscreen ed ha logica difettosa di calcolo del clipRect che causa artefatti coprilancetta da lasciare sullo schermo. Rimuovere e leggere la sovrapposizione non ha fatto nulla per me. Provare a correggere la larghezza della linea funziona, ma si otterranno comunque problemi di estremità con larghezze di linea più grandi. L'utilizzo dell'opzione roadSizeForZoomLevel non funziona (lineWidth = 0)

Per eliminare gli artefatti endcap che non scompaiono mai ho utilizzato il renderer dall'app di esempio Breadcrumb. Ora ho solo occasionalmente il problema inaccettabile del ridisegno quando si sposta la mappa.

Il renderizzatore breadtrumb penso sia ciò che il PolylineRenderer avrebbe dovuto essere ma qualcuno lo ha rotto. Ma non è ancora chiaro come si possano forzare i ridisegni fuori schermo (non sono un esperto di core graphics, ma dato che l'app per le mappe di Apple non mostra questo comportamento sono sicuro che un guru potrebbe capirlo.

Ad ogni modo se almeno vuoi un renderer che non lascia junk sullo schermo usa il renderizzatore Breadcrumb.Questo è il meglio che ho trovato.Se hai davvero bisogno di un mapkit migliore prova googmaps

0

OK, ho risolto questo problema con il rendering lento di MKPolylineRenderer. renderizzatore da [campione breadcrumb Apple] [1] https://developer.apple.com/library/content/samplecode/Breadcrumb/Introduction/Intro.html#//apple_ref/doc/uid/DTS40010048-Intro-DontLinkElementID_2

Semplicemente invece di aggiungere punti dinamicamente al CrumpPath aggiunge solo il tuo percorso.

In secondo luogo, ora che è stato corretto il rendering difettoso di MKPolylines, è necessario velocizzarlo perché è orribilmente lento.

Vedere questa risposta su Stack Overflow: https://stackoverflow.com/a/28964449/7313127

di adattare questo al "CrumbPathRenderer" basta aggiungere questa obj codice C per la funzione drawMapRect (Questo è solo veloce e sporco)

dispatch_once_t statica onceToken;

dispatch_once (& onceToken,^{

CADisplayLink *displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(update)]; 

    [displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; 
}); 

Creare un metodo di aggiornamento sul renderer che chiama setNeedsDisplay

-() aggiornamento void {

[self setNeedsDisplay]; 

}

Metto anche in renderer.setNeedsDisplay (ma è così probabilmente non è necessario)

func MapView (_ MapView: MKMapView, regionWillChangeAnimated animato: Bool)

{

crumbRenderer.setNeedsDisplay() 

}

Nota importante: Questo renderà senza problemi, ma userà 100 % PROCESSORE. Quindi, per non scaricare la batteria del telefono e la CPU, nel metodo di aggiornamento mantenere una chiamata statica e chiamare setNeedsDisplay ogni tre volte il link di visualizzazione lo chiama. Ricorda che il collegamento di visualizzazione CA è un timer di aggiornamento dell'hardware.

Se si segue questa risposta (frettolosamente composto), che mi ha portato giorni per capire, si utilizzerà circa il 30% della CPU e tuoi sentieri della mappa senza mai presentarsi brutto.

Hey mela, voglio fissare MKMapView?

2

MKPolyline non è il disegno quando lo zoom sta cambiando e quando la regione sta cambiando. Correzione semplice sotto.

public class PolylineRenderer : MKPolylineRenderer { 

    private var displayLink: CADisplayLink! 
    private var ticks = 0 

    override public init(overlay: MKOverlay) { 
     super.init(overlay: overlay) 

     displayLink = CADisplayLink(target: self, selector:#selector(PolylineRenderer._update)) 
    displayLink.add(to: .main, forMode: .commonModes) 
    } 

    func _update() { 
     if ticks < 3 { 
      ticks+=1 
     } else { 
      ticks = 0 
     } 

     if ticks == 0 { 
      self.setNeedsDisplay() 
     } 
    } 

    deinit { 
     if displayLink != nil { 
      displayLink.invalidate() 
     } 
    } 
} 

È piuttosto semplice una volta che ci si accorge che non è abbastanza veloce da dipingere. Saltare 3 tick non uccide la CPU e ciao ai frangenti.

1

Swift 3 soluzione:

creare una sottoclasse di MKPolylineRenderer

class CustomPolyline: MKPolylineRenderer { 

    override func applyStrokeProperties(to context: CGContext, atZoomScale zoomScale: MKZoomScale) { 
     super.applyStrokeProperties(to: context, atZoomScale: zoomScale) 
     UIGraphicsPushContext(context) 
     if let ctx = UIGraphicsGetCurrentContext() { 
      ctx.setLineWidth(self.lineWidth) 
     } 
    } 

} 

poi usarlo nella vostra rendererFor MapKit delegato:

func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer { 
     let renderer = CustomPolyline(overlay: overlay) 
     renderer.strokeColor = UIColor.red 
     renderer.lineWidth = 100 
     return renderer 
} 

vostri polilinee non sarà ri-renderizzare dopo lo zoom evitando così i manufatti

Problemi correlati