Làm thế nào để bạn vẽ một đường thẳng giữa hai điểm trong một bitmap?


17

Tôi đang chơi xung quanh với các bản đồ chiều cao (bitmap), cố gắng tạo một số bản đồ của riêng mình trong trò chơi của mình và để tôi cần thực hiện một số phương pháp vẽ cơ bản. Tôi đã nhanh chóng nhận ra rằng vẽ các đường thẳng không cơ bản như tôi nghĩ.

Thật đơn giản nếu các điểm của bạn chia sẻ tọa độ X hoặc Y hoặc nếu chúng được căn chỉnh để bạn có thể vẽ một đường chéo hoàn hảo. Nhưng trong tất cả các trường hợp khác, nó phức tạp hơn.

Thuật toán nào bạn sử dụng để xác định những pixel nào cần được tô màu để nó trở thành một đường "thẳng"?

Câu trả lời:



21

Thuật toán đường thẳng của Bresenham có thể được sử dụng để xác định điểm nào trong lưới raster để vẽ đồ thị để đạt được xấp xỉ trực quan phù hợp của một đoạn đường.

Thuật toán bao gồm quá trình rasterization của một dòng được xác định bởi điểm gốc và điểm cuối trong một không gian tọa độ trong đó điểm gốc nằm ở phía trên bên trái. Các tọa độ số nguyên được cho là ánh xạ tới các tâm pixel. Đáng chú ý, dạng cơ bản của thuật toán chỉ bao gồm một quãng tám của vòng tròn: dạng mà đường thẳng có tọa độ X và Y tăng nhưng độ dốc âm có giá trị tuyệt đối nhỏ hơn 1. Tất cả các quãng tám khác có thể được suy ra dưới dạng biến đổi đơn giản của điều này quãng tám cơ bản.

Trong psuedocode, hình thức cơ bản này trông giống như:

void DrawLine(Point origin, Point endpoint, Bitmap surface) {
    deltaX = endpoint.X - origin.X
    deltaY = endpoint.Y - origin.Y
    error = 0

    // Note the below fails for completely vertical lines.
    deltaError = absoluteValue(deltaY / deltaX)

    Y = origin.Y
    for (X from origin.X to endpoint.X) {
        surface.PlotPixel(X, Y)
        error = error + deltaError 
        if (error >= 0.5) {
            ++Y;
            error -= 1.0
        }
    }
}

Trang web Rosetta Code có một bộ sưu tập các triển khai cụ thể bằng nhiều ngôn ngữ .

Bạn cũng có thể quan tâm đến thuật toán dòng của Wu , cho phép khử răng cưa.


3
Chỉ muốn cảnh báo người đi đường không được đưa mã giả đi kèm ra khỏi bối cảnh, vì nó sẽ không hoạt động ra khỏi hộp. Nó chỉ hoạt động cho một octant cụ thể (đọc phần còn lại của câu trả lời). Nếu bạn đang tìm kiếm mã để sao chép / dán, hãy thử liên kết đến trang web Rosetta Code.
congusbongus

1
Đối với bất kỳ ai muốn kiểm tra phiên bản c của thuật toán dòng của Wu, tôi muốn cảnh báo bạn rằng nó chưa hoàn chỉnh. Trong _dla_changebrightness khi bạn thay đổi độ sáng, bạn cần thay đổi nó từ: to->red = br * (float)from->red;sang sau đây : to->red = (br * (float)from->red) + ((1-br) * (float) to->red);. Làm tương tự cho màu xanh lá cây và màu xanh một cách trân trọng
Fredrik Boston Westman

2

Dưới đây là một cách vẽ đường cực kỳ đơn giản. Các chức năng có thể dễ dàng được thay đổi để được sử dụng trong các dự án.

void draw_line(float x0, float y0, const float& x1, const float& y1)
{
    float x{x1 - x0}, y{y1 - y0};
    const float max{std::max(std::fabs(x), std::fabs(y))};
    x /= max; y /= max;
    for (float n{0}; n < max; ++n)
    {
        // draw pixel at ( x0, y0 )
        x0 += x; y0 += y;
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.