2012-01-22 7 views
12

Con mia grande sorpresa ho appena scoperto che drawLine e drawRect non comprendono la posizione finale, cioè .:Canvas 'drawLine e drawRect che non includono la posizione finale?

canvas.drawLine(100, 100, 100, 100, paint); 

o

RectF rect = new RectF(100, 100, 100, 100); 
canvas.drawRect(rect, paint); 

non sarà disegnare nulla.

La mia pittura è definito come segue:

Paint paint = new Paint(); 
paint.setAntiAlias(false); 
paint.setStyle(Paint.Style.FILL); 
return paint; 

Ho cercato di definire la mia pittura come FILL_AND_STROKE, ma non sarebbe di aiuto.

drawPaint di Android() javadoc non elenca nemmeno i parametri stopX e stopY!

Quindi, se voglio tracciare una linea verticale che va esattamente da BeginY a Endy (incluso), devo fare quanto segue:

canvas.drawLine(constX, beginY, constX, endY + 1) 

Si noti che non ho aggiunto 1 al finale Posizione X, solo per terminare Y (xstays uguale a come voglio una linea verticale).

Il mio dispositivo è HTC SENSE.

Modifica: Simon, hai ragione, piuttosto che fare una domanda Ho appena provato a condividere la mia sensazione di sorpresa che Android non fa quello che i suoi doc dicono in un caso così fondamentale come il disegno di base, e assicurati che non ho fatto nessuno stupido errore sulla mia strada.

per farmi più chiaro: javadoc di drawRect dice:

pubblico drawRect void (float a sinistra, galleggiare in alto, galleggiare a destra, galleggiare in basso, Paint Paint)

Disegnare il rettangolo specificato utilizzando il vernice specificata. Il rettangolo verrà riempito o incorniciato in base allo stile nella pittura.

sinistro - Il lato sinistro del rettangolo da disegnare

superiore - Il lato superiore del rettangolo da disegnare

destra - Il lato destro del rettangolo da disegnare

fondo - il lato inferiore del rettangolo da disegnare

vernice - la vernice utilizzata per disegnare il rect

Così, quando si scrive

canvas.drawRect(x1, y1, x2, y2) 

si aspetta un rettangolo i cui angoli sono a (x1, y1); (x1, y2); (x2, y1) e (x2, y2).

Android dice: sbagliato! Saranno a (x1, y1); (x1, y2-1); (x2-1, y1) e (x2-1, y2-1).

Per i più curiosi: impostare il clipping tela:

canvas.clipRect(x1, y1, x2, y2) 

quindi provare a disegnare un punto:

canvas.drawPoint(x1, y1, paint); 

e si ottiene un punto sullo schermo.

quindi provare nell'angolo opposto: appare

canvas.drawPoint(x2, y2, paint); 

nulla. nulla apparirà nelle restanti 2 angoli così:

canvas.drawPoint(x1, y2, paint); 


canvas.drawPoint(x2, y2, paint); 

Ancora non non è sorprendente per voi gente?

Quindi la conclusione è che Android tratta destra e inferiore coordinate esclusivo, nel senso che ad esempio quando si scrive:

canvas.clipRect(x1, y1, x2, y2) 

Otterrete i limiti di ritaglio di (x1, y1, x2 - 1, y2 - 1). Lo stesso vale per ogni metodo che prende a destra e in basso coordinate o oggetti Rect/RectF.

+0

C'è una domanda qui? Se si desidera disegnare un singolo punto, utilizzare: http://developer.android.com/reference/android/graphics/Canvas.html # drawPoint (float,% 20float,% 20android.graphics.Paint) –

+1

Questa non è una domanda, ma sono contento che sia qui. Mi fa risparmiare sperimentando per trovare la risposta a questa altra domanda: http://stackoverflow.com/questions/3063892/canvas-clipping-rect-right-bottom-edge-inclusive –

risposta

5

tua domanda rivela una contraddizione nella API di disegno di Android. Tu dici

Quindi, se voglio tracciare una linea verticale che va esattamente da BeginY a Endy (incluso), devo fare quanto segue:

canvas.drawLine(constX, beginY, constX, endY + 1) 

Si noti che non ho aggiunto 1 alla posizione X finale, solo alla fine Y (xstays lo stesso di cui voglio una linea verticale).

La frase tra parentesi è a mio parere la chiave per comprendere la natura della incoerenza:

È inoltre potrebbe aggiungere 1 alla posizione X finale (! O anche alla posizione di inizio X), e otterresti esattamente la linea identica al pixel. Perché? Poiché l'algoritmo sottostante per la trasformazione da "pixel sinistro in/destra pixel out" -concept al "pixel iniziale e finale in" -concept è il seguente (mostrato solo per x, per y è lo stesso):

