Boost.GILでブレセンハムのアルゴリズム
Boost.GILで線を引きたくなったので作ってみた。
ある点 a から点 b まで線を引くパターンで、b.x >= a.x かつ b.y >= a.y かつ b.x - a.x >= b.y - a.yのパターンのみ実装しています。それに合わないケースはrotated_viewやtransposed_viewで視点を変更して、前途の条件に合わせるようにviewを作り替えています。
#include <iostream> #include <cassert> #include <cmath> #include <boost/gil/gil_all.hpp> #include <boost/gil/extension/io/png_io.hpp> template <class View, class T, class Value> void bresenham(View& view, boost::gil::point2<T> const& a, boost::gil::point2<T> const& b, Value const& v) { assert(b.x >= a.x); assert(b.y >= a.y); assert(b.x - a.x >= b.y - a.y); T const dx = b.x - a.x; T const dy = b.y - a.y; T e = -dx; for (T x = a.x, y = a.y; x < b.x; x += 1) { view(x, y) = v; e += 2 * dy; if (e >= 0) { y += 1; e -= 2 * dx; } } } template <class View, class T, class Value> void line(View& view, boost::gil::point2<T> const& a, boost::gil::point2<T> const& b, Value const& v) { namespace gil = boost::gil; typedef gil::point2<T> point_t; auto const dx = b.x - a.x; auto const dy = b.y - a.y; if (dx >= 0 && dy >= 0) { if (dx >= dy) { bresenham(view, a, b, v); } else { auto view2 = gil::transposed_view(view); bresenham(view2, point_t(a.y, a.x), point_t(b.y, b.x), v); } } else if (dx >= 0) { auto view2 = gil::rotated90ccw_view(view); line(view2, a, point_t(b.x, b.y - 2 * dy), v); } else if (dy >= 0) { auto view2 = gil::rotated90cw_view(view); line(view2, a, point_t(b.x - 2 * dx, b.y), v); } else { line(view, b, a, v); } } int main() { namespace gil = boost::gil; gil::point2<ptrdiff_t> size(300, 300); gil::rgb8_image_t img(size); auto view = gil::view(img); gil::fill_pixels(view, gil::rgb8_pixel_t(0, 0, 0)); for (double theta = 0; theta < 2 * M_PI; theta += M_PI / 12.0) { int x = std::round(std::cos(theta) * 80 + 150); int y = std::round(std::sin(theta) * 80 + 150); line(view, gil::point2<int>(150, 150), gil::point2<int>(x, y), gil::rgb8_pixel_t(255, 255, 255)); } gil::png_write_view("line.png", view); }
Boost.GILによるpng生成
libpngってC++ friendlyじゃないよね、って呟いていたら、id:faith_and_braveさんに「そこでBoost.GILですよ」と言われたので、作ってみた。
#include <utility> #include <boost/gil/gil_all.hpp> #include <boost/gil/extension/io/png_io.hpp> int main() { namespace gil = boost::gil; gil::point2<ptrdiff_t> dim(400, 400); gil::gray8_image_t img(dim); auto view = gil::view(img); for (ptrdiff_t i = 0; i < dim.y; ++i) { for (ptrdiff_t j = 0; j < dim.x; ++j) { view(i, j) = 255 * (std::min(i, j) / static_cast<double>(dim.x)); } } gil::png_write_view("img.png", view); return 0; }
IO時にlibpngを読んでいるので、
$ g++-4.5 -std=c++0x -o gil gil.cpp -W -Wall -O3 -lpng
のようにlibpngをリンクしないとコンパイルできません。