11 constexpr
size_t indices_between_anchor_points = 3;
12 constexpr
size_t indices_between_anchor_pointsi = 3;
15 is_anchor_point(
size_t i)
17 return i % indices_between_anchor_points == 0;
21 is_control_point(
size_t i)
23 return !is_anchor_point(i);
26 template<
typename T,
bool b>
struct Const {
using Type = T; };
27 template<
typename T>
struct Const<T, true> {
using Type = std::add_const_t<T>; };
29 template <
typename TVec> TVec get_zero_value();
30 template<> vec2f constexpr get_zero_value<vec2f>()
35 template<
typename Vec,
typename Segment,
typename Unit,
bool is_const>
36 struct PolyBezierWrapper
38 using TPoints =
typename Const<std::vector<Vec>, is_const>
::Type;
49 TBool* arg_is_autoset_enabled
57 Vec& point_at(
int i) {
return (*
points)[
i]; }
61 void reset(
const Vec& left,
const Vec& right,
const Vec& up,
const Vec& down,
const Vec& center,
float scale)
66 points->push_back(center + left * scale);
67 points->push_back(center + (left + up) * 0.5f * scale);
68 points->push_back(center + (right + down) * 0.5f * scale);
69 points->push_back(center + right * scale);
72 void add_point(
const Vec& p)
74 const auto p2 = point_at(num_points() - 2);
75 const auto p3 = point_at(num_points() - 1);
77 const auto p4 = p3 + Vec::from_to(p2, p3);
79 const auto p5 = p4 + Vec::from_to(p4, p6);
87 auto_set_affected_control_points(num_points() - 1);
91 void move_point(
int i,
const Vec& delta)
100 point_at(i) += delta;
104 auto_set_affected_control_points(i);
108 if(is_anchor_point(i))
113 point_at(loop_index(i + 1)) += delta;
117 point_at(loop_index(i - 1)) += delta;
123 const int corresponding_control_index = is_anchor_point(i + 1) ?
i + 2 :
i - 2;
124 const int anchor_index = is_anchor_point(i + 1) ?
i + 1 :
i - 1;
127 const auto cci = loop_index(corresponding_control_index);
128 const auto ai = loop_index(anchor_index);
129 const auto distance = Vec::from_to(point_at(cci), point_at(ai)).get_length();
130 const auto direction = Vec::from_to(point_at(i), point_at(ai)).get_normalized();
131 point_at(cci) = point_at(ai) + distance * direction;
136 [[nodiscard]] Segment
137 get_segment(
int i)
const
139 const auto b =
i * 3;
144 point_at(loop_index(b+indices_between_anchor_pointsi)),
150 get_number_of_segments()
const
152 return num_points() / indices_between_anchor_points;
156 set_closed(
bool new_is_closed)
168 const auto d = Vec::from_to(point_at(num_points() - 2), point_at(num_points() - 1));
169 const auto p1 = point_at(num_points() - 1) +
d;
170 const auto p2 = point_at(0) + Vec::from_to(point_at(1), point_at(0));
176 auto_set_anchor_control_points(0);
177 auto_set_anchor_control_points(num_points() - indices_between_anchor_pointsi);
187 auto_set_start_and_end_control_points();
200 set_auto_set_control_points(
bool is_autoset)
211 auto_set_all_control_points();
216 toggle_auto_set_control_points()
223 loop_index(
int i)
const
225 const auto s = num_points();
230 auto_set_affected_control_points(
int updated_anchor_index)
234 const auto update_anchor_index = [&](
int anchor_index)
238 auto_set_anchor_control_points(loop_index(anchor_index));
242 update_anchor_index(updated_anchor_index - indices_between_anchor_pointsi);
243 update_anchor_index(updated_anchor_index);
244 update_anchor_index(updated_anchor_index + indices_between_anchor_pointsi);
247 auto_set_start_and_end_control_points();
251 auto_set_all_control_points()
253 for(
int point_index = 0; point_index < num_points(); point_index += indices_between_anchor_pointsi)
255 auto_set_anchor_control_points(point_index);
257 auto_set_start_and_end_control_points();
261 auto_set_start_and_end_control_points()
268 const auto set_index = [&](
int r,
int a,
int b)
270 point_at(loop_index(r)) = (point_at(loop_index(a)) + point_at(loop_index(b))) * 0.5f;
273 set_index(-2, -1, -3);
277 auto_set_anchor_control_points(
int anchor_index)
280 const auto anchor_pos = point_at(anchor_index);
282 const auto get_distance_and_dir = [&](
int index) -> std::pair<float, Vec>
286 const auto ft = Vec::from_to(anchor_pos, point_at(loop_index(index)));
287 const auto offset = ft.get_normalized_and_length();
288 const auto dir = offset.normalized.to_vec();
289 return {offset.length, dir};
293 return {0.0f, get_zero_value<Vec>()};
296 const auto set_control_point = [&](
int control_index,
float distance,
const Unit& dir)
300 point_at(loop_index(control_index)) = anchor_pos + dir * distance * 0.5f;
304 const auto [distance_from_anchor_to_fst_neighbour, anchor_to_fst_neighbour] = get_distance_and_dir(anchor_index - indices_between_anchor_pointsi);
305 const auto [distance_from_anchor_to_sec_neighbour, anchor_to_sec_neighbour] = get_distance_and_dir(anchor_index + indices_between_anchor_pointsi);
306 const auto dir = Vec::from_to(anchor_to_sec_neighbour, anchor_to_fst_neighbour).get_normalized();
308 set_control_point(anchor_index - 1, distance_from_anchor_to_fst_neighbour, dir);
309 set_control_point(anchor_index + 1, -distance_from_anchor_to_sec_neighbour, dir);
319 &
self->is_autoset_enabled
323 PolyBezierWrapper<vec2f, BezierSegment2, unit2f, true> make_wrapper(
const eu::core::PolyBezier2*
self)
329 &
self->is_autoset_enabled
339 const auto left =
vec2f(-1, 0);
340 const auto right =
vec2f(1, 0);
341 const auto up =
vec2f(0, 1);
342 const auto down =
vec2f(0, -1);
344 make_wrapper(
this).reset(left, right, up, down, center, 50.0f);
350 return iterate<std::size_t>(0,
points.size());
356 make_wrapper(
this).add_point(
p);
362 return core::is_anchor_point(
i);
368 return core::is_control_point(
i);
375 make_wrapper(
this).move_point(
i, delta);
381 return iterate(0, make_wrapper(
this).get_number_of_segments());
387 return make_wrapper(
this).get_segment(
i);
393 make_wrapper(
this).set_closed(new_is_closed);
399 make_wrapper(
this).toggle_closed();
406 make_wrapper(
this).set_auto_set_control_points(is_autoset);
412 make_wrapper(
this).toggle_auto_set_control_points();
StepIteratorCreator< T > iterate(const T from, T to, T step=1)
int c_sizet_to_int(size_t t)
Range< T > make_range(T min, T max)
bool is_within(const Range< T > &range, T value)
TBool * is_autoset_enabled
Anchor and control points.
Composite Bézier curve or polybezier.
BezierSegment2 get_segment(int i) const
StepIteratorCreator< size_t > iterate_points() const
static bool is_anchor_point(size_t i)
void set_closed(bool is_closed)
static bool is_control_point(size_t i)
void set_auto_set_control_points(bool is_autoset)
void add_point(const vec2f &p)
StepIteratorCreator< int > iterate_segments() const
std::vector< vec2f > points
void move_point(int i, const vec2f &delta)
void toggle_auto_set_control_points()
PolyBezier2(const vec2f ¢er)