Skip to content

Commit 0f0ec17

Browse files
committed
Add multiAxis
1 parent 78ccbd5 commit 0f0ec17

File tree

24 files changed

+328
-125
lines changed

24 files changed

+328
-125
lines changed

src/base/geom/rect.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,10 @@ template <class Container>
170170
Rect Rect::Boundary(const Container &points)
171171
{
172172
auto &&[minx, maxx] = std::ranges::minmax(
173-
std::ranges::views::transform(points, std::mem_fn(&Point::x)),
173+
std::views::transform(points, std::mem_fn(&Point::x)),
174174
Math::Floating::less);
175175
auto &&[miny, maxy] = std::ranges::minmax(
176-
std::ranges::views::transform(points, std::mem_fn(&Point::y)),
176+
std::views::transform(points, std::mem_fn(&Point::y)),
177177
Math::Floating::less);
178178
return Rect{{minx, miny}, {maxx - minx, maxy - miny}};
179179
}

src/base/refl/auto_accessor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ const Accessor<Object, runtime> &getAccessor(
153153

154154
template <class Object, bool runtime = false> auto getAccessorNames()
155155
{
156-
return std::ranges::views::keys(getAccessors<Object, runtime>());
156+
return std::views::keys(getAccessors<Object, runtime>());
157157
}
158158
}
159159

src/base/type/uniquelist.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define TYPE_UNIQUELIST
33

44
#include <algorithm>
5+
#include <cstddef>
6+
#include <functional>
57
#include <map>
68
#include <ranges>
79
#include <utility>
@@ -217,7 +219,7 @@ template <class T> class UniqueList
217219

218220
[[nodiscard]] auto as_set() const noexcept
219221
{
220-
return std::ranges::views::keys(items);
222+
return std::views::keys(items);
221223
}
222224

223225
template <class It, class Sentinel = It>

src/chart/generator/axis.cpp

Lines changed: 66 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#include "axis.h"
22

