123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- #include "common/sketchbook.hpp"
- constexpr
- float2 project(float2 x, float2 surface)
- {
- return surface * surface(x)
- / surface.magnitude();
- }
- constexpr
- float2 reject(float2 x, float2 surface)
- {
- return x - project(x,surface);
- }
- constexpr
- float2 reflect(float2 x, float2 surface)
- {
- return project(x,surface) - reject(x,surface);
- }
- constexpr
- float2 rotate(float2 x, float2 half_angle)
- {
- return reflect( reflect(x, float2::i()), half_angle );
- }
- constexpr
- float2 normalize(float2 x)
- {
-
- return x / support::root2(x.quadrance());
- }
- template <size_t Exponent = 3, typename Value = float>
- class protractor
- {
- public:
- using vector = geom::vector<Value,2>;
-
-
-
-
-
-
-
-
-
-
- using array = std::array<vector, (size_t(1)<<Exponent) + 1>;
- static constexpr array circle = []()
- {
- using support::halfway;
- array points{};
-
- points.front() = vector::i();
- points.back() = -vector::i();
- auto bisect = [](auto begin, auto end,
- auto& self)
- {
-
-
- if(end - begin <= 2)
- return;
-
-
- auto middle = halfway(begin, end);
-
-
-
- *(middle) = normalize(halfway(*begin, *(end - 1)));
-
- self(begin, middle + 1,
- self);
- self(middle, end,
- self);
- };
- if(Exponent > 0)
- {
-
-
- auto middle = halfway(points.begin(), points.end());
- *middle = vector::j();
- bisect(points.begin(), middle + 1,
- bisect);
- bisect(middle, points.end(),
- bisect);
- }
- return points;
- }();
-
- static constexpr vector tau(Value factor)
- {
- assert(Value{0} <= factor && factor < Value{1});
- Value index = factor * (protractor::circle.size() - 1);
- int whole = index;
- Value fraction = index - whole;
- return way(circle[whole], circle[whole+1], fraction);
-
-
- }
-
- static constexpr vector tau()
- {
- return -vector::i();
- }
-
- static constexpr vector small_radian(Value value)
- {
- return {support::root2(Value{1} - value*value), value};
-
- }
-
- static vector radian(Value angle)
- {
-
- return {std::cos(angle), std::sin(angle)};
- }
-
-
- static vector angle(Value tau_factor)
- {
- const static auto tau = std::acos(-1) * 2;
- if(tau_factor < (Value{0.5f}/(circle.size()-1))/10 )
- return small_radian(tau_factor * tau);
- else
- return protractor::tau(tau_factor);
- }
- };
- float2 angle = float2::one(1.f);
- float regular_angle = 0.f;
- void start(Program& program)
- {
- program.draw_loop = [&](auto frame, auto delta)
- {
- frame.begin_sketch()
- .rectangle(rect{frame.size})
- .fill(rgb::white(0))
- ;
- constexpr auto half = float2::one(0.5);
-
- frame.begin_sketch()
- .ellipse(anchored_rect2f{
- float2::one(300), frame.size/2, half
- })
- .outline(0xff00ff_rgb)
- ;
-
- frame.begin_sketch()
- .ellipse(anchored_rect2f{
- float2::one(10),
- frame.size/2 + rotate(float2::j(150), angle),
- float2::one(0.5f)
- })
- .fill(0xff00ff_rgb);
- ;
-
- frame.begin_sketch()
- .line(frame.size/2, frame.size/2 + angle * 50)
- .ellipse(anchored_rect2f{
- float2::one(100), frame.size/2, half
- })
- .outline(0xffff00_rgb)
- ;
-
-
- { auto sketch = frame.begin_sketch();
- for(size_t i = 1; i < protractor<>::circle.size(); ++i)
- {
- sketch.line(frame.size/2 + protractor<>::circle[i-1]*45, frame.size/2 + protractor<>::circle[i] * 45);
- }
- sketch.outline(0x00ffff_rgb);
- }
-
- if(pressed(scancode::j))
- angle.x() -= 1.f * delta.count();
- if(pressed(scancode::l))
- angle.x() += 1.f * delta.count();
- if(pressed(scancode::k))
- angle.y() += 1.f * delta.count();
- if(pressed(scancode::i))
- angle.y() -= 1.f * delta.count();
-
- auto move_regular_angle = [&](float direction)
- {
- regular_angle += direction * delta.count() * 0.1f;
- regular_angle = support::wrap(regular_angle,1.f);
- angle = protractor<>::tau(regular_angle);
- };
- if(pressed(scancode::right))
- move_regular_angle(1);
- if(pressed(scancode::left))
- move_regular_angle(-1);
-
-
- if(pressed(scancode::a))
- angle = rotate(angle, protractor<>::small_radian(delta.count() * 0.1f));
- if(pressed(scancode::d))
- angle = rotate(angle, protractor<>::small_radian(delta.count() * -0.1f));
- };
- }
|