I have been using the CImg library, and have been pleased with how easy it is to integrate and use. However, I now want to draw thick lines (i.e., more than one pixel thick). It is not clear from the API documentation of the draw_line
function (here) how this can be done. A second version of the function (just below the first in the documentation) even takes a texture as input, but again no width. It seems strange that such a comprehensive library would not have this feature. Perhaps it's supposed to be done using some kind of transformation? I know I could do it using a polygon (i.e., a rectangle where I would compute the corners of the polygon using a normal to the line), but I fear that would be significantly slower.
Apparently, it is not possible 'out-of-the-box', but creating your own routine that calls multiple times the 'draw_line()' routine of CImg, with one or two pixels shifts should give you the result you want, without much work.
This function can be used to draw thick lines as polygons.
void draw_line(cimg_library::CImg<uint8_t>& image,
const int x1, const int y1,
const int x2, const int y2,
const uint8_t* const color,
const unsigned int line_width)
{
if (x1 == x2 && y1 == y2) {
return;
}
// Convert line (p1, p2) to polygon (pa, pb, pc, pd)
const double x_diff = std::abs(x1 - x2);
const double y_diff = std::abs(y1 - y2);
const double w_diff = line_width / 2.0;
// Triangle between pa and p1: x_adj^2 + y_adj^2 = w_diff^2
// Triangle between p1 and p2: x_diff^2 + y_diff^2 = length^2
// Similar triangles: y_adj / x_diff = x_adj / y_diff = w_diff / length
// -> y_adj / x_diff = w_diff / sqrt(x_diff^2 + y_diff^2)
const int x_adj = y_diff * w_diff / std::sqrt(std::pow(x_diff, 2) + std::pow(y_diff, 2));
const int y_adj = x_diff * w_diff / std::sqrt(std::pow(x_diff, 2) + std::pow(y_diff, 2));
// Points are listed in clockwise order, starting from top-left
cimg_library::CImg<int> points(4, 2);
points(0, 0) = x1 - x_adj;
points(0, 1) = y1 + y_adj;
points(1, 0) = x1 + x_adj;
points(1, 1) = y1 - y_adj;
points(2, 0) = x2 + x_adj;
points(2, 1) = y2 - y_adj;
points(3, 0) = x2 - x_adj;
points(3, 1) = y2 + y_adj;
image.draw_polygon(points, color);
}
Benchmarks with line_width
20 and 3 colors. First time is using this function, second time is drawing single 1 px wide line using image.draw_line()
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With