Skip to content

Commit 742bd52

Browse files
authored
Merge pull request #629 from vizzuhq/axis_refactor_v13
Axis refactor v13 - Preparation to multiple origo
2 parents 0f78e3b + 4694ee8 commit 742bd52

37 files changed

+788
-389
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
- Fix invalid read/write when animation is contiguous (onFinish callback calls setKeyframe).
88
- Waterfall chart preset not aligned.
99
- Split chart count negative values too.
10+
- Split chart when same dimension on main and sub axis.
1011

1112
### Changed
1213

src/base/alg/union_foreach.h

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
#ifndef ALG_UNION_FOREACH_H
2+
#define ALG_UNION_FOREACH_H
3+
4+
#include <cstdint>
5+
#include <functional>
6+
#include <ranges>
7+
8+
namespace Alg
9+
{
10+
11+
namespace Impl
12+
{
13+
enum class union_call_t : std::uint8_t {
14+
both,
15+
only_left,
16+
only_right
17+
};
18+
19+
struct single_t
20+
{
21+
} constexpr static single{};
22+
struct multi_t
23+
{
24+
} constexpr static multi{};
25+
26+
template <class F>
27+
concept Property =
28+
std::same_as<F, single_t> || std::same_as<F, multi_t>;
29+
30+
template <class F,
31+
class I1,
32+
class I2 = I1,
33+
class Ptr1 = decltype(std::to_address(std::declval<I1 &>())),
34+
class Ptr2 = decltype(std::to_address(std::declval<I2 &>()))>
35+
concept address_binary_invocable =
36+
std::copy_constructible<F>
37+
&& (std::invocable<F &, Ptr1, Ptr2, union_call_t>
38+
|| std::invocable<F &, Ptr1, Ptr2>);
39+
40+
template <class R>
41+
concept insert_value_returns_iterator = requires {
42+
{
43+
std::declval<R &>().insert(
44+
std::declval<const std::ranges::range_value_t<R> &>())
45+
} -> std::same_as<std::ranges::iterator_t<R>>;
46+
};
47+
48+
template <class R>
49+
concept insert_value_returns_pair = requires {
50+
{
51+
std::declval<R &>().insert(
52+
std::declval<const std::ranges::range_value_t<R> &>())
53+
} -> std::same_as<std::pair<std::ranges::iterator_t<R>, bool>>;
54+
};
55+
56+
template <std::ranges::forward_range R,
57+
class CVR = std::remove_cvref_t<R>>
58+
using default_property_t = typename std::conditional_t<
59+
insert_value_returns_iterator<CVR>,
60+
std::type_identity<multi_t>,
61+
std::enable_if<insert_value_returns_pair<CVR>, single_t>>::type;
62+
63+
template <class Fun, class Arg1, class Arg2>
64+
constexpr void
65+
invoke(Fun &&f, Arg1 &&arg1, Arg2 &&arg2, union_call_t val)
66+
{
67+
if constexpr (std::invocable<Fun &&,
68+
Arg1 &&,
69+
Arg2 &&,
70+
union_call_t>)
71+
std::invoke(std::forward<Fun>(f),
72+
std::forward<Arg1>(arg1),
73+
std::forward<Arg2>(arg2),
74+
val);
75+
else
76+
std::invoke(std::forward<Fun>(f),
77+
std::forward<Arg1>(arg1),
78+
std::forward<Arg2>(arg2));
79+
}
80+
81+
template <class Exp, class Fun, class Arg>
82+
constexpr const Arg &assignIfSame([[maybe_unused]] Arg &to,
83+
const Arg &from)
84+
{
85+
if constexpr (std::same_as<Exp, Fun>)
86+
return to = from;
87+
else
88+
return from;
89+
}
90+
91+
}
92+
93+
using Impl::multi;
94+
using Impl::single;
95+
using Impl::union_call_t;
96+
97+
template <std::forward_iterator It1,
98+
std::sentinel_for<It1> End1,
99+
std::forward_iterator It2,
100+
std::sentinel_for<It2> End2,
101+
std::indirectly_unary_invocable<It1> Proj1 = std::identity,
102+
std::indirectly_unary_invocable<It2> Proj2 = std::identity,
103+
std::indirect_strict_weak_order<std::projected<It1, Proj1>,
104+
std::projected<It2, Proj2>> Comp = std::ranges::less,
105+
Impl::address_binary_invocable<It1, It2> Fun,
106+
Impl::Property Prop>
107+
constexpr void union_foreach(It1 first1,
108+
End1 last1,
109+
It2 first2,
110+
End2 last2,
111+
Fun f,
112+
Prop,
113+
Comp comp = {},
114+
Proj1 proj1 = {},
115+
Proj2 proj2 = {})
116+
{
117+
using enum union_call_t;
118+
using Impl::assignIfSame;
119+
using Impl::invoke;
120+
const std::iter_value_t<It1> *lastValid1{};
121+
const std::iter_value_t<It2> *lastValid2{};
122+
while (first1 != last1 || first2 != last2)
123+
if (first2 == last2
124+
|| (first1 != last1
125+
&& std::invoke(comp,
126+
std::invoke(proj1, *first1),
127+
std::invoke(proj2, *first2))))
128+
invoke(f,
129+
assignIfSame<Impl::single_t, Prop>(lastValid1,
130+
std::to_address(first1++)),
131+
lastValid2,
132+
only_left);
133+
else if (first1 == last1
134+
|| std::invoke(comp,
135+
std::invoke(proj2, *first2),
136+
std::invoke(proj1, *first1)))
137+
invoke(f,
138+
lastValid1,
139+
assignIfSame<Impl::single_t, Prop>(lastValid2,
140+
std::to_address(first2++)),
141+
only_right);
142+
else {
143+
auto &&key = std::invoke(proj1, *first1);
144+
invoke(f,
145+
lastValid1 = std::to_address(first1++),
146+
lastValid2 = std::to_address(first2++),
147+
both);
148+
149+
if constexpr (std::is_same_v<Impl::multi_t, Prop>) {
150+
while (first1 != last1 && first2 != last2
151+
&& !std::invoke(comp,
152+
key,
153+
std::invoke(proj1, *first1))
154+
&& !std::invoke(comp,
155+
key,
156+
std::invoke(proj2, *first2)))
157+
invoke(f,
158+
lastValid1 = std::to_address(first1++),
159+
lastValid2 = std::to_address(first2++),
160+
both);
161+
162+
while (first1 != last1
163+
&& !std::invoke(comp,
164+
key,
165+
std::invoke(proj1, *first1)))
166+
invoke(f,
167+
std::to_address(first1++),
168+
lastValid2,
169+
only_left);
170+
171+
while (first2 != last2
172+
&& !std::invoke(comp,
173+
key,
174+
std::invoke(proj2, *first2)))
175+
invoke(f,
176+
lastValid1,
177+
std::to_address(first2++),
178+
only_right);
179+
180+
lastValid1 = nullptr;
181+
lastValid2 = nullptr;
182+
}
183+
}
184+
}
185+
186+
template <std::ranges::forward_range R,
187+
std::indirectly_unary_invocable<std::ranges::iterator_t<R>> Proj =
188+
std::identity,
189+
std::indirect_strict_weak_order<
190+
std::projected<std::ranges::iterator_t<R>, Proj>> Comp =
191+
std::ranges::less,
192+
Impl::address_binary_invocable<std::ranges::iterator_t<R>> Fun,
193+
Impl::Property Prop = Impl::default_property_t<R>>
194+
constexpr void union_foreach(const R &r1,
195+
const R &r2,
196+
Fun f,
197+
Comp comp = {},
198+
Proj proj = {},
199+
Prop p = {})
200+
{
201+
union_foreach(std::ranges::begin(r1),
202+
std::ranges::end(r1),
203+
std::ranges::begin(r2),
204+
std::ranges::end(r2),
205+
std::move(f),
206+
p,
207+
std::move(comp),
208+
proj,
209+
proj);
210+
}
211+
}
212+
213+
#endif

