2012-01-22 13 views
12

Trước sự ngạc nhiên của tôi, tôi vừa phát hiện ra rằng DrawLine và drawRect không bao gồm các vị trí kết thúc, tức là .:Bản vẽ và drawRine của Canvas không bao gồm vị trí kết thúc?

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

hoặc

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

sẽ không rút ra bất cứ điều gì.

sơn My được định nghĩa như sau:

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

tôi đã cố gắng xác định sơn của tôi như FILL_AND_STROKE, nhưng nó sẽ không giúp đỡ.

drawPaint() javadoc của Android thậm chí không liệt kê các thông số stopX và stopY!

Vì vậy, nếu tôi muốn vẽ một đường thẳng đứng mà đi chính xác từ beginY để Endy (bao gồm), tôi phải làm như sau:

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

Chú ý rằng tôi không thêm từ 1 tới kết thúc X vị trí, chỉ để kết thúc Y (xstays giống như tôi muốn một đường thẳng đứng).

Thiết bị của tôi là HTC SENSE.

Chỉnh sửa: Simon, bạn nói đúng, thay vì hỏi một câu hỏi tôi vừa cố gắng chia sẻ cảm giác ngạc nhiên rằng Android không làm những gì tài liệu của nó nói trong trường hợp cơ bản như bản vẽ cơ bản và đảm bảo rằng tôi đã không làm bất kỳ sai lầm ngu ngốc trên con đường của tôi.

Để làm cho bản thân mình rõ ràng hơn: javadoc drawRect cho biết:

public void drawRect (float trái, nổi hàng đầu, nổi đúng, trôi nổi dưới, sơn sơn)

Vẽ hình chữ nhật quy định sử dụng sơn được chỉ định. Hình chữ nhật sẽ được điền hoặc đóng khung dựa trên Kiểu trong sơn.

trái - Phía bên trái của hình chữ nhật được vẽ

đầu - Phía trên cùng của hình chữ nhật được vẽ

đúng - Phía bên phải của hình chữ nhật được vẽ

đáy - phía dưới cùng của hình chữ nhật được vẽ

sơn - các sơn dùng để vẽ rect

Vì vậy, khi viết

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

Bạn mong đợi một hình chữ nhật có góc là (x1, y1); (x1, y2); (x2, y1) và (x2, y2).

Android nói: sai! Họ sẽ ở (x1, y1); (x1, y2-1); (x2-1, y1) và (x2-1, y2-1).

Đối với những người tò mò: thiết lập cắt vải:

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

Sau đó cố gắng vẽ một điểm:

canvas.drawPoint(x1, y1, paint); 

và bạn sẽ có được một điểm trên màn hình.

Sau đó thử ở góc đối diện:

canvas.drawPoint(x2, y2, paint); 

gì xuất hiện. sẽ không có gì xuất hiện ở 2 góc còn lại:

canvas.drawPoint(x1, y2, paint); 


canvas.drawPoint(x2, y2, paint); 

Vẫn không có gì đáng ngạc nhiên cho bạn?

Vì vậy, kết luận là Android xử lý đúngdưới cùng tọa độ là độc quyền, có nghĩa là ví dụ: khi viết:

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

Bạn sẽ nhận được các giới hạn cắt (x1, y1, x2 - 1, y2 - 1). Điều tương tự cũng xảy ra với mọi phương thức có các đối tượng phảidưới cùng hoặc Đối tượng/đối tượng.

+0

Có câu hỏi nào ở đây không? Nếu bạn muốn vẽ một điểm thì hãy sử dụng: http://developer.android.com/reference/android/graphics/Canvas.html # drawPoint (float,% 20float,% 20android.graphics.Paint) –

+1

Đây không phải là một câu hỏi, nhưng tôi rất vui vì nó ở đây. Tiết kiệm cho tôi làm thử nghiệm để tìm ra câu trả lời cho câu hỏi khác này: http://stackoverflow.com/questions/3063892/canvas-clipping-rect-right-bottom-edge-inclusive –

Trả lời

5

Câu hỏi của bạn cho thấy một sự mâu thuẫn trong API vẽ của Android. Bạn nói

Vì vậy, nếu tôi muốn vẽ một đường thẳng đứng mà đi chính xác từ beginY để Endy (bao gồm), tôi phải làm như sau:

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

Chú ý rằng tôi không thêm 1 đến vị trí X kết thúc, chỉ để kết thúc Y (xstays giống như tôi muốn một đường thẳng đứng).

Câu trong ngoặc là theo ý kiến ​​của tôi chìa khóa để hiểu được bản chất của sự mâu thuẫn:

