punch_aim.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. /* the way boxas align punchies
  2. */
  3. #include "common/sketchbook.hpp"
  4. constexpr float circle_radius = .12;
  5. constexpr float corner_radius = 14.f;
  6. constexpr float precision_mode_motion_scale = .01f;
  7. constexpr float2 half = float2::one(.5f);
  8. struct line
  9. {
  10. float2 start;
  11. float2 direction;
  12. };
  13. struct circle
  14. {
  15. float2 center;
  16. float radius;
  17. float magnitude() const;
  18. explicit operator range2f() const;
  19. bool contains(float2 point) const;
  20. };
  21. line l;
  22. circle c;
  23. bool precision_mode = false;
  24. float2* dragged_point = nullptr;
  25. float* dragged_radius = nullptr;
  26. circle* dragged_circle = nullptr;
  27. bool is_near(float2 corner, float2 position);
  28. sketch arrow(sketch s, float2 start, float2 end);
  29. void start(Program& program)
  30. {
  31. program.key_down = [](scancode code, keycode)
  32. {
  33. switch(code)
  34. {
  35. case scancode::lshift:
  36. case scancode::rshift:
  37. precision_mode = true;
  38. break;
  39. default: break;
  40. }
  41. };
  42. program.key_up = [&program](scancode code, keycode)
  43. {
  44. switch(code)
  45. {
  46. case scancode::leftbracket:
  47. case scancode::c:
  48. if(pressed(scancode::rctrl) || pressed(scancode::lctrl))
  49. case scancode::escape:
  50. program.end();
  51. break;
  52. case scancode::lshift:
  53. case scancode::rshift:
  54. precision_mode = false;
  55. break;
  56. default: break;
  57. }
  58. };
  59. program.mouse_down = [](float2 position, auto)
  60. {
  61. if(is_near(l.start + l.direction, position))
  62. dragged_point = &l.direction;
  63. else if(is_near(l.start, position))
  64. dragged_point = &l.start;
  65. else if(c.contains(position))
  66. dragged_circle = &c;
  67. };
  68. program.mouse_up = [](auto, auto)
  69. {
  70. dragged_point = nullptr;
  71. dragged_circle = nullptr;
  72. dragged_radius = nullptr;
  73. };
  74. program.mouse_move = [](auto, float2 motion)
  75. {
  76. if(precision_mode)
  77. motion *= precision_mode_motion_scale;
  78. if(dragged_circle)
  79. dragged_circle->center += motion;
  80. if(dragged_point)
  81. (*dragged_point) += motion;
  82. if(dragged_radius)
  83. (*dragged_radius) += motion.x();
  84. };
  85. program.draw_once = [](auto frame)
  86. {
  87. const float2 center = frame.size / 2;
  88. c.center = center;
  89. c.radius = frame.size.x() * circle_radius;
  90. l.start = center - 2 * c.radius;
  91. l.direction = float2::one(4 * c.radius);
  92. };
  93. program.draw_loop = [](auto frame, auto)
  94. {
  95. const float2 center_direction = c.center - l.start;
  96. bool itchin = center_direction(l.direction) < l.direction.quadrance();
  97. frame.begin_sketch()
  98. .rectangle(rect{ frame.size })
  99. .fill(0xffffff_rgb)
  100. ;
  101. geom::loop(frame.size/3, [&](auto i) {
  102. const float2 center_direction = c.center - i*3;
  103. const auto quadrance = l.direction.quadrance();
  104. auto normal = common::normalize(common::rotate(l.direction, common::protractor<>::tau(1/4.f)));
  105. bool itchin = center_direction(l.direction) < quadrance
  106. && center_direction(normal) < c.radius
  107. && center_direction(-normal) < c.radius
  108. ;
  109. frame.begin_sketch().ellipse(rect{float2::one(3), i*3}).fill(itchin ? 0xaa0000_rgb : 0xffffff_rgb);
  110. });
  111. frame.begin_sketch()
  112. .ellipse(range2f(c))
  113. .fill(itchin ? 0x00aa00_rgb : 0xaaaaaa_rgb)
  114. ;
  115. arrow(frame.begin_sketch(), l.start, l.start + l.direction)
  116. .line_width(1).outline(0x770077_rgb)
  117. ;
  118. frame.begin_sketch()
  119. .ellipse(rect{float2::one(corner_radius), l.start, half})
  120. .line_width(1).outline(0x555555_rgb)
  121. ;
  122. const float2 line_point = l.start + l.direction;
  123. frame.begin_sketch()
  124. .ellipse(rect{float2::one(corner_radius), line_point, half})
  125. .line_width(1).outline(0x555555_rgb)
  126. ;
  127. };
  128. }
  129. float circle::magnitude() const
  130. {
  131. return radius * radius;
  132. }
  133. circle::operator range2f() const
  134. {
  135. return {center - radius, center + radius};
  136. }
  137. bool circle::contains(float2 point) const
  138. {
  139. return (center - point).magnitude() < magnitude();
  140. }
  141. bool is_near(float2 corner, float2 position)
  142. {
  143. return circle{corner, corner_radius}.contains(position);
  144. }
  145. sketch arrow(sketch s, float2 start, float2 end)
  146. {
  147. float2 direction = end - start;
  148. float2 perpendicular = direction.mix<1,0>() * float2(-1.f,1.f);
  149. float2 shaft = start + direction * .8f;
  150. s.line(start, end);
  151. s.line(end, shaft + perpendicular * .1f);
  152. s.line(end, shaft - perpendicular * .1f);
  153. return s;
  154. }