src/base/geom/affinetransform.cpp

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -70,28 +70,31 @@ AffineTransform &AffineTransform::operator*=(
7070
return *this;
7171
}
7272

73-
Geom::Point AffineTransform::operator()(
74-
const Geom::Point &original) const
73+
Point AffineTransform::operator()(const Point &original) const
7574
{
7675
return {original.x * m[0][0] + original.y * m[0][1] + m[0][2],
7776
original.x * m[1][0] + original.y * m[1][1] + m[1][2]};
7877
}
7978

80-
Geom::Line AffineTransform::operator()(
81-
const Geom::Line &original) const
79+
Line AffineTransform::operator()(const Line &original) const
8280
{
8381
return {(*this)(original.begin), (*this)(original.end)};
8482
}
8583

86-
Geom::Polygon AffineTransform::operator()(
87-
const Geom::Polygon &original) const
84+
Polygon AffineTransform::operator()(const Polygon &original) const
8885
{
89-
Geom::Polygon res;
86+
Polygon res;
9087
for (auto point : original.points) res.add((*this)(point));
9188
return res;
9289
}
9390

94-
void AffineTransform::shift(const Geom::Point &offset)
91+
Size AffineTransform::operator()(const Size &original) const
92+
{
93+
return {original.x * m[0][0] + original.y * m[0][1],
94+
original.x * m[1][0] + original.y * m[1][1]};
95+
}
96+
97+
void AffineTransform::shift(const Point &offset)
9598
{
9699
m[0][2] += offset.x;
97100
m[1][2] += offset.y;

src/base/geom/affinetransform.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,15 @@ class AffineTransform
2828
double m10,
2929
double m11,
3030
double m12);
31-
explicit AffineTransform(Geom::Point offset,
31+
explicit AffineTransform(Point offset,
3232
double scale = 1.0,
3333
double angle = 0.0);
3434

3535
[[nodiscard]] const Matrix &getMatrix() const { return m; }
3636

3737
[[nodiscard]] AffineTransform inverse() const;
3838
[[nodiscard]] bool transforms() const;
39-
void shift(const Geom::Point &offset);
39+
void shift(const Point &offset);
4040

4141
friend AffineTransform operator*(AffineTransform lhs,
4242
const AffineTransform &rhs)
@@ -46,9 +46,10 @@ class AffineTransform
4646
AffineTransform &operator*=(const AffineTransform &other);
4747
bool operator==(const AffineTransform &other) const = default;
4848

49-
Geom::Point operator()(const Geom::Point &original) const;
50-
Geom::Line operator()(const Geom::Line &original) const;
51-
Geom::Polygon operator()(const Geom::Polygon &original) const;
49+
Point operator()(const Point &original) const;
50+
Line operator()(const Line &original) const;
51+
Polygon operator()(const Polygon &original) const;
52+
Size operator()(const Size &original) const;
5253

5354
[[nodiscard]] std::string toJSON() const;
5455

src/base/geom/point.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ struct Point
236236

237237
struct Size : Point
238238
{
239+
[[nodiscard]] static Size Oriented(Orientation orientation,
240+
double value,
241+
double other = 0.0)
242+
{
243+
return {Point::Coord(orientation, value, other)};
244+
}
239245

240246
static Size Square(double size) { return {size, size}; }
241247

src/base/geom/rect.cpp

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#include <algorithm>
44
#include <array>
55
#include <cmath>
6-
#include <compare>
76

87
#include "base/math/floating.h"
98

@@ -91,24 +90,6 @@ Rect Rect::intersection(const Rect &rect) const
9190
Size{xRight - xLeft, yTop - yBottom}};
9291
}
9392