Bạn cũng có thể thêm 1 đến vị trí X kết thúc (! Hoặc thậm chí đến đầu vị trí X), và bạn sẽ nhận được chính xác đường tương tự pixel-wise. Tại sao vậy? Vì thuật toán cơ bản để chuyển đổi từ "pixel bên trái vào/điểm ảnh bên trái" của Android "-concept thành" pixel bắt đầu và kết thúc trong "-concept như sau (chỉ hiển thị cho x, y y giống nhau):

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; 
} 

kết quả của việc này (theo ý kiến ​​của phụ tối ưu của tôi) chuyển đổi là dòng

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

được chính xác song song với

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

Tôi nghĩ mọi người sẽ mong đợi loại V ngược lại, vì các điểm kết thúc được phân cách bởi ít nhất 1 pixel (khoảng cách của chúng là hai điểm ảnh) và các điểm bắt đầu giống hệt nhau.

Nhưng thử nghiệm trên các thiết bị khác nhau và các phiên bản Android, 1 cách hoàn hảo đường thẳng đứng là trong cột điểm ảnh 149 và thứ 2 trong cột 150.

BTW: Việc chuyển đổi đúng để sử dụng "bắt đầu và kết thúc điểm ảnh trong" - khái niệm là:

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

nếu nền của bạn là màu đen, thêm một tuyên bố paint.setColor(Color.RED); và cũng có thể bạn đã vượt qua RectF rect = new RectF(100, 100, 100, 100); tất cả các điểm là cùng, hãy thử RectF rect = new RectF(100, 100, 200, 200);

HOẶC cho dòng canvas.drawLine(10, 10, 10, 10 + 15, paint);

0

rect bạn nên làm việc vây, cố gắng thêm một số nền, dòng của bạn bây giờ là một điểm ảnh, hai tham số cuối cùng không phải là chiều dài, đó là sự kết thúc của nó.

1

Câu hỏi của bạn về cơ bản là câu trả lời cho this. Cảm ơn bạn.

Tôi, vì một, không ngạc nhiên bởi điều này và sẽ không muốn bất kỳ cách nào khác. Dưới đây là lý do:

  • Nó phù hợp với java.awt, javax.swing và các API, cũng như cốt lõi phương pháp Java như String.substring(int, int)List<?>.get(int).

  • Nó tương thích với android.graphics.RectF, không quan tâm đến pixel — làm cách nào bạn có thể có một phần nhỏ pixel?

  • API là thuận tiện:

    • Đối với một hình chữ nhật 40 × 30, nhanh chóng Rect(0, 0, 40, 30)

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

  • Các toán và hình học được dễ dàng hơn theo cách này. Ví dụ, nếu bạn muốn vẽ một hình chữ nhật làm trung tâm trong vải:

 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);

API là đúng; the API documentation, thật không may, chỉ thiếu chi tiết.

(Trên thực tế, nó được đề cập trong the detail for the Rect.contains(int, int) method. Nó không may rằng Google cho phép các API ra khỏi cửa mà không có sự biến lĩnh vực mình được ghi nhận, tuy nhiên.)

+0

Hành vi này KHÔNG phù hợp với java.awt. Đồ họa - nếu bạn gọi g.drawLine (100, 100, 100, 100), bạn sẽ nhận được một pixel được vẽ. Nó cũng là một hành vi đặc biệt ngu ngốc vì bạn không thể vẽ một đường kết nối hai điểm giống như trong mỗi API 2D khác và để vẽ một đường thẳng, bạn phải sử dụng để hack như drawLine (..); drawPoint (.. bắt đầu ..); drawPoint (.. kết thúc ..). Tương tự như Chuỗi và Danh sách không liên quan. – Gilead

+0

@Gilead: Lỗi của tôi: 'java.awt.Graphics.drawRect()' lấy một đối số chiều rộng và chiều cao, phù hợp với điểm của tôi ở trên, về toán học. Nó có thể đã được tốt hơn cho Android để làm điều đó theo cách đó, quá. Và chúng ta sẽ đồng ý không đồng ý về việc liệu sự nhất quán với 'Chuỗi' và' Danh sách' có liên quan hay không; Tôi thành thật tìm thấy nền tảng Android dễ dàng hơn để làm việc nếu không có quá nhiều mâu thuẫn. –

+0

Điều này đã giúp tôi hiểu, nhưng tôi muốn thêm một cái gì đó: top = Khoảng cách giữa dưới cùng của màn hình và dưới cùng của hình chữ nhật. bottom = Khoảng cách giữa đầu màn hình và cạnh trên của hình chữ nhật. left = Khoảng cách giữa cạnh trái của màn hình và cạnh trái của hình chữ nhật. right = Khoảng cách giữa cạnh phải của màn hình và cạnh phải của hình chữ nhật. – AgentKnopf