Hướng dẫn draw line in php - vẽ đường thẳng trong php

Từ các ngăn kéo của "Tôi đã không nhận ra rằng nó phức tạp như thế nào" Tôi đã tự hỏi vào một ngày khác làm thế nào để vẽ một dòng chỉ bằng pixel. Điều này hóa ra là phức tạp hơn tôi nghĩ.

Thông thường trong PHP, bạn sẽ sử dụng hàm imageLine () để vẽ một dòng giữa hai điểm. Khối mã sau đây tạo và hình ảnh và vẽ một đường trắng từ tọa độ 50x, 50y đến 200x, 150y.

// Generate image resource with a width an height of 250 pixels.
$im = imagecreatetruecolor(250, 250);

// Create a color.
$white = imagecolorallocate($im, 255, 255, 255);

// Draw a white line from 50x,50y to 200x,150y.
imageline($im, 50, 50, 200, 150, $white);

// Write the image resource to a file called line.png.
imagepng($im, 'line.png');

// Destroy the image resource.
imagedestroy($im);

Điều này tạo ra một hình ảnh trông như thế này.

Hướng dẫn draw line in php - vẽ đường thẳng trong php

Như một bài tập, tôi đã xem xét cách vẽ cùng một dòng bằng cách chỉ vẽ các pixel dọc theo dòng. Điểm bắt đầu của điều này là với hàm ImageSetPixel (), cho phép chúng tôi đặt một màu khác cho bất kỳ pixel nào trong hình ảnh. Tôi biết rằng tôi phải bước dọc theo dòng và tô màu từng pixel trong từng chút một. Sau một chút nghiên cứu, tôi đã tìm thấy thuật toán dòng của Bresenham, cho phép một dòng được rút ra giữa hai điểm. Thuật toán dòng của Bresenham là một trong những gia đình thuật toán cho phép các dòng được rút ra giữa điểm này sang điểm khác, nhưng tôi sẽ chỉ tập trung vào thuật toán này trong bài đăng này.Bresenham's line algorithm, which allows a line to be drawn between two points. Bresenham's line algorithm is one of a family of algorithms that allow lines to be drawn between one point and another, but I'm only going to concentrate on this algorithm in this post.

Thuật toán của Bresenham hoạt động bằng cách xem xét các điểm raster giữa điểm bắt đầu và điểm cuối. Một điểm raster là một điểm mà tại đó một pixel được hiển thị trên màn hình và bởi vì dòng thực tế giữa hai điểm sẽ đi qua một số pixel khác nhau mà chúng ta cần để quyết định pixel nào mô tả tốt nhất dòng. Thuật toán & nbsp; đi dọc theo dòng và quyết định xem các pixel có nên 'bật' hoặc 'tắt' hay không, do đó vẽ đường.

Trên thực tế, điều này không đúng về mặt kỹ thuật. Hãy thực hiện một dòng đi từ 0x, 1y đến 5x, 4y. Những gì chúng tôi làm là chạy dọc theo các giá trị X từ 0 đến 5 và sau đó quyết định xem có vẽ một pixel tại một điểm nhất định trên trục y bằng cách nhìn vào độ dốc của dòng không. Nếu điểm cuối cao hơn thì hãy vẽ pixel cao hơn và nếu điểm cuối thấp hơn, & nbsp; vẽ pixel thấp hơn. Thuật toán theo phương trình sau (được lấy từ Wikipedia).

Trước khi lặp qua tọa độ X, chúng ta cần tìm ra một số giá trị trước.

$dx = $x1 - $x0;

$dy = $y1 - $y0;

$slope = $dy / $dx;

$pitch = $y0 - $slope * $x0;

Điều này cho chúng ta các giá trị 0,6 cho độ dốc và 1 cho sân. Đối với mỗi bước dọc theo tọa độ x, sau đó chúng ta có thể tìm ra vị trí của tọa độ y bằng cách sử dụng phương trình đơn giản hóa. & NBSP;

$y = $slope * $x + $pitch;

Mỗi điểm dẫn đến các tính toán sau. & NBSP;

xTính toán để giải quyết yy
0 0,6 * 0 + 11
1 0,6 * 1 + 12
2 0,6 * 2 + 12
3 0,6 * 3 + 13
4 0,6 * 4 + 13
5 n/a4

