2010-12-28 9 views
12

Un breve background: Sto lavorando a un'applicazione di disegno basata sul Web e uno degli strumenti che sto implementando è una matita spessa 1 pixel. Lo strumento consente all'utente di tracciare linee alias 1pz sul quadro.Disegno di linee con alias da 1 pixel di spessore in tempo reale

Per determinare dove l'utente sta disegnando nell'area di disegno, le coordinate del mouse vengono monitorate. Se si tiene premuto il mouse 1, il pixel su cui si trova il cursore cambierà. Essenzialmente funziona come lo strumento matita in Photoshop.

NOTA: l'algoritmo di Bresenham non funzionerà per questa situazione. Il mio input viene inviato in tempo reale, quindi non sto disegnando una riga da P0 a P1 in cui la distanza tra P0 e P1 è di molti pixel. In generale, P1 è un vicino di P0.

Il problema che sto avendo è che le mie linee risultanti non hanno un peso 1px perfettamente pulito. Ecco un esempio:

Line comparison

Si noti che entrambe le linee sono disegnate a mano, per cui v'è una certa varianza. La cosa interessante è che Photoshop è in grado di creare una rappresentazione 1px molto più pulita della linea che disegno. Il motivo per cui la mia linea sembra più sporca a causa di questo:

Photoshop's line

My line

Quando si disegna con lo strumento nella mia domanda, i pixel rossi sono riempiti In Photoshop, i pixel rossi non lo sono. compilato. Ciò ha senso perché per spostarsi da un dato pixel a, ad esempio, al suo vicino sud-est, il vicino est o sud sarà probabilmente passato sopra. C'è una possibilità estremamente sottile che il cursore superi lo esattamente nell'angolo del vicino sud-est, evitando il disegno del pixel rosso, ma questo di solito non accade.

Quindi, la domanda che mi rimane è come Photoshop sia in grado di saltare i pixel rossi visualizzati nelle mie linee. L'unica cosa che potevo pensare era aspettare che due pixel venissero messi in coda prima di tracciarne uno, così saprei se un "corner-neighbour" è passato sopra. In quel caso non disegnerei il primo dei due pixel perché sarebbe equivalente a un pixel rosso nel mio diagramma. Ciò comporta il rischio di non disegnare un pixel previsto se l'utente disegna un pixel, sposta il cursore di un pixel verso sud e quindi di un pixel verso est. Entrambi i pixel dovrebbero essere disegnati, ma l'algoritmo direbbe il contrario.

Qualche idea? In che modo Photoshop può gestire questo problema?

+0

Cosa succede quando si muove velocemente il mouse? Salta i pixel? –

+0

@Hans Passant Sì, quando disegno velocemente ottengo linee simili a quelle che produce Photoshop. Ciò che è strano è che non è necessario disegnare rapidamente in Photoshop per saltare quei pixel indesiderati. – Xenethyl

+0

Memorizza i punti del mouse in una polilinea. Non aggiunge un nuovo segmento ad esso quando può semplicemente estendere il precedente. –

risposta

3

Originale: dai un'occhiata all'algoritmo di riga di Bresenham. Si può facilmente esteso riguardante levigante ecc

Edit: Per quanto riguarda lo sviluppo della questione e le discussioni (soprattutto i commenti qui sotto), vorrei estrarre alcuni punti interessanti: strumento matita di Photoshop fa anche disegnare molto simili linee con pixel "est" e "sud-est", anche se il mouse viene spostato relativamente lentamente fornendo così molti campioni per tutti quei pixel. Non appena il mouse viene spostato più velocemente, la traiettoria non fornisce campioni per tutti i pixel direttamente vicini. Il risultato sarebbe quindi la linea spessa di 1 pixel desiderata. In conclusione, notiamo: non c'è "magia" dietro lo strumento matita di Photoshop; sembra solo scansionare meno campioni. Per dettagli vedi discussioni/commenti sotto.

+0

Sono d'accordo; cercare l'algoritmo di Xiaolin Wu in wikipedia per esempio. – WebMonster

+0

