2009-08-03 22 views
23

Attualmente sto usando l'algoritmo di Bresenham per disegnare linee ma sono (ovviamente) di un pixel di spessore. La mia domanda è qual è il modo più efficace per tracciare linee di spessore arbitrario?come posso creare una linea di spessore arbitrario usando Bresenham?

Il linguaggio che sto usando è C.

+1

Rimodificato "linguaggio indipendente" dal momento che il linguaggio di implementazione non è veramente rilevante. –

+0

ecco una domanda SO correlata: http://stackoverflow.com/questions/101718/drawing-a-variable-width-line-in-opengl-no-gllinewidth –

+0

@banister: hai qualche demo da condividere con noi? – sdkie

risposta

10

Penso che il modo migliore è quello di disegnare un rettangolo, piuttosto che una linea dal momento che una linea con larghezza è un oggetto bidimensionale. Tring per disegnare un insieme di linee parallele per evitare il sovrascrittura (per ridurre la larghezza di banda di scrittura) e il underdraw (pixel mancanti) sarebbe piuttosto complesso. Non è troppo difficile calcolare i punti d'angolo del rettangolo dal punto iniziale e finale e la larghezza.

+2

Non ho trovato la soluzione. Puoi elaborare per favore. – sdkie

9

Ecco uno paper and Delphi implementation di una versione modificata dell'algoritmo di Bresenham per disegnare linee addensate.

Si potrebbe anche voler dare un'occhiata a , una libreria per il rendering software di alta qualità e ad alte prestazioni di grafica 2D. Dai uno sguardo allo demo page per avere un'idea di cosa può fare.

4

Alcuni itinerari semplice da usare:

  1. per qualsiasi larghezza di n dove n è dispari. per ogni punto p tracciato anche i punti sopra/sotto per n/2 (se la linea è> angolo di 45 gradi disegna invece da lato a lato).
    • non proprio una linea corretta dello spessore corretto, più simile a una penna corsiva, ma molto veloce.
  2. per il punto iniziale p (x, y) selezionare i punti t0 eb in modo che siano centrati su p ma n pixel separati. per il punto finale fare lo stesso risultante in t1 b1. Disegna linee da t0 -> t1, t1-> b1, b1 -> t0, b0 -> t1. Compila il rettangolo risultante.
    • Il trucco qui è raccogliere i punti in modo che appaiano ortogonali alla direzione del percorso.
  3. per ogni punto p sulla linea anziché disegnare un punto disegnare un cerchio.
    • Questo ha il vantaggio di rendere i punti finali "puliti" indipendentemente dall'orientamento.
    • non ci dovrebbe essere bisogno di rendere qualsiasi cerchi in solido tranne il primo.
    • piuttosto lento
2

Presumo che si elabora campate orizzontali da una linea di delimitazione all'altro, e calcolare il valore x di ciascuna delle linee con il metodo di Bresenham come si va (in una singola ciclo continuo).

Non ho provato.

I punti finali possono richiedere un po 'di attenzione, per non sembrare stranamente troncati.

+0

sì questa era la strategia che avevo in mente anche io e sono d'accordo sul fatto che gli end-point avranno bisogno di un po 'di riflessione. – horseyguy

0

Per la mia applicazione di stampante termica incorporata, utilizzando l'algoritmo di Bresenham, la linea era troppo sottile. Non ho GL o niente di speciale. Ho finito per decrementare semplicemente il valore Y e disegnare più linee sotto il primo. Ogni numero di spessore ha aggiunto un'altra linea. Molto veloce da implementare e realizzato per i risultati desiderati, dalla stampa bitmap monocromatica a quella termica.

+0

Mi è piaciuta la tua idea, come hai testato/calcolato la distanza desiderata tra le linee in modo da imitare lo spessore? è stato per tentativi ed errori? –

+0

Ogni punto ha un altro punto sotto di esso ... nessun calcolo; la linea era visibilmente più spessa. Ho finito per utilizzare 3 linee, ognuna con un valore Y inferiore rispetto al precedente. Qualsiasi y inferiore al minimo è stato modificato in Y minimo. –