int left, top, right, bottom; // left/top pixel inclusive, right/bottom pixel exclusive 
int x1, y1, x2, y2;   // x1/y1 and x2/y2 pixels inclusive 

if (left == right) { 
    x1 = x2 = left; 
} else if (left < right) { 
    x1 = left; 
    x2 = right - 1; 
} else { 
    x1 = right; 
    x2 = left - 1; 
} 

il risultato di questa (nel mio subottimale parere) conversione è che la linea

canvas.drawLine(150, 150, 149, 160, paint); 

è esattamente parallela

canvas.drawLine(150, 150, 151, 160, paint); 

Penso che tutti si aspetterebbero una sorta di V inversa, poiché i punti finali sono separati da almeno 1 pixel (la loro distanza è di due pixel) ei punti di partenza sono identici.

Ma testato su vari dispositivi e versioni di Android, il primo perfettamente linea verticale è nella colonna di pixel 149 e il 2 ° nella colonna 150.

BTW: La trasformazione corretta di utilizzare il "inizio e fine dei pixel in" - concetto è:

int x1, y1, x2, y2;   // x1/y1 and x2/y2 pixels inclusive 

if (x1 <= x2) 
    ++x2; 
else 
    ++x1; 
if (y1 <= y2) 
    ++y2; 
else 
    ++y1; 
canvas.drawLine(x1, y1, x2, y2, paint); 
0

se il vostro sfondo è nero, aggiungere una dichiarazione paint.setColor(Color.RED); e anche si doveva passare RectF rect = new RectF(100, 100, 100, 100); tutti i punti sono gli stessi, provare RectF rect = new RectF(100, 100, 200, 200);

O per la linea canvas.drawLine(10, 10, 10, 10 + 15, paint);

0

tuo rect dovrebbe funzionare pinne, tenta di aggiungere un po 'di sfondo, la tua linea ora ha un pixel, l'ultimo parametro non è la lunghezza, è la posizione finale.

1

La tua domanda è essenzialmente la risposta per this. Grazie.

Io, per esempio, non sono sorpreso da questo, e non lo vorrei in nessun altro modo. Ecco perché:

  • Essa è coerente con java.awt, javax.swing e altre API, così come i principali metodi Java come ad esempio String.substring(int, int) e List<?>.get(int).

  • È compatibile con android.graphics.RectF, che non interessa i pixel: come si può avere una frazione di pixel?

  • L'API è conveniente:

    • Per un rettangolo 40 × 30, istanziare Rect(0, 0, 40, 30)

    • Rect.right - Rect.left == Rect.width()

  • La matematica e la geometria sono facile in questo modo. Ad esempio, se si vuole disegnare un rettangolo centrato all'interno della tela:

 Rect clipBounds = canvas.getClipBounds() 
    int myRectWidth = 20; 
    int myRectHeight = 10; 
    int left = (clipBounds.width() - myRectWidth)/2; 
    int top = (clipBounds.height() - myRectHeight)/2; 
    int right = clipBounds.width() - left; // See how nice this is? 
    int bottom = clipBounds.height() - top; // This wouldn't work if bottom was inclusive! 
    canvas.drawRect(left, top, right, bottom);

L'API è di destra; the API documentation, sfortunatamente, manca solo di dettagli.

(In realtà, è menzionato in the detail for the Rect.contains(int, int) method. E 'un peccato che Google lascia l'API fuori dalla porta senza le variabili di campo si sono documentata, tuttavia.)

+0

Questo comportamento NON è coerente con java.awt. Grafica: se chiami g.drawLine (100, 100, 100, 100) otterrai un singolo pixel disegnato. È anche un comportamento particolarmente stupido in quanto non è possibile tracciare una linea che collega due punti come in ogni altra API 2D e per tracciare correttamente una linea è necessario ricorrere a hack come drawLine (..); drawPoint (.. iniziare ..); drawPoint (.. fine ..). La somiglianza con String e List è irrilevante. – Gilead

+0

@Gilead: Il mio errore: 'java.awt.Graphics.drawRect()' prende un argomento di larghezza e altezza, che si adatta al mio punto sopra, sulla matematica. Sarebbe stato meglio per Android farlo anche in questo modo. E dovremo accettare di non essere d'accordo sul fatto che la coerenza con 'String' e' List' siano rilevanti; Sinceramente troverei la piattaforma Android più facile da usare se non ci fossero così tante incoerenze. –

+0

Questo mi ha aiutato a capire, ma vorrei aggiungere qualcosa: top = Distanza tra la parte inferiore dello schermo e la parte inferiore del rettangolo. fondo = Distanza tra la parte superiore dello schermo e il bordo superiore del rettangolo. sinistra = Distanza tra il bordo sinistro dello schermo e il bordo sinistro del rettangolo. a destra = Distanza tra il bordo destro dello schermo e il bordo destro del rettangolo. – AgentKnopf

Problemi correlati