@Flinsch In realtà sto usando l'algoritmo di Bresenham per colmare le lacune nel mio input da utente. Quelle parti della linea vengono fuori bene. Il problema che sto descrivendo si sta verificando perché il cursore dell'utente passa sopra un pixel cardinale mentre si sposta verso un vicino adiacente. Idealmente, voglio saltare il pixel cardinale se un vicino ad angolo è il prossimo pixel che l'utente voleva disegnare. – Xenethyl

+2

@WebMonster Xiaolin L'algoritmo di linea di Wu è per disegnare linee anti-alias. – Xenethyl

5

La differenza tra le due linee è fondamentalmente che Photoshop è ri-valutando il pixel n-1 disegnato DOPO disegnando il pixel n, e cancellazione se dà positivo con uno dei seguenti maschere:

x 1 x  x 1 x 
1 o x or x o 1 
x x x  x x x 

o

x x x  x x x 
1 o x or x o 1 
x 1 x  x 1 x 

x = non importa
o = Il pixel n-1
1 = pixel evidenziati dopo il disegno n pixel

.210

o scritta come logica:

pixel Supponiamo che n-1 si trova ad un [i, j], così, dopo aver segnato il pixel n, controllare:

If ((a[i-1,j ]==1 && a[i ,j-1]==1) || 
    (a[i-1,j ]==1 && a[i ,j+1]==1) || 
    (a[i ,j-1]==1 && a[i+1,j ]==1) || 
    (a[i ,j+1]==1 && a[i+1,j ]==1)) 
Then 
    Unmark a[i,j]; 

si può decidere il vostro attirare la vostra la linea ha ritardato un pixel solo per non mostrare i pixel "in via di estinzione" (anche se dubito che sarà visibile a quella scala).

alt text
.

+0

Grazie per l'aiuto con una delle mie domande di nuovo. L'ambiente che sto gestendo in questo modo favorisce molto una soluzione preventiva rispetto a una reattiva ("cancellare" un pixel è un processo implicito, specialmente quando si considera il disegno su qualcosa che già esiste). Il problema qui è decidere se un pixel dovrebbe * veramente * essere cancellato. Cosa accadrebbe se l'utente intendesse disegnare la forma a "L" nel diagramma? L'algoritmo lo cancellerebbe ciecamente. Trovo difficile credere che l'implementazione di Adobe sia follemente complicata con la previsione e il tracciamento della traiettoria ... – Xenethyl

+0

@Xenethyl Se l'utente è schizzinoso riguardo agli angoli in Photoshop, probabilmente utilizzerà un altro strumento e non una matita a mano libera. Ma sono d'accordo sul fatto che PShop potrebbe avere algoritmi migliori lì. Per quanto riguarda il disegno su qualcosa di preesistente, ho pensato di avere un comando "annulla", quindi Unmarking! = Cancellare. –

+0

Concordato sul fatto che le preferenze dell'utente siano un po 'presenti. Sfortunatamente, questo problema è al centro del mio algoritmo di disegno per qualsiasi altro strumento di disegno/pittura (es. Matita con punte diverse, pennello, ecc.). Ogni linea disegnata dall'utente viene trattata come una riga 1px e se viene usato un suggerimento (ad esempio una stella), viene semplicemente stampato su ogni coordinata di pixel. Undo non è ancora implementato, ma il processo sarebbe coinvolto in modo simile. La modifica dei dati dei pixel richiede purtroppo una copia, una lettura, una modifica e una scrittura in questo ambiente. – Xenethyl

0

Immagino che tu abbia finalmente risolto la tua domanda (sono passati 6 anni ...), ma volevo solo dire che la tua applicazione sembra funzionare meglio di Photoshop in questo caso particolare. Anche se penso di sapere quale fosse il tuo obiettivo (evitando quei cluster di pixel), lo "spessore costante" è meglio raggiunto con la tua App (nonostante quei raggruppamenti indesiderati), mentre Photoshop crea un modello di "corda per salsicce" che può essere più intelligente, ma non così larghezza-costante e, quindi, non così "reale". È probabilmente dovuto a una diversa gestione dei valori decimali (arrotondamento) e alla selezione dei pixel da riempire o saltare. Ma ancora, questo è un vecchio argomento.