3+
#include <__compare/compare_three_way.h>
34
#include <algorithm>
45
#include <cmath>
6+
#include <compare>
7+
#include <cstddef>
58
#include <cstdint>
69
#include <functional>
710
#include <limits>
@@ -46,7 +49,10 @@ void Axises::addLegendInterpolation(double legendFactor,
4649
&& target.measure.enabled.get())
4750
|| (!source.dimension.empty()
4851
&& !target.dimension.empty()))
49-
&& source.seriesName() != target.seriesName()) {
52+
&& source.seriesName() != target.seriesName()
53+
&& !DimensionAxis::commonDimensionParts(
54+
source.dimension.getValues(),
55+
target.dimension.getValues())) {
5056
if (!leftLegend[0]) leftLegend[0].emplace(legendType);
5157
if (!leftLegend[1]) leftLegend[1].emplace(legendType);
5258

@@ -67,8 +73,11 @@ void Axises::addLegendInterpolation(double legendFactor,
6773
leftLegend[0] && leftLegend[1]
6874
&& leftLegend[0]->interpolated
6975
== leftLegend[1]->interpolated
70-
&& leftLegend[0]->calc.seriesName()
71-
== leftLegend[1]->calc.seriesName();
76+
&& (leftLegend[0]->calc.seriesName()
77+
== leftLegend[1]->calc.seriesName()
78+
|| DimensionAxis::commonDimensionParts(
79+
leftLegend[0]->calc.dimension.getValues(),
80+
leftLegend[1]->calc.dimension.getValues()));
7281
sameInterpolated && !leftLegend[0]->calc.dimension.empty()
7382
&& !leftLegend[1]->calc.dimension.empty()) {
7483

@@ -100,6 +109,19 @@ Geom::Point Axises::origo() const
100109
return {at(AxisId::x).measure.origo(),
101110
at(AxisId::y).measure.origo()};
102111
}
112+
std::size_t DimensionAxis::commonDimensionParts(const Values &lhs,
113+
const Values &rhs)
114+
{
115+
return lhs.empty() || rhs.empty()
116+
? 0
117+
: std::ranges::mismatch(lhs.begin()->first,
118+
rhs.begin()->first,
119+
[](const auto &lhsItem, const auto &rhsItem)
120+
{
121+
return lhsItem.column == rhsItem.column;
122+
}).in1
123+
- lhs.begin()->first.begin();
124+
}
103125

104126
MeasureAxis::MeasureAxis(const Math::Range<> &interval,
105127
std::string &&series,
@@ -242,7 +264,7 @@ MeasureAxis interpolate(const MeasureAxis &op0,
242264

243265
return res;
244266
}
245-
bool DimensionAxis::add(const Data::SliceIndex &index,
267+
bool DimensionAxis::add(const std::vector<Data::SliceIndex> &index,
246268
const Math::Range<> &range,
247269
std::uint32_t position,
248270
const std::optional<ColorBase> &color,
@@ -302,27 +324,57 @@ DimensionAxis interpolate(const DimensionAxis &op0,
302324
factor));
303325
using Val = DimensionAxis::Values::value_type;
304326

327+
std::size_t commonSize =
328+
DimensionAxis::commonDimensionParts(op0.getValues(),
329+
op1.getValues());
330+
std::size_t maxSize = std::max(
331+
op0.values.empty() ? 0 : op0.values.begin()->first.size(),
332+
op1.values.empty() ? 0 : op1.values.begin()->first.size());
333+
305334
const Val *latest1{};
306335
const Val *latest2{};
307336

308-
auto merger = [&](const Val &lhs, const Val &rhs) -> Val
337+
auto merger = [&](const Val &lhs,
338+
const Val &rhs,
339+
const Val::first_type *key = nullptr) -> Val
340+
{
341+
printf("%s to %s\n",
342+
DimensionAxis::mergedLabels(lhs.first).c_str(),
343+
DimensionAxis::mergedLabels(rhs.first).c_str());
344+
return {key ? *key : lhs.first,
345+
interpolate(lhs.second, rhs.second, factor)};
346+
};
347+
348+
auto needMerge = [&](const Val &lhs, const Val &rhs)
309349
{
310350
latest1 = std::addressof(lhs);
311351
latest2 = std::addressof(rhs);
312-
return {lhs.first,
313-
interpolate(lhs.second, rhs.second, factor)};
352+
return commonSize == maxSize || commonSize == 0;
353+
};
354+
355+
auto comparator = [&](const auto &lhs, const auto &rhs)
356+
{
357+
if (commonSize == maxSize || commonSize == 0)
358+
return std::compare_three_way{}(lhs, rhs);
359+
return std::lexicographical_compare_three_way(lhs.begin(),
360+
lhs.begin() + commonSize,
361+
rhs.begin(),
362+
rhs.begin() + commonSize);
314363
};
315364

316365
auto &&one_side =
317-
[&merger](bool first,
366+
[&](bool first,
318367
DimensionAxis::Item::PosType DimensionAxis::Item::*pos,
319368
const Val *&paramOther)
320369
{
321370
return [&, first, pos](const Val &val) -> Val
322371
{
323-
if (paramOther && paramOther->first == val.first) {
324-
auto &&res = first ? merger(val, *paramOther)
325-
: merger(*paramOther, val);
372+
if (paramOther
373+
&& std::is_eq(
374+
comparator(paramOther->first, val.first))) {
375+
auto &&res = first
376+
? merger(val, *paramOther)
377+
: merger(*paramOther, val, &val.first);
326378
(res.second.*pos).makeAuto();
327379
return res;
328380
}
@@ -334,11 +386,13 @@ DimensionAxis interpolate(const DimensionAxis &op0,
334386
op1.values,
335387
res.values,
336388
Alg::merge_args{.projection = &Val::first,
389+
.comparator = comparator,
337390
.transformer_1 =
338391
one_side(true, &DimensionAxis::Item::endPos, latest2),
339392
.transformer_2 = one_side(false,
340393
&DimensionAxis::Item::startPos,
341394
latest1),
395+
.need_merge = needMerge,
342396
.merger = merger});
343397

344398
return res;
@@ -438,7 +492,7 @@ interpolate(const SplitAxis &op0, const SplitAxis &op1, double factor)
438492
}
439493
else
440494
res.parts
441-
.insert({std::nullopt,
495+
.insert({{},
442496
{.weight =
443497
op0.parts.empty() ? 1 - factor : factor}})
444498
->second.unique = true;

src/chart/generator/axis.h

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define AXIS_H
33

44
#include <map>
5+
#include <ranges>
56

67
#include "base/anim/interpolated.h"
78
#include "base/geom/point.h"
@@ -21,7 +22,7 @@ namespace Vizzu::Gen
2122
struct ChannelStats
2223
{
2324
using TrackType = std::variant<Math::Range<>,
24-
std::map<std::uint32_t, Data::SliceIndex>>;
25+
std::map<std::uint32_t, std::vector<Data::SliceIndex>>>;
2526

2627
Refl::EnumArray<ChannelId, TrackType> tracked;
2728
Math::Range<> lightness;
@@ -35,9 +36,9 @@ struct ChannelStats
3536
void track(ChannelId at, const Data::MarkerId &id)
3637
{
3738
auto &vec = std::get<1>(tracked[at]);
38-
if (id.label)
39+
if (!id.label.empty())
3940
vec.try_emplace(static_cast<std::uint32_t>(id.itemId),
40-
*id.label);
41+
id.label);
4142
}
4243

4344
void track(ChannelId at, const double &value)
@@ -128,13 +129,13 @@ struct DimensionAxis
128129
friend Item
129130
interpolate(const Item &op0, const Item &op1, double factor);
130131
};
131-
using Values = std::multimap<Data::SliceIndex, Item>;
132+
using Values = std::multimap<std::vector<Data::SliceIndex>, Item>;
132133

133134
double factor{};
134135
bool hasMarker{};
135136

136137
DimensionAxis() = default;
137-
bool add(const Data::SliceIndex &index,
138+
bool add(const std::vector<Data::SliceIndex> &index,
138139
const Math::Range<> &range,
139140
std::uint32_t position,
140141
const std::optional<ColorBase> &color,
@@ -145,19 +146,19 @@ struct DimensionAxis
145146

146147
[[nodiscard]] auto begin()
147148
{
148-
return std::ranges::views::values(values).begin();
149+
return std::views::values(values).begin();
149150
};
150151
[[nodiscard]] auto end()
151152
{
152-
return std::ranges::views::values(values).end();
153+
return std::views::values(values).end();
153154
}
154155
[[nodiscard]] auto begin() const
155156
{
156-
return std::ranges::views::values(values).begin();
157+
return std::views::values(values).begin();
157158
};
158159
[[nodiscard]] auto end() const
159160
{
160-
return std::ranges::views::values(values).end();
161+
return std::views::values(values).end();
161162
}
162163
[[nodiscard]] bool empty() const { return values.empty(); }
163164
bool setLabels(double step);
@@ -179,6 +180,23 @@ struct DimensionAxis
179180
ItemSorterByRangeStart>{begin(), end()};
180181
}
181182

183+
static std::size_t commonDimensionParts(const Values &lhs,
184+
const Values &rhs);
185+
186+
template <std::string Data::SliceIndex::*which =
187+
&Data::SliceIndex::value>
188+
[[nodiscard]] static std::string mergedLabels(
189+
const std::vector<Data::SliceIndex> &slices)
190+
{
191+
return {std::from_range,
192+
std::views::transform(slices,
193+
[](const Data::SliceIndex &slice)
194+
{
195+
return ", " + slice.*which;
196+
})
197+
| std::views::join | std::views::drop(2)};
198+
}
199+
182200
private:
183201
Values values;
184202
};
@@ -189,10 +207,13 @@ struct Axis
189207
MeasureAxis measure;
190208
DimensionAxis dimension;
191209

192-
[[nodiscard]] const std::string &seriesName() const
210+
[[nodiscard]] std::string seriesName() const
193211
{
194-
if (!dimension.empty())
195-
return dimension.getValues().begin()->first.column;
212+
if (!dimension.empty()) {
213+
return DimensionAxis::mergedLabels<
214+
&Data::SliceIndex::column>(
215+
dimension.getValues().begin()->first);
216+
}
196217
return measure.series;
197218
}
198219

@@ -220,8 +241,7 @@ struct SplitAxis : Axis
220241
}
221242
};
222243

223-
using Parts =
224-
std::multimap<std::optional<Data::SliceIndex>, Part>;
244+
using Parts = std::multimap<std::vector<Data::SliceIndex>, Part>;
225245
Parts parts;
226246

227247
[[nodiscard]] bool operator==(

src/chart/generator/buckets.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct Buckets
3636

3737
[[nodiscard]] auto operator*() const
3838
{
39-
return std::ranges::views::transform(data,
39+
return std::views::transform(data,
4040
[this](Marker *marker)
4141
-> std::pair<Marker &, const Data::MarkerId &>
4242
{

0 commit comments

Comments
 (0)