Điều này tạo ra pixel ở những nơi sau (pixel cuối cùng được rút vào cuối).

.0123456
0.......
1x......
2.xx....
3...xx..
4.....x.
5.......

Bạn có thể nghĩ rằng đây là tất cả mọi thứ chúng ta cần làm, nhưng có một vấn đề khi chúng ta cố gắng tính toán độ dốc hướng lên. Các tính toán trên dựa trên thực tế là giá trị x tăng, vì vậy chúng ta cần thêm một số mã để tính đến một dòng bắt đầu ở mức cao & nbsp; x & nbsp; giá trị và giảm. Chúng tôi cũng sẽ gặp phải một vấn đề nếu điểm cuối cao hơn điểm bắt đầu. Do đó, chúng tôi cần phải tăng hoặc giảm x hoặc y để vẽ đường chính xác.

Tôi đã thấy các ví dụ trên internet nơi & NBSP; Thuật toán dòng của Bresenham được chia thành hai phần trong đó các đường dốc lên và xuống được xử lý trong các chức năng khác nhau. Điều này có thể hữu ích khi tối ưu hóa cao mọi thứ, nhưng nhìn chung một chức năng duy nhất là tốt.

Cuối cùng, chúng ta cũng cần thêm một chút mã trong trường hợp tọa độ bắt đầu và kết thúc giống như chúng ta không cần phải chạy qua bất kỳ mã nào trong số này.

Mã cuối cùng cho bản vẽ dòng sử dụng thuật toán dòng của Bresenham & nbsp; như sau.

/**
  * Draw a line using Bresenham's line algorithm.
  *
  * @param resource $im
  *   The image resource.
  * @param int $x0
  *   The x part of the starting coordinate.
  * @param int $y0
  *   The y part of the starting coordinate.
  * @param int $x1
  *   The x part of the ending coordinate.
  * @param int $y1
  *   The y part of the ending coordinate.
  * @param int $color
  *   The color of the line, created from imagecolorallocate().
  */
function drawLine($im, $x0, $y0, $x1, $y1, $color) {
  if ($x0 == $x1 && $y0 == $y1) {
    // Start and finish are the same.
    imagesetpixel($im, $x0, $y0, $color);
    return;
  }

  $dx = $x1 - $x0;
  if ($dx < 0) {
    // x1 is lower than x0.
    $sx = -1;
  } else {
    // x1 is higher than x0.
    $sx = 1;
  }

  $dy = $y1 - $y0;
  if ($dy < 0) {
    // y1 is lower than y0.
    $sy = -1;
  } else {
    // y1 is higher than y0.
    $sy = 1;
  }

  if (abs($dy) < abs($dx)) {
    // Slope is going downwards.
    $slope = $dy / $dx;
    $pitch = $y0 - $slope * $x0;

    while ($x0 != $x1) {
      imagesetpixel($im, $x0, round($slope * $x0 + $pitch), $color);
      $x0 += $sx;
    }
  } else {
    // Slope is going upwards.
    $slope = $dx / $dy;
    $pitch = $x0 - $slope * $y0;

    while ($y0 != $y1) {
      imagesetpixel($im, round($slope * $y0 + $pitch), $y0, $color);
      $y0 += $sy;
    }
  }

  // Finish by adding the final pixel.
  imagesetpixel($im, $x1, $y1, $color);
}

Chạy một vài ví dụ về chức năng này với tọa độ ngẫu nhiên tạo ra hình ảnh sau.

Thuật toán dòng của Bresenham được sử dụng khá rộng rãi trong nhiều ứng dụng khác nhau nhưng nó không phải là & NBSP; rất tuyệt vời trong việc tạo ra các dòng chống răng cưa để nó không được sử dụng khi cần chống răng cưa.

Ngẫu nhiên, hàm & nbsp; imageLine () trong PHP gọi hàm & nbsp; gdimageline () từ thư viện GD. Như có thể thấy từ mã nguồn của gdimageline () chức năng này thực sự thực hiện thuật toán dòng của & nbsp; Bresenham. Điều này phức tạp hơn (và được thử nghiệm tốt hơn nhiều!) So với ví dụ đơn giản của tôi ở đây, nhưng nó vẫn tuân theo các quy tắc cơ bản tương tự.

Hỗ trợ chúng tôi!

Hãy hỗ trợ chúng tôi và cho phép chúng tôi tiếp tục viết bài.