94-
bool Rect::intersects(const Rect &r) const
95-
{
96-
using Math::Floating::is_zero;
97-
using std::strong_order;
98-
auto first = strong_order(right(), r.left());
99-
auto second = strong_order(r.right(), left());
100-
auto third = strong_order(top(), r.bottom());
101-
auto fourth = strong_order(r.top(), bottom());
102-
103-
auto isOutside = is_lt(first) || is_lt(second) || is_lt(third)
104-
|| is_lt(fourth)
105-
|| ((is_eq(first) || is_eq(second))
106-
&& !is_zero(width()) && !is_zero(r.width()))
107-
|| ((is_eq(third) || is_eq(fourth))
108-
&& !is_zero(height()) && !is_zero(r.height()));
109-
return !isOutside;
110-
}
111-
11293
Point Rect::center() const { return pos + size / 2.0; }
11394

11495
Rect Rect::popBottom(double length)

src/base/geom/rect.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,11 @@ struct Rect
5656
return {bottom(), top()};
5757
}
5858

59+
[[nodiscard]] Math::Range<> oSize(Orientation o) const
60+
{
61+
return isHorizontal(o) ? hSize() : vSize();
62+
}
63+
5964
[[nodiscard]] Math::Range<> x() const
6065
{
6166
return {pos.x, pos.x + size.x};
@@ -101,6 +106,14 @@ struct Rect
101106
setTop(range.max);
102107
}
103108

109+
void setOSize(Orientation o, const Math::Range<> &range)
110+
{
111+
if (isHorizontal(o))
112+
setHSize(range);
113+
else
114+
setVSize(range);
115+
}
116+
104117
[[nodiscard]] Rect bottomHalf() const
105118
{
106119
return {pos, size.verticalHalf()};
@@ -138,7 +151,6 @@ struct Rect
138151
[[nodiscard]] Rect intersection(const Rect &rect) const;
139152

140153
[[nodiscard]] bool contains(const Point &p) const;
141-
[[nodiscard]] bool intersects(const Rect &r) const;
142154
[[nodiscard]] Point center() const;
143155

144156
[[nodiscard]] Rect outline(const Geom::Size &margin) const

0 commit comments

Comments
 (0)