Jak skutecznie narysować CGPath na CATiledLayer? Obecnie sprawdzam, czy obwiednia kafelka przecina obwiednię ścieżki w następujący sposób:

-(void)drawLayer:(CALayer*)layer inContext:(CGContextRef)context {
    CGRect boundingBox = CGPathGetPathBoundingBox(drawPath);
    CGRect rect = CGContextGetClipBoundingBox(context);

    if( !CGRectIntersectsRect(boundingBox, rect) )
        return;

    // Draw path...
}

Nie jest to zbyt wydajne, ponieważ drawLayer:inContext: jest wywoływane wielokrotnie z wielu wątków i powoduje wielokrotne rysowanie ścieżki.

Czy jest lepszy, bardziej wydajny sposób na to zrobić?

8
JWood 3 luty 2012, 16:55

2 odpowiedzi

Najlepsza odpowiedź

Najprostszą opcją jest narysowanie krzywej na duży obraz, a następnie ułożenie go obok siebie. Ale jeśli układasz kafelki, prawdopodobnie oznacza to, że obraz byłby zbyt duży lub po prostu narysowałeś ścieżkę, prawda?

Więc prawdopodobnie musisz podzielić swoją ścieżkę. Najprostszym podejściem jest podzielenie go element po elemencie za pomocą CGPathApply. Dla każdego elementu możesz sprawdzić jego pole ograniczające i określić, czy ten element mieści się w twoich granicach. Jeśli nie, po prostu śledź ostatni punkt końcowy. Jeśli tak, przejdź do ostatniego widzianego punktu końcowego i dodaj element do nowej ścieżki dla tego kafelka. Kiedy skończysz, każda płytka narysuje własną ścieżkę.

Technicznie rzecz biorąc, „rysujesz” tutaj rzeczy, które wykraczają poza twoje granice (takie jak linia, która rozciąga się poza kafelek), ale jest to znacznie tańsze niż się wydaje. Core Graphics bardzo łatwo przycina pojedyncze elementy. Celem jest uniknięcie obliczania elementów, których w ogóle nie ma w polu ograniczającym.

Pamiętaj, aby buforować wynikową ścieżkę. Nie musisz obliczać ścieżki dla każdej płytki; tylko te, które rysujesz. Ale unikaj przeliczania go za każdym razem, gdy kafelek jest dobierany. Za każdym razem, gdy dane ulegną zmianie, zrzuć pamięć podręczną. Jeśli istnieje bardzo duża liczba płytek, możesz również użyć NSCache, aby zoptymalizować to jeszcze lepiej.

5
Rob Napier 15 luty 2012, 18:01

Nie pokazujesz, gdzie powstaje ścieżka. Jeśli to możliwe, możesz spróbować zbudować ścieżkę w metodzie -drawLayer:inContext:, tworząc tylko jej część potrzebną do rysowania kafelka.

Podobnie jak w przypadku wszystkich problemów z wydajnością, powinieneś użyć Instruments, aby sprofilować swój kod i dowiedzieć się, gdzie dokładnie znajdują się wąskie gardła. Czy już tego próbowałeś, a jeśli tak, to co znalazłeś?

Na marginesie, czy istnieje powód, dla którego używasz CGPath zamiast UIBezierPath? Z Dokumentacja Apple:

Do tworzenia ścieżek w systemie iOS zaleca się używanie UIBezierPath zamiast funkcji CGPath, chyba że potrzebujesz niektórych funkcji, które zapewnia tylko Core Graphics, takich jak dodawanie wielokropków do ścieżek. Aby uzyskać więcej informacji na temat tworzenia i renderowania ścieżek w UIKit, zobacz „Rysowanie kształtów przy użyciu ścieżek Beziera”.

2
Andrew Madsen 14 luty 2012, 01:10