Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/base/geom/rect.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,10 @@ template <class Container>
Rect Rect::Boundary(const Container &points)
{
auto &&[minx, maxx] = std::ranges::minmax(
std::ranges::views::transform(points, std::mem_fn(&Point::x)),
std::views::transform(points, std::mem_fn(&Point::x)),
Math::Floating::less);
auto &&[miny, maxy] = std::ranges::minmax(
std::ranges::views::transform(points, std::mem_fn(&Point::y)),
std::views::transform(points, std::mem_fn(&Point::y)),
Math::Floating::less);
return Rect{{minx, miny}, {maxx - minx, maxy - miny}};
}
Expand Down
2 changes: 1 addition & 1 deletion src/base/math/renard.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Renard
[[nodiscard]] double floor(double value) const;

private:
std::span<const double> numbers;
std::span<const double> numbers{};
};

}
Expand Down
2 changes: 1 addition & 1 deletion src/base/refl/auto_accessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ const Accessor<Object, runtime> &getAccessor(

template <class Object, bool runtime = false> auto getAccessorNames()
{
return std::ranges::views::keys(getAccessors<Object, runtime>());
return std::views::keys(getAccessors<Object, runtime>());
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/base/type/uniquelist.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define TYPE_UNIQUELIST

#include <algorithm>
#include <cstddef>
#include <functional>
#include <map>
#include <ranges>
#include <utility>
Expand Down Expand Up @@ -217,7 +219,7 @@ template <class T> class UniqueList

[[nodiscard]] auto as_set() const noexcept
{
return std::ranges::views::keys(items);
return std::views::keys(items);
}

template <class It, class Sentinel = It>
Expand Down
76 changes: 63 additions & 13 deletions src/chart/generator/axis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@

#include <algorithm>
#include <cmath>
#include <compare>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>

#include "base/alg/merge.h"
#include "base/anim/interpolated.h"
Expand Down Expand Up @@ -46,7 +48,10 @@ void Axises::addLegendInterpolation(double legendFactor,
&& target.measure.enabled.get())
|| (!source.dimension.empty()
&& !target.dimension.empty()))
&& source.seriesName() != target.seriesName()) {
&& source.seriesName() != target.seriesName()
&& !DimensionAxis::commonDimensionParts(
source.dimension.getValues(),
target.dimension.getValues())) {
if (!leftLegend[0]) leftLegend[0].emplace(legendType);
if (!leftLegend[1]) leftLegend[1].emplace(legendType);

Expand All @@ -67,8 +72,11 @@ void Axises::addLegendInterpolation(double legendFactor,
leftLegend[0] && leftLegend[1]
&& leftLegend[0]->interpolated
== leftLegend[1]->interpolated
&& leftLegend[0]->calc.seriesName()
== leftLegend[1]->calc.seriesName();
&& (leftLegend[0]->calc.seriesName()
== leftLegend[1]->calc.seriesName()
|| DimensionAxis::commonDimensionParts(
leftLegend[0]->calc.dimension.getValues(),
leftLegend[1]->calc.dimension.getValues()));
sameInterpolated && !leftLegend[0]->calc.dimension.empty()
&& !leftLegend[1]->calc.dimension.empty()) {

Expand Down Expand Up @@ -100,6 +108,19 @@ Geom::Point Axises::origo() const
return {at(AxisId::x).measure.origo(),
at(AxisId::y).measure.origo()};
}
std::size_t DimensionAxis::commonDimensionParts(const Values &lhs,
const Values &rhs)
{
return lhs.empty() || rhs.empty()
? 0
: std::ranges::mismatch(lhs.begin()->first,
rhs.begin()->first,
[](const auto &lhsItem, const auto &rhsItem)
{
return lhsItem.column == rhsItem.column;
}).in1
- lhs.begin()->first.begin();
}

MeasureAxis::MeasureAxis(const Math::Range<> &interval,
std::string &&series,
Expand Down Expand Up @@ -242,7 +263,7 @@ MeasureAxis interpolate(const MeasureAxis &op0,

return res;
}
bool DimensionAxis::add(const Data::SliceIndex &index,
bool DimensionAxis::add(const std::vector<Data::SliceIndex> &index,
const Math::Range<> &range,
std::uint32_t position,
const std::optional<ColorBase> &color,
Expand Down Expand Up @@ -302,27 +323,54 @@ DimensionAxis interpolate(const DimensionAxis &op0,
factor));
using Val = DimensionAxis::Values::value_type;

std::size_t commonSize =
DimensionAxis::commonDimensionParts(op0.getValues(),
op1.getValues());
std::size_t maxSize = std::max(
op0.values.empty() ? 0 : op0.values.begin()->first.size(),
op1.values.empty() ? 0 : op1.values.begin()->first.size());

const Val *latest1{};
const Val *latest2{};

auto merger = [&](const Val &lhs, const Val &rhs) -> Val
auto merger = [&](const Val &lhs,
const Val &rhs,
const Val::first_type *key = nullptr) -> Val
{
return {key ? *key : lhs.first,
interpolate(lhs.second, rhs.second, factor)};
};

auto needMerge = [&](const Val &lhs, const Val &rhs)
{
latest1 = std::addressof(lhs);
latest2 = std::addressof(rhs);
return {lhs.first,
interpolate(lhs.second, rhs.second, factor)};
return commonSize == maxSize || commonSize == 0;
};

auto comparator = [&](const auto &lhs, const auto &rhs)
{
if (commonSize == maxSize || commonSize == 0)
return std::compare_three_way{}(lhs, rhs);
return std::lexicographical_compare_three_way(lhs.begin(),
lhs.begin() + commonSize,
rhs.begin(),
rhs.begin() + commonSize);
};

auto &&one_side =
[&merger](bool first,
[&](bool first,
DimensionAxis::Item::PosType DimensionAxis::Item::*pos,
const Val *&paramOther)
{
return [&, first, pos](const Val &val) -> Val
{
if (paramOther && paramOther->first == val.first) {
auto &&res = first ? merger(val, *paramOther)
: merger(*paramOther, val);
if (paramOther
&& std::is_eq(
comparator(paramOther->first, val.first))) {
auto &&res = first
? merger(val, *paramOther)
: merger(*paramOther, val, &val.first);
(res.second.*pos).makeAuto();
return res;
}
Expand All @@ -334,11 +382,13 @@ DimensionAxis interpolate(const DimensionAxis &op0,
op1.values,
res.values,
Alg::merge_args{.projection = &Val::first,
.comparator = comparator,
.transformer_1 =
one_side(true, &DimensionAxis::Item::endPos, latest2),
.transformer_2 = one_side(false,
&DimensionAxis::Item::startPos,
latest1),
.need_merge = needMerge,
.merger = merger});

return res;
Expand Down Expand Up @@ -438,7 +488,7 @@ interpolate(const SplitAxis &op0, const SplitAxis &op1, double factor)
}
else
res.parts
.insert({std::nullopt,
.insert({{},
{.weight =
op0.parts.empty() ? 1 - factor : factor}})
->second.unique = true;
Expand Down
48 changes: 34 additions & 14 deletions src/chart/generator/axis.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define AXIS_H

#include <map>
#include <ranges>

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

Refl::EnumArray<ChannelId, TrackType> tracked;
Math::Range<> lightness;
Expand All @@ -35,9 +36,9 @@ struct ChannelStats
void track(ChannelId at, const Data::MarkerId &id)
{
auto &vec = std::get<1>(tracked[at]);
if (id.label)
if (!id.label.empty())
vec.try_emplace(static_cast<std::uint32_t>(id.itemId),
*id.label);
id.label);
}

void track(ChannelId at, const double &value)
Expand Down Expand Up @@ -128,13 +129,13 @@ struct DimensionAxis
friend Item
interpolate(const Item &op0, const Item &op1, double factor);
};
using Values = std::multimap<Data::SliceIndex, Item>;
using Values = std::multimap<std::vector<Data::SliceIndex>, Item>;

double factor{};
bool hasMarker{};

DimensionAxis() = default;
bool add(const Data::SliceIndex &index,
bool add(const std::vector<Data::SliceIndex> &index,
const Math::Range<> &range,
std::uint32_t position,
const std::optional<ColorBase> &color,
Expand All @@ -145,19 +146,19 @@ struct DimensionAxis

[[nodiscard]] auto begin()
{
return std::ranges::views::values(values).begin();
return std::views::values(values).begin();
};
[[nodiscard]] auto end()
{
return std::ranges::views::values(values).end();
return std::views::values(values).end();
}
[[nodiscard]] auto begin() const
{
return std::ranges::views::values(values).begin();
return std::views::values(values).begin();
};
[[nodiscard]] auto end() const
{
return std::ranges::views::values(values).end();
return std::views::values(values).end();
}
[[nodiscard]] bool empty() const { return values.empty(); }
bool setLabels(double step);
Expand All @@ -179,6 +180,23 @@ struct DimensionAxis
ItemSorterByRangeStart>{begin(), end()};
}

static std::size_t commonDimensionParts(const Values &lhs,
const Values &rhs);

template <std::string Data::SliceIndex::*which =
&Data::SliceIndex::value>
[[nodiscard]] static std::string mergedLabels(
const std::vector<Data::SliceIndex> &slices)
{
return std::ranges::to<std::string>(
std::views::transform(slices,
[](const Data::SliceIndex &slice)
{
return ", " + slice.*which;
})
| std::views::join | std::views::drop(2));
}

private:
Values values;
};
Expand All @@ -189,10 +207,13 @@ struct Axis
MeasureAxis measure;
DimensionAxis dimension;

[[nodiscard]] const std::string &seriesName() const
[[nodiscard]] std::string seriesName() const
{
if (!dimension.empty())
return dimension.getValues().begin()->first.column;
if (!dimension.empty()) {
return DimensionAxis::mergedLabels<
&Data::SliceIndex::column>(
dimension.getValues().begin()->first);
}
return measure.series;
}

Expand Down Expand Up @@ -220,8 +241,7 @@ struct SplitAxis : Axis
}
};

using Parts =
std::multimap<std::optional<Data::SliceIndex>, Part>;
using Parts = std::multimap<std::vector<Data::SliceIndex>, Part>;
Parts parts;

[[nodiscard]] bool operator==(
Expand Down
2 changes: 1 addition & 1 deletion src/chart/generator/buckets.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ struct Buckets

[[nodiscard]] auto operator*() const
{
return std::ranges::views::transform(data,
return std::views::transform(data,
[this](Marker *marker)
-> std::pair<Marker &, const Data::MarkerId &>
{
Expand Down
Loading