2012-11-30 8 views
8

Voglio convertire un percorso tracciato in un oggetto riempito. (Programmazione, in JavaScript.)Come ottenere il contorno di un tratto?

La linea è solo una semplice linea curva, una sequenza di coordinate. Posso rendere questa linea come un percorso e dargli un tratto di un certo spessore ... ma sto cercando di ottenere una forma piena piuttosto che una linea tratteggiata, così posso apportare ulteriori modifiche su di essa, come ad esempio la deformazione così, il "tratto" risultante potrebbe variare in spessore o avere parti personalizzate tagliate fuori da esso (nessuna di queste cose è possibile con un vero tratto SVG, per quanto ne so).

Così sto cercando di manualmente 'addensare' una linea in una forma solida. Non riesco a trovare alcuna funzione che funzioni in questo modo: ho esaminato i documenti di D3.js e Raphaël, ma senza fortuna. Qualcuno sa di una biblioteca/funzione che farebbe questo?

O, ancora meglio: se qualcuno potrebbe spiegare a me la teoria geometria a come avrei potuto fare manualmente questo compito, prendendo la lista della linea coordinate di che ho e elaborazione di un nuovo percorso che effettivamente 'colpi' di esso, che sarebbe fantastico Per dirla in altro modo, che cosa fa il browser quando dici di tracciare un tracciato - come fa a capire quale forma dovrebbe essere il tratto?

risposta

3

C'è stata una domanda simile di recente: svg: generate 'outline path'

Tutto sommato, questo è un compito non banale. Come accennato nella mia risposta alla domanda collegata, PostScript ha un comando per generare percorsi che producono sostanzialmente lo stesso risultato di un tratto, chiamato strokepath. Se si guarda a ciò che Ghostscript sputa quando si esegue il codice che ho postato alla domanda collegata, è piuttosto brutto. E anche Inkscape non fa davvero un buon lavoro. Ho appena provato Path => Outline in Inkscape (penso che sia quello che dovrebbero dire le didascalie in inglese), e ciò che è venuto fuori non sembra proprio lo stesso del percorso tracciato.

Il caso "più semplice" sarebbe se si avessero solo polilinee, poligoni o percorsi non autointersecanti che non contengono curve perché, in generale, non è possibile tracciare curve di Bézier "parallele" esatte a destra e il lato sinistro di una curva Bézier non banale che delimitarebbe l'area segnata - è matematicamente inesistente. Quindi dovresti approssimarlo in un modo o nell'altro. Per i segmenti di linea retta, la soluzione esatta può essere trovata relativamente facilmente.

Il modo classico di rendere tracciati vettoriali con curve/archi a loro è quello di approssimare il tutto con un polilinea sufficientemente liscia. De Casteljau's Algorithm viene in genere utilizzato per trasformare curve di Bézier in segmenti di linea. (Questo è anche ciò che emerge quando usi il comando strokepath in Ghostscript.) Puoi quindi trovare delimitare i segmenti di linea paralleli, ma devi unirli correttamente, usando le giuste regole di linejoin e miterlimit. Certo, non dimenticare la linecap.

Ho pensato che i percorsi che si intersecano potrebbero essere complicati perché potresti ottenere aree vuote all'interno del percorso, vale a dire che l'area di attraversamento di un percorso nero potrebbe diventare bianca. Questo potrebbe non essere un problema per i percorsi aperti quando si utilizza nonzero winding rule, ma sarei cauto in merito. Per i percorsi chiusi, probabilmente è necessario che i due percorsi "delimitano" vengano eseguiti con orientamento opposto. Ma non sono sicuro in questo momento se questo copre davvero tutte le potenziali insidie.

Scusate se causo molta confusione con questo e forse non sono di grande aiuto.

1

Il metodo standard è l'algoritmo Tiller-Hanson (Offset di profili bidimensionali, 1984, che irritantemente non è in linea gratuitamente) che crea una buona approssimazione.L'idea è che, poiché i punti di controllo di ciascuna curva di Bezier si trovano su linee tangenti all'inizio e alla fine della curva, una curva parallela avrà la stessa proprietà. Quindi compensiamo l'inizio e la fine della curva, quindi troviamo nuovi punti di controllo usando queste intersezioni. Tuttavia, ciò dà risultati molto negativi per curve acuminate, quindi il primo passo è bisecare la curva originale, che è molto facile da fare per le curve di Bezier, fino a quando non si trasforma in un angolo sufficientemente piccolo.

Altri perfezionamenti sono necessari per trattare (i) intersezioni tra i paralleli, all'interno di ciascun vertice; (ii) inserire un arco di un cerchio per riempire lo spazio all'esterno di ciascun vertice; e (iii) l'aggiunta di tappi terminali - quadrato, testa a testa o circolare.

Tiller-Hanson è difficile da implementare, ma c'è una buona implementazione open source nella libreria FreeType, in ftstroke.c (http://git.savannah.gnu.org/cgit/freetype/freetype2.git/ albero/src/base/ftstroke.c).

Mi dispiace dire che può essere piuttosto difficile integrare questo codice, ma l'ho usato correttamente e funziona bene.

1

Questa pagina ha un tutorial abbastanza buono sulle curve di Bezier in generale con una bella sezione sulle curve di offset.

http://pomax.github.io/bezierinfo/

Un metodo meno preciso ma forse più veloce può essere trovato qui.

http://seant23.wordpress.com/2010/11/12/offset-bezier-curves/

Non c'è una risposta matematico, poiché la curva parallelo ad una curva di Bezier non è generalmente una curva di Bezier. La maggior parte dei metodi ha casi degenerati, specialmente quando si tratta di una serie di curve.

Pensa a una curva semplice come a una senza punti problematici. Nessuna cuspide, nessun loop, nessuna inflessione e idealmente una curvatura strettamente crescente. Traccia tutte le curve iniziali in queste semplici curve. Trova tutte le curve di offset di queste curve semplici. Rimetti insieme tutte le curve di offset occupandoti di spazi e intersezioni. Le curve quadratiche sono molto più trattabili se hai la possibilità di lavorare con loro.

Penso che la maggior parte dei browser faccia qualcosa di simile a processingjs, in quanto hanno casi degenerati anche con curve quadratiche. Ad esempio, guarda la curva 200,300 719,301 500,300 con uno spessore di 100 o più.