+0

Scusa se mi manco confuso riguardo il controllo dello spessore e il controllo della larghezza della linea. –

15

Prendere un altro ciclo di Bresenham e utilizzarlo per modificare la posizione iniziale e finale della linea originale in direzione rettangolare. Il problema è trovare il giusto punto di partenza e non disegnare alcun pixel due volte (o saltare un pixel) mentre si disegna la riga successiva.

Il codice C funzionante e testato è disponibile da Github C code.

Qui una pagina di test che include alcune righe di esempio create da questo codice. I pixel neri sono i punti di partenza dell'algoritmo.

Test page with bresenham lines with different thickness

+2

Se potessi, risparmierei di più questa risposta, perché è l'unica che indirizza il lettore verso un'implementazione pulita e funzionante in C, proprio come richiesto dall'OP. – msteiger

+0

È così intelligente! – hexaflexagonal

1

http://members.chello.at/~easyfilter/bresenham.html

L'esempio in fondo a questo link è javascript, ma dovrebbe essere abbastanza facile da adattare a C. Si tratta di un algoritmo di antialiasing abbastanza semplice per disegnare le linee di spessore variabile.

7

Per la massima precisione, e anche una buona prestazione per linee più spesse, in particolare, è possibile disegnare la linea come un poligono. Qualche pseudo codice:

draw_line(x1,y1,x2,y2,thickness) 
    Point p[4]; 
    angle = atan2(y2-y1,x2-x1); 
    p[0].x = x1 + thickness*cos(angle+PI/2); 
    p[0].y = y1 + thickness*sin(angle+PI/2); 
    p[1].x = x1 + thickness*cos(angle-PI/2); 
    p[1].y = y1 + thickness*sin(angle-PI/2); 
    p[2].x = x2 + thickness*cos(angle-PI/2); 
    p[2].y = y2 + thickness*sin(angle-PI/2); 
    p[3].x = x2 + thickness*cos(angle+PI/2); 
    p[3].y = y2 + thickness*sin(angle+PI/2); 
    draw_polygon(p,4) 

E facoltativamente si può disegnare un cerchio in corrispondenza di ciascun punto finale.

+0

In un modo questo sta riducendo il problema a uno più complesso. Per farlo funzionare (in Python), ho dovuto aggiustare le cose, però: a) scambiare il peccato e il cos. b) invece di moltiplicare per lo spessore, moltiplicare per lo spessore/2.0. – Ant6n

+0

@ Ant6n Penso che sia * l'angolo * che è sbagliato. Questo dovrebbe essere "atan2 (y2-y1, x2-x1)'. – colinta

+0

@colina Risolto il problema. – Fabel

0

Ero di fronte allo stesso problema qualche tempo fa. Sulla base di questo codice paper, ho creato un'implementazione di riferimento Matlab, che vorrei condividere su GitHub.

1

Lo faccio abbastanza spesso per generare immagini di fibre e sfere per simulazioni di supporti porosi. Ho un modo molto semplice per farlo usando una tecnica di analisi delle immagini molto standard conosciuta come la "trasformazione a distanza". Ciò richiede l'accesso a un pacchetto di analisi delle immagini. Io uso Python con Scipy, quindi questo non è un problema. Ecco una demo per convertire i punti distribuiti in modo casuale in sfere:

import scipy as sp 
import scipy.ndimage as spim 

im1 = sp.rand(100, 100) < 0.995 # Create random points in space 
dt = spim.distance_transform_edt(im1) 
im2 = dt < 5 # To create sphere with a radius of 5 

random seeds, distance map, final spheres

E che è! La trasformazione della distanza può essere lenta per immagini di grandi dimensioni, ma è disponibile una versione efficiente. Ad esempio, ImageJ ha uno parallelizzato. Ovviamente, per creare fibre spesse, basta creare l'immagine di quelle sottili, quindi applicare i passaggi 2 e 3 sopra.

Problemi correlati