13_draw_line.cpp 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. #include <cstdio>
  2. #include <cerrno>
  3. #include <thread>
  4. #include <random>
  5. #include "simple/graphical/initializer.h"
  6. #include "simple/graphical/software_window.h"
  7. #include "simple/graphical/algorithm/blit.h"
  8. #include "simple/graphical/algorithm/fill.h"
  9. #include "simple/graphical/algorithm/line.hpp"
  10. #include "simple/support/misc.hpp"
  11. using namespace simple::graphical;
  12. using namespace color_literals;
  13. using namespace std::chrono_literals;
  14. using simple::geom::vector;
  15. using simple::support::min_element;
  16. using rgb_pixels = pixel_writer<rgb_pixel, surface::byte>;
  17. const auto tau = 2*std::acos(-1);
  18. float2 from_angle(float angle) { return {cos(angle), sin(angle)}; }
  19. void integer_dda_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value);
  20. void floating_dda_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value);
  21. void integer_vector_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value);
  22. void floating_vector_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value);
  23. void radius_vector_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value); // TODO
  24. void bresenham_line(const line<int2> line, rgb_pixels pixels, rgb_pixel value);
  25. void xiaolin_wu_line(const line<int2> line, rgb_pixels pixels, rgb_pixel value);
  26. void perfect_line(const line<float2> line, rgb_pixels pixels, rgb_pixel value); // TODO
  27. int main(int argc, char const* argv[]) try
  28. {
  29. initializer init;
  30. software_window win("Line drawing", int2::one(400), window::flags::borderless);
  31. const int zoom = argc > 1 ? simple::support::ston<int>(argv[1]) : 1;
  32. if(zoom <= 0)
  33. throw std::logic_error("zoom is not positive!");
  34. const auto logical_size = win.surface().size() / zoom;
  35. surface canvas (logical_size, pixel_format(pixel_format::type::rgb24));
  36. auto pixels = std::get<rgb_pixels>(canvas.pixels());
  37. const int half_size = min_element(win.size())/2 - 1; // -1 becaus we set the enpoints
  38. const float offset = tau/10;
  39. const float radius = half_size / zoom;
  40. const auto position = float2::one(half_size) / zoom;
  41. const auto color = 0xffffff_rgb;
  42. for(float i = 0; i < tau; i += tau*0.001f)
  43. {
  44. float angle = i;
  45. fill(canvas, canvas.format().color(0x000000_rgb));
  46. integer_dda_line({position + from_angle(angle) * radius/2, position + from_angle(angle) * radius}, pixels, color);
  47. angle -= offset;
  48. floating_dda_line({position + from_angle(angle) * radius/2, position + from_angle(angle) * radius}, pixels, color);
  49. angle -= offset;
  50. integer_vector_line({position + from_angle(angle) * radius/2, position + from_angle(angle) * radius}, pixels, color);
  51. angle -= offset;
  52. floating_vector_line({position + from_angle(angle) * radius/2, position + from_angle(angle) * radius}, pixels, color);
  53. angle -= offset;
  54. bresenham_line({int2(round(position + from_angle(angle) * radius/2)), int2(round(position + from_angle(angle) * radius))}, pixels, color);
  55. angle -= offset;
  56. xiaolin_wu_line({int2(round(position + from_angle(angle) * radius/2)), int2(round(position + from_angle(angle) * radius))}, pixels, color);
  57. blit(canvas, win.surface(), rect{win.surface().size()});
  58. win.update();
  59. std::this_thread::sleep_for(16ms);
  60. }
  61. std::this_thread::sleep_for(3313ms);
  62. return 0;
  63. }
  64. catch(...)
  65. {
  66. if(errno)
  67. std::perror("ERROR");
  68. const char* sdl_error = SDL_GetError();
  69. if(*sdl_error)
  70. std::puts(sdl_error);
  71. throw;
  72. }
  73. void floating_dda_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value)
  74. {
  75. const auto setter = [&pixels, &value](const float2& position)
  76. {
  77. pixels.set<rgb_vector>(value, position);
  78. };
  79. const auto tail = dda_line(line, setter);
  80. const auto tail_size = tail.end() - tail.begin();
  81. rgba_vector end_value = rgb_vector(value);
  82. end_value.a() = std::clamp(tail_size.length(),0.f,1.f);
  83. pixels.set(end_value, tail.end());
  84. }
  85. void integer_dda_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value)
  86. {
  87. const auto setter = [&pixels, &value](const float2& position)
  88. {
  89. pixels.set(value, int2(round(position)));
  90. };
  91. setter(dda_line(line, setter).end());
  92. }
  93. void floating_vector_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value)
  94. {
  95. const auto setter = [&pixels, &value](const float2& position)
  96. {
  97. pixels.set<rgb_vector>(value, position);
  98. };
  99. const auto tail = vector_line(line, setter);
  100. const auto tail_size = tail.end() - tail.begin();
  101. rgba_vector end_value = rgb_vector(value);
  102. end_value.a() = std::clamp(tail_size.length(),0.f,1.f);
  103. pixels.set(end_value, tail.end());
  104. }
  105. void integer_vector_line(const line<float2>& line, rgb_pixels pixels, rgb_pixel value)
  106. {
  107. const auto setter = [&pixels, &value](const float2& position)
  108. {
  109. pixels.set(value, int2(round(position)));
  110. };
  111. setter(vector_line(line, setter).end());
  112. }
  113. void bresenham_line(line<int2> line, rgb_pixels pixels, rgb_pixel value)
  114. {
  115. bresenham_line(line, [&pixels, &value](int2 position)
  116. {
  117. pixels.set(value, position);
  118. });
  119. }
  120. void xiaolin_wu_line(line<int2> line, rgb_pixels pixels, rgb_pixel value)
  121. {
  122. using rational = rational<int>;
  123. bresenham_line(line, [&pixels, &value](int2 position, rational ratio)
  124. {
  125. const auto blended = value.transformed([&ratio](auto color)
  126. { return rgb_pixel::coordinate_type(int(color * ratio)); });
  127. pixels.set(rgb_pixel{blended}, position);
  128. });
  129. }