diff --git a/src/base/conv/numtostr.cpp b/src/base/conv/numtostr.cpp index d27b698b3..c01ab2810 100644 --- a/src/base/conv/numtostr.cpp +++ b/src/base/conv/numtostr.cpp @@ -51,9 +51,7 @@ std::string NumberToString::convert(double number) } if (number_view.starts_with('-') - && number_view.find_last_not_of(std::string_view{ - std::initializer_list{'0', ',', '.', '\0'}}) - == 0) { + && number_view.find_last_not_of("0,.") == 0) { number_view.remove_prefix(1); ++begin; --decimalPoint; diff --git a/src/chart/animator/morph.cpp b/src/chart/animator/morph.cpp index d8f793d4f..8146f948b 100644 --- a/src/chart/animator/morph.cpp +++ b/src/chart/animator/morph.cpp @@ -1,5 +1,6 @@ #include "morph.h" +#include #include #include @@ -16,7 +17,51 @@ namespace Vizzu::Anim::Morph { -using Math::interpolate; +template struct interpolatable_t +{ + constexpr bool operator()() const + { + using Math::interpolate; + return requires(const T &a, const T &b, double factor) { + { + interpolate(a, b, factor) + } -> std::same_as; + }; + } +}; + +template concept interpolatable = interpolatable_t{}(); + +struct interpolate_t +{ + template + constexpr T + operator()(const T &a, const T &b, double factor) const; +}; + +constexpr inline static interpolate_t interpolate{}; + +template +constexpr T +interpolate_t::operator()(const T &a, const T &b, double factor) const +{ + if constexpr (interpolatable) { + using Math::interpolate; + return interpolate(a, b, factor); + } + else { + T res; + Refl::visit( + [factor](V &res, const V &op0, const V &op1) + { + res = Morph::interpolate(op0, op1, factor); + }, + res, + a, + b); + return res; + } +} AbstractMorph::AbstractMorph(const Gen::Plot &source, const Gen::Plot &target, @@ -116,19 +161,9 @@ void Horizontal::transform(const Gen::Plot &source, Gen::Plot &actual, double factor) const { - actual.axises.at(Gen::ChannelId::x).common = - interpolate(source.axises.at(Gen::ChannelId::x).common, - target.axises.at(Gen::ChannelId::x).common, - factor); - - actual.axises.at(Gen::ChannelId::x).measure = - interpolate(source.axises.at(Gen::ChannelId::x).measure, - target.axises.at(Gen::ChannelId::x).measure, - factor); - - actual.axises.at(Gen::ChannelId::x).dimension = - interpolate(source.axises.at(Gen::ChannelId::x).dimension, - target.axises.at(Gen::ChannelId::x).dimension, + actual.axises.at(Gen::AxisId::x) = + interpolate(source.axises.at(Gen::AxisId::x), + target.axises.at(Gen::AxisId::x), factor); actual.keepAspectRatio = interpolate(source.keepAspectRatio, @@ -191,34 +226,14 @@ void Vertical::transform(const Gen::Plot &source, Gen::Plot &actual, double factor) const { - actual.axises.at(Gen::ChannelId::y).common = - interpolate(source.axises.at(Gen::ChannelId::y).common, - target.axises.at(Gen::ChannelId::y).common, + actual.axises.at(Gen::AxisId::y) = + interpolate(source.axises.at(Gen::AxisId::y), + target.axises.at(Gen::AxisId::y), factor); - actual.axises.at(Gen::ChannelId::y).measure = - interpolate(source.axises.at(Gen::ChannelId::y).measure, - target.axises.at(Gen::ChannelId::y).measure, - factor); - - actual.axises.at(Gen::ChannelId::y).dimension = - interpolate(source.axises.at(Gen::ChannelId::y).dimension, - target.axises.at(Gen::ChannelId::y).dimension, - factor); - - actual.axises.at(Gen::ChannelId::size).common = - interpolate(source.axises.at(Gen::ChannelId::size).common, - target.axises.at(Gen::ChannelId::size).common, - factor); - - actual.axises.at(Gen::ChannelId::size).measure = - interpolate(source.axises.at(Gen::ChannelId::size).measure, - target.axises.at(Gen::ChannelId::size).measure, - factor); - - actual.axises.at(Gen::ChannelId::size).dimension = - interpolate(source.axises.at(Gen::ChannelId::size).dimension, - target.axises.at(Gen::ChannelId::size).dimension, + actual.axises.at(Gen::ChannelId::size) = + interpolate(source.axises.at(Gen::ChannelId::size), + target.axises.at(Gen::ChannelId::size), factor); actual.guides.y = @@ -250,35 +265,14 @@ void Morph::Color::transform(const Gen::Plot &source, Gen::Plot &actual, double factor) const { - actual.axises.at(Gen::ChannelId::color).common = - interpolate(source.axises.at(Gen::ChannelId::color).common, - target.axises.at(Gen::ChannelId::color).common, + actual.axises.at(Gen::ChannelId::color) = + interpolate(source.axises.at(Gen::ChannelId::color), + target.axises.at(Gen::ChannelId::color), factor); - actual.axises.at(Gen::ChannelId::color).measure = - interpolate(source.axises.at(Gen::ChannelId::color).measure, - target.axises.at(Gen::ChannelId::color).measure, - factor); - - actual.axises.at(Gen::ChannelId::color).dimension = - interpolate(source.axises.at(Gen::ChannelId::color).dimension, - target.axises.at(Gen::ChannelId::color).dimension, - factor); - - actual.axises.at(Gen::ChannelId::lightness).common = interpolate( - source.axises.at(Gen::ChannelId::lightness).common, - target.axises.at(Gen::ChannelId::lightness).common, - factor); - - actual.axises.at(Gen::ChannelId::lightness).measure = interpolate( - source.axises.at(Gen::ChannelId::lightness).measure, - target.axises.at(Gen::ChannelId::lightness).measure, - factor); - - actual.axises.at(Gen::ChannelId::lightness).dimension = - interpolate( - source.axises.at(Gen::ChannelId::lightness).dimension, - target.axises.at(Gen::ChannelId::lightness).dimension, + actual.axises.at(Gen::ChannelId::lightness) = + interpolate(source.axises.at(Gen::ChannelId::lightness), + target.axises.at(Gen::ChannelId::lightness), factor); } diff --git a/src/chart/animator/planner.cpp b/src/chart/animator/planner.cpp index 1378a6cb3..741000361 100644 --- a/src/chart/animator/planner.cpp +++ b/src/chart/animator/planner.cpp @@ -352,28 +352,11 @@ bool Planner::positionMorphNeeded() const bool Planner::needColor() const { return (isAnyLegend(Gen::ChannelId::color) - && (source->axises.at(Gen::ChannelId::color).common - != target->axises.at(Gen::ChannelId::color) - .common - || source->axises.at(Gen::ChannelId::color) - .dimension - != target->axises.at(Gen::ChannelId::color) - .dimension - || source->axises.at(Gen::ChannelId::color).measure - != target->axises.at(Gen::ChannelId::color) - .measure)) + && source->axises.at(Gen::ChannelId::color) + != target->axises.at(Gen::ChannelId::color)) || (isAnyLegend(Gen::ChannelId::lightness) - && (source->axises.at(Gen::ChannelId::lightness).common - != target->axises.at(Gen::ChannelId::lightness) - .common - || source->axises.at(Gen::ChannelId::lightness) - .dimension - != target->axises.at(Gen::ChannelId::lightness) - .dimension - || source->axises.at(Gen::ChannelId::lightness) - .measure - != target->axises.at(Gen::ChannelId::lightness) - .measure)) + && source->axises.at(Gen::ChannelId::lightness) + != target->axises.at(Gen::ChannelId::lightness)) || anyMarker(+[](const Gen::Marker &source, const Gen::Marker &target) -> bool { @@ -419,23 +402,13 @@ bool Planner::verticalBeforeHorizontal() const bool Planner::needVertical() const { - return source->axises.at(Gen::ChannelId::y).common - != target->axises.at(Gen::ChannelId::y).common - || source->axises.at(Gen::ChannelId::y).measure - != target->axises.at(Gen::ChannelId::y).measure - || source->axises.at(Gen::ChannelId::y).dimension - != target->axises.at(Gen::ChannelId::y).dimension + return source->axises.at(Gen::AxisId::y) + != target->axises.at(Gen::AxisId::y) || source->guides.at(Gen::AxisId::y) != target->guides.at(Gen::AxisId::y) || (isAnyLegend(Gen::ChannelId::size) - && (source->axises.at(Gen::ChannelId::size).common - != target->axises.at(Gen::ChannelId::size).common - || source->axises.at(Gen::ChannelId::size).measure - != target->axises.at(Gen::ChannelId::size) - .measure - || source->axises.at(Gen::ChannelId::size).dimension - != target->axises.at(Gen::ChannelId::size) - .dimension)) + && source->axises.at(Gen::ChannelId::size) + != target->axises.at(Gen::ChannelId::size)) || (source->markerConnectionOrientation != target->markerConnectionOrientation && (source->markerConnectionOrientation.value_or( @@ -465,12 +438,8 @@ bool Planner::needVertical() const bool Planner::needHorizontal() const { - return source->axises.at(Gen::ChannelId::x).common - != target->axises.at(Gen::ChannelId::x).common - || source->axises.at(Gen::ChannelId::x).measure - != target->axises.at(Gen::ChannelId::x).measure - || source->axises.at(Gen::ChannelId::x).dimension - != target->axises.at(Gen::ChannelId::x).dimension + return source->axises.at(Gen::AxisId::x) + != target->axises.at(Gen::AxisId::x) || source->guides.at(Gen::AxisId::x) != target->guides.at(Gen::AxisId::x) || source->keepAspectRatio != target->keepAspectRatio diff --git a/src/chart/generator/axis.cpp b/src/chart/generator/axis.cpp index 4ced0f0dd..d0b4a3f22 100644 --- a/src/chart/generator/axis.cpp +++ b/src/chart/generator/axis.cpp @@ -22,17 +22,10 @@ namespace Vizzu::Gen { -CommonAxis interpolate(const CommonAxis &op0, - const CommonAxis &op1, - double factor) -{ - return {interpolate(op0.title, op1.title, factor)}; -} - Geom::Point Axises::origo() const { - return {at(ChannelId::x).measure.origo(), - at(ChannelId::y).measure.origo()}; + return {at(AxisId::x).measure.origo(), + at(AxisId::y).measure.origo()}; } MeasureAxis::MeasureAxis(Math::Range interval, @@ -64,8 +57,6 @@ double MeasureAxis::origo() const return -range.getMin() / range.size(); } -void MeasureAxis::track(double value) { trackedRange.include(value); } - MeasureAxis interpolate(const MeasureAxis &op0, const MeasureAxis &op1, double factor) @@ -240,11 +231,6 @@ bool DimensionAxis::setLabels(double step) return hasLabel; } -void DimensionAxis::track(const Data::MarkerId &id) -{ - (*trackedValues)[id.itemId] = id.label; -} - DimensionAxis interpolate(const DimensionAxis &op0, const DimensionAxis &op1, double factor) diff --git a/src/chart/generator/axis.h b/src/chart/generator/axis.h index 1e07318c0..9163f8319 100644 --- a/src/chart/generator/axis.h +++ b/src/chart/generator/axis.h @@ -16,20 +16,34 @@ namespace Vizzu::Gen { -struct CommonAxis + +struct ChannelStats { - ::Anim::String title; + using TrackType = std::variant, + std::vector>>; - [[nodiscard]] bool operator==(const CommonAxis &) const = default; -}; + Refl::EnumArray tracked; -CommonAxis interpolate(const CommonAxis &op0, - const CommonAxis &op1, - double factor); + void track(ChannelId at, const Data::MarkerId &id) + { + auto &vec = std::get<1>(tracked.at(at)); + vec[id.itemId] = id.label; + } + + void track(ChannelId at, const double &value) + { + std::get<0>(tracked.at(at)).include(value); + } + + void setIfRange(AxisId at, const Math::Range &range) + { + if (auto *r = std::get_if<0>(&tracked.at(asChannel(at)))) + *r = range; + } +}; struct MeasureAxis { - Math::Range trackedRange; ::Anim::Interpolated enabled{false}; Math::Range range = Math::Range::Raw(0, 1); ::Anim::String unit; @@ -42,8 +56,6 @@ struct MeasureAxis std::optional step); bool operator==(const MeasureAxis &other) const; [[nodiscard]] double origo() const; - - void track(double value); }; MeasureAxis interpolate(const MeasureAxis &op0, @@ -103,8 +115,6 @@ struct DimensionAxis bool enabled{false}; std::string category{}; - std::shared_ptr>> - trackedValues; DimensionAxis() = default; bool add(const Data::SliceIndex &index, @@ -124,7 +134,6 @@ struct DimensionAxis return values.cend(); } bool setLabels(double step); - void track(const Data::MarkerId &id); private: Values values; @@ -136,9 +145,11 @@ DimensionAxis interpolate(const DimensionAxis &op0, struct Axis { - CommonAxis common; + ::Anim::String title; MeasureAxis measure; DimensionAxis dimension; + + [[nodiscard]] bool operator==(const Axis &other) const = default; }; struct Axises diff --git a/src/chart/generator/guides.cpp b/src/chart/generator/guides.cpp index 99321f0b9..ee6edf97b 100644 --- a/src/chart/generator/guides.cpp +++ b/src/chart/generator/guides.cpp @@ -1,6 +1,5 @@ #include "guides.h" -#include "base/math/interpolation.h" #include "chart/options/align.h" #include "chart/options/channel.h" #include "chart/options/coordsystem.h" @@ -10,24 +9,6 @@ namespace Vizzu::Gen { -GuidesByAxis interpolate(const GuidesByAxis &op0, - const GuidesByAxis &op1, - double factor) -{ - GuidesByAxis res; - res.axis = interpolate(op0.axis, op1.axis, factor); - res.labels = interpolate(op0.labels, op1.labels, factor); - res.axisSticks = - interpolate(op0.axisSticks, op1.axisSticks, factor); - res.axisGuides = - interpolate(op0.axisGuides, op1.axisGuides, factor); - res.markerGuides = - interpolate(op0.markerGuides, op1.markerGuides, factor); - res.interlacings = - interpolate(op0.interlacings, op1.interlacings, factor); - return res; -} - bool GuidesByAxis::operator==(const GuidesByAxis &other) const { return axis == other.axis && labels == other.labels @@ -39,8 +20,8 @@ bool GuidesByAxis::operator==(const GuidesByAxis &other) const Guides::Guides(const Options &options) { - const auto &channelX = options.getChannels().at(ChannelId::x); - const auto &channelY = options.getChannels().at(ChannelId::y); + const auto &channelX = options.getChannels().at(AxisId::x); + const auto &channelY = options.getChannels().at(AxisId::y); if (channelX.isEmpty() && channelY.isEmpty()) return; auto xIsMeasure = channelX.isMeasure(); @@ -49,8 +30,8 @@ Guides::Guides(const Options &options) auto isCircle = options.geometry.get() == ShapeType::circle; auto isHorizontal = options.isHorizontal(); - const auto &xOpt = options.getChannels().at(ChannelId::x); - const auto &yOpt = options.getChannels().at(ChannelId::y); + const auto &xOpt = options.getChannels().at(AxisId::x); + const auto &yOpt = options.getChannels().at(AxisId::y); x.axis = xOpt.axisLine.getValue(yIsMeasure); y.axis = yOpt.axisLine.getValue(xIsMeasure && !isPolar); diff --git a/src/chart/generator/guides.h b/src/chart/generator/guides.h index 4c8fd731b..01391e9d5 100644 --- a/src/chart/generator/guides.h +++ b/src/chart/generator/guides.h @@ -22,10 +22,6 @@ struct GuidesByAxis bool operator==(const GuidesByAxis &other) const; }; -GuidesByAxis interpolate(const GuidesByAxis &op0, - const GuidesByAxis &op1, - double factor); - struct Guides { GuidesByAxis x; diff --git a/src/chart/generator/marker.cpp b/src/chart/generator/marker.cpp index 485117ecb..325f09653 100644 --- a/src/chart/generator/marker.cpp +++ b/src/chart/generator/marker.cpp @@ -10,6 +10,7 @@ #include "base/geom/rect.h" #include "base/math/range.h" #include "chart/options/align.h" +#include "chart/options/channel.h" #include "chart/options/coordsystem.h" #include "chart/options/shapetype.h" #include "dataframe/old/datatable.h" @@ -22,7 +23,7 @@ namespace Vizzu::Gen Marker::Marker(const Options &options, const Data::DataCube &data, - Axises &stats, + ChannelStats &stats, const Data::SeriesList &mainAxisList, const Data::SeriesList &subAxisList, const Data::MultiIndex &index, @@ -82,15 +83,15 @@ Marker::Marker(const Options &options, horizontal ? &mainId : subAxisId); auto yChannelRectDim = - channels.at(ChannelId::y).isDimension() - && channels.at(ChannelId::y).hasDimension() + channels.at(AxisId::y).isDimension() + && channels.at(AxisId::y).hasDimension() && options.geometry == ShapeType::rectangle && options.align != Base::Align::Type::stretch; spacing.x = (horizontal || (lineOrCircle && !polar) || yChannelRectDim) && options.getChannels().anyAxisSet() - && channels.at(ChannelId::x).isDimension() + && channels.at(AxisId::x).isDimension() ? 1 : 0; @@ -102,14 +103,14 @@ Marker::Marker(const Options &options, !horizontal ? &mainId : subAxisId); auto xChannelRectDim = - channels.at(ChannelId::x).isDimension() - && channels.at(ChannelId::x).hasDimension() + channels.at(AxisId::x).isDimension() + && channels.at(AxisId::x).hasDimension() && options.geometry == ShapeType::rectangle && options.align != Base::Align::Type::stretch; spacing.y = (!horizontal || lineOrCircle || xChannelRectDim) && options.getChannels().anyAxisSet() - && channels.at(ChannelId::y).isDimension() + && channels.at(AxisId::y).isDimension() ? 1 : 0; @@ -165,7 +166,7 @@ Conv::JSONObj &&Marker::appendToJSON(Conv::JSONObj &&jsonObj) const double Marker::getValueForChannel(const Channels &channels, ChannelId type, const Data::DataCube &data, - Axises &stats, + ChannelStats &stats, const Data::MultiIndex &index, const Data::MarkerId *mid) const { @@ -175,8 +176,6 @@ double Marker::getValueForChannel(const Channels &channels, double value{}; - auto &stat = stats.at(type); - if (channel.isDimension()) { std::optional nid; if (!mid) @@ -189,7 +188,7 @@ double Marker::getValueForChannel(const Channels &channels, else value = static_cast(id.itemId); - if (enabled) stat.dimension.track(id); + if (enabled) stats.track(type, id); } else { if (const auto &measure = *channel.measureId; @@ -198,7 +197,7 @@ double Marker::getValueForChannel(const Channels &channels, else value = data.valueAt(index, measure); - if (enabled) stat.measure.track(value); + if (enabled) stats.track(type, value); } return value; } diff --git a/src/chart/generator/marker.h b/src/chart/generator/marker.h index eaf7ba676..da104849b 100644 --- a/src/chart/generator/marker.h +++ b/src/chart/generator/marker.h @@ -17,7 +17,7 @@ namespace Vizzu::Gen { -struct Axises; +struct ChannelStats; class Marker { @@ -27,7 +27,7 @@ class Marker Marker(const Options &options, const Data::DataCube &data, - Axises &stats, + ChannelStats &stats, const Data::SeriesList &mainAxisList, const Data::SeriesList &subAxisList, const Data::MultiIndex &index, @@ -97,7 +97,7 @@ class Marker double getValueForChannel(const Channels &channels, ChannelId type, const Data::DataCube &data, - Axises &stats, + ChannelStats &stats, const Data::MultiIndex &index, const Data::MarkerId * = nullptr) const; }; diff --git a/src/chart/generator/plotbuilder.cpp b/src/chart/generator/plotbuilder.cpp index 80ed148f1..37dc3dc41 100644 --- a/src/chart/generator/plotbuilder.cpp +++ b/src/chart/generator/plotbuilder.cpp @@ -64,28 +64,15 @@ PlotBuilder::PlotBuilder(const Data::DataTable &dataTable, normalizeColors(); addAlignment(subBuckets); } - - resetDimensionTrackers(); } -void PlotBuilder::initDimensionTrackers() const +void PlotBuilder::initDimensionTrackers() { for (const auto &ch : plot->options->getChannels().getChannels()) { if (!ch.isDimension()) continue; - plot->axises.at(ch.type).dimension.trackedValues = - std::make_shared< - std::vector>>( - dataCube.combinedSizeOf(ch.dimensions()).second); - } -} - -void PlotBuilder::resetDimensionTrackers() const -{ - for (const Channel &ch : - plot->options->getChannels().getChannels()) { - if (!ch.isDimension()) continue; - plot->axises.at(ch.type).dimension.trackedValues.reset(); + stats.tracked.at(ch.type).emplace<1>( + dataCube.combinedSizeOf(ch.dimensions()).second); } } @@ -108,7 +95,7 @@ Buckets PlotBuilder::generateMarkers(std::size_t &mainBucketSize) for (auto &&index : dataCube) plot->markers.emplace_back(*plot->getOptions(), dataCube, - plot->axises, + stats, mainIds, subIds, index, @@ -135,11 +122,11 @@ Buckets PlotBuilder::generateMarkers(std::size_t &mainBucketSize) && plot->getOptions()->geometry.get() == ShapeType::line && plot->getOptions() ->getChannels() - .at(ChannelId::x) + .at(AxisId::x) .isDimension() && plot->getOptions() ->getChannels() - .at(ChannelId::y) + .at(AxisId::y) .isDimension()) { plot->markerConnectionOrientation.emplace( *plot->getOptions()->orientation.get()); @@ -205,12 +192,6 @@ void PlotBuilder::addSpecLayout(Buckets &buckets) } } -Math::Range &PlotBuilder::getMeasTrackRange( - ChannelId type) const -{ - return plot->axises.at(type).measure.trackedRange; -} - bool PlotBuilder::linkMarkers(const Buckets &buckets, bool main) const { auto &&sorted = sortedBuckets(buckets, main); @@ -337,8 +318,8 @@ void PlotBuilder::normalizeXY() ++markerIt; if (markerIt == plot->markers.end()) { - getMeasTrackRange(ChannelId::x) = xrange.getRange({0.0, 0.0}); - getMeasTrackRange(ChannelId::y) = yrange.getRange({0.0, 0.0}); + stats.setIfRange(AxisId::x, xrange.getRange({0.0, 0.0})); + stats.setIfRange(AxisId::y, xrange.getRange({0.0, 0.0})); return; } @@ -366,10 +347,12 @@ void PlotBuilder::normalizeXY() marker.fromRectangle(newRect); } - getMeasTrackRange(ChannelId::x) = - Math::Range::Raw(boundRect.left(), boundRect.right()); - getMeasTrackRange(ChannelId::y) = - Math::Range::Raw(boundRect.bottom(), boundRect.top()); + stats.setIfRange(AxisId::x, + Math::Range::Raw(boundRect.left(), + boundRect.right())); + stats.setIfRange(AxisId::y, + Math::Range::Raw(boundRect.bottom(), + boundRect.top())); } void PlotBuilder::calcMeasureAxises(const Data::DataTable &dataTable) @@ -382,18 +365,16 @@ void PlotBuilder::calcMeasureAxises(const Data::DataTable &dataTable) void PlotBuilder::calcMeasureAxis(const Data::DataTable &dataTable, ChannelId type) { - auto &axis = plot->axises.at(type).measure; const auto &scale = plot->getOptions()->getChannels().at(type); - auto range = getMeasTrackRange(type); if (auto &&meas = scale.measureId) { - - if (auto &title = plot->axises.at(type).common.title; + if (auto &title = plot->axises.at(type).title; scale.title.isAuto()) title = dataCube.getName(*meas); else if (scale.title) title = *scale.title; - if (type == plot->getOptions()->subAxisType() + if (auto &axis = plot->axises.at(type).measure; + type == plot->getOptions()->subAxisType() && plot->getOptions()->align == Base::Align::Type::stretch) { axis = {Math::Range::Raw(0, 100), @@ -402,6 +383,7 @@ void PlotBuilder::calcMeasureAxis(const Data::DataTable &dataTable, scale.step.getValue()}; } else { + auto &&range = std::get<0>(stats.tracked.at(type)); axis = {range.isReal() ? range : Math::Range::Raw(0, 0), dataTable.getUnit(meas->getColIndex()), @@ -409,9 +391,6 @@ void PlotBuilder::calcMeasureAxis(const Data::DataTable &dataTable, scale.step.getValue()}; } } - else - axis = {}; - axis.trackedRange = range; } void PlotBuilder::calcDimensionAxises() @@ -434,7 +413,7 @@ void PlotBuilder::calcDimensionAxis(ChannelId type) if (!marker.enabled) continue; const auto &id = - (type == ChannelId::x) + (type == AxisId::x) == plot->getOptions()->isHorizontal() ? marker.mainId : marker.subId; @@ -442,13 +421,12 @@ void PlotBuilder::calcDimensionAxis(ChannelId type) if (const auto &slice = id.label) axis.add(*slice, static_cast(id.itemId), - marker.getSizeBy(type == ChannelId::x), + marker.getSizeBy(type == AxisId::x), merge); } } else { - const auto &indices = - *plot->axises.at(type).dimension.trackedValues; + const auto &indices = std::get<1>(stats.tracked.at(type)); double count = 0; for (auto i = 0U; i < indices.size(); ++i) @@ -463,8 +441,8 @@ void PlotBuilder::calcDimensionAxis(ChannelId type) if (auto &&series = scale.labelSeries()) axis.category = series.value().getColIndex(); - auto &title = plot->axises.at(type).common.title; - if (scale.title.isAuto() && !hasLabel) + if (auto &title = plot->axises.at(type).title; + scale.title.isAuto() && !hasLabel) title = axis.category; else if (scale.title) title = *scale.title; @@ -612,10 +590,8 @@ void PlotBuilder::normalizeColors() cbase.setPos(color.rescale(cbase.getPos())); } - plot->axises.at(ChannelId::color).measure.range = - getMeasTrackRange(ChannelId::color) = color; - plot->axises.at(ChannelId::lightness).measure.range = - getMeasTrackRange(ChannelId::lightness) = lightness; + plot->axises.at(ChannelId::color).measure.range = color; + plot->axises.at(ChannelId::lightness).measure.range = lightness; for (auto &value : plot->axises.at(ChannelId::color).dimension) value.second.colorBase = diff --git a/src/chart/generator/plotbuilder.h b/src/chart/generator/plotbuilder.h index 89d2ea80d..ab536d1b5 100644 --- a/src/chart/generator/plotbuilder.h +++ b/src/chart/generator/plotbuilder.h @@ -5,6 +5,7 @@ #include "chart/options/options.h" #include "dataframe/old/datatable.h" +#include "axis.h" #include "plotptr.h" namespace Vizzu::Gen @@ -24,6 +25,7 @@ class PlotBuilder private: Data::DataCube dataCube; PlotPtr plot; + ChannelStats stats; struct BucketInfo { @@ -31,8 +33,7 @@ class PlotBuilder double size{}; }; - void initDimensionTrackers() const; - void resetDimensionTrackers() const; + void initDimensionTrackers(); Buckets generateMarkers(std::size_t &mainBucketSize); [[nodiscard]] bool linkMarkers(const Buckets &buckets, bool main) const; @@ -50,9 +51,6 @@ class PlotBuilder [[nodiscard]] std::vector sortedBuckets(const Buckets &buckets, bool main) const; void addSpecLayout(Buckets &buckets); - - [[nodiscard]] Math::Range &getMeasTrackRange( - ChannelId type) const; }; } diff --git a/src/chart/main/stylesheet.cpp b/src/chart/main/stylesheet.cpp index f6917de63..c9f65f96d 100644 --- a/src/chart/main/stylesheet.cpp +++ b/src/chart/main/stylesheet.cpp @@ -103,7 +103,7 @@ void Sheet::setAxisLabels() def.side = AxisLabel::Side::positive; } else if (const auto &xAxis = - options->getChannels().at(Gen::ChannelId::x); + options->getChannels().at(Gen::AxisId::x); xAxis.isDimension() && xAxis.hasDimension() && options->angle == 0) def.angle.reset(); @@ -221,7 +221,7 @@ void Sheet::setAfterStyles(Gen::Plot &plot, const Geom::Size &size) std::vector> ranges; bool has_collision = false; for (const auto &pair : - plot.axises.at(Gen::ChannelId::x).dimension) { + plot.axises.at(Gen::AxisId::x).dimension) { if (pair.second.weight == 0) continue; diff --git a/src/chart/options/channel.cpp b/src/chart/options/channel.cpp index 46cc995ab..e45556883 100644 --- a/src/chart/options/channel.cpp +++ b/src/chart/options/channel.cpp @@ -16,24 +16,6 @@ namespace Vizzu::Gen { -std::optional asAxis(ChannelId type) -{ - return type == ChannelId::x || type == ChannelId::y - ? std::make_optional(static_cast( - static_cast(type))) - : std::nullopt; -} - -ChannelId asChannel(AxisId type) -{ - return static_cast(static_cast(type)); -} - -bool operator==(const AxisId &axis, const ChannelId &channel) -{ - return asChannel(axis) == channel; -} - Channel Channel::makeChannel(Type id) { switch (id) { diff --git a/src/chart/options/channel.h b/src/chart/options/channel.h index cc1020c68..f06b0465a 100644 --- a/src/chart/options/channel.h +++ b/src/chart/options/channel.h @@ -91,11 +91,26 @@ class Channel Base::AutoParam step{}; }; -std::optional asAxis(ChannelId type); -ChannelId asChannel(AxisId type); +[[nodiscard]] constexpr std::optional asAxis(ChannelId type) +{ + switch (type) { + case ChannelId::x: + case ChannelId::y: + return static_cast(static_cast(type)); + default: return std::nullopt; + } +} -[[nodiscard]] bool operator==(const AxisId &axis, - const ChannelId &channel); +[[nodiscard]] constexpr ChannelId asChannel(AxisId type) +{ + return static_cast(static_cast(type)); +} + +[[nodiscard]] constexpr bool operator==(const AxisId &axis, + const ChannelId &channel) +{ + return asChannel(axis) == channel; +} } diff --git a/src/chart/options/options.cpp b/src/chart/options/options.cpp index 5a73ba17b..013fe8fb7 100644 --- a/src/chart/options/options.cpp +++ b/src/chart/options/options.cpp @@ -9,7 +9,6 @@ #include "base/math/trig.h" #include "dataframe/old/types.h" -#include "align.h" #include "channel.h" #include "channelrange.h" #include "coordsystem.h" @@ -211,16 +210,15 @@ bool Options::sameAttributes(const Options &other) const && markersInfo == other.markersInfo; } -ChannelId Options::getHorizontalChannel() const +AxisId Options::getHorizontalChannel() const { - return Math::rad2quadrant(angle) % 2 == 0 ? ChannelId::x - : ChannelId::y; + return Math::rad2quadrant(angle) % 2 == 0 ? AxisId::x : AxisId::y; } -ChannelId Options::getVerticalChannel() const +AxisId Options::getVerticalChannel() const { - return getHorizontalChannel() == ChannelId::x ? ChannelId::y - : ChannelId::x; + return getHorizontalChannel() == AxisId::x ? AxisId::y + : AxisId::x; } bool Options::isShapeValid(const ShapeType &shapeType) const @@ -259,8 +257,8 @@ void Options::setAutoParameters() Orientation Options::getAutoOrientation() const { - if (const auto &x = getChannels().at(ChannelId::x), - &y = getChannels().at(ChannelId::y); + if (const auto &x = getChannels().at(AxisId::x), + &y = getChannels().at(AxisId::y); x.isMeasure() && (y.isDimension() || (!x.hasDimension() && y.hasDimension()))) @@ -280,8 +278,8 @@ std::optional Options::getAutoLegend() const if (auto &&meas = channels.at(ChannelId::label).measureId) series.erase(*meas); - for (auto channelId : {ChannelId::x, ChannelId::y}) - if (auto id = channels.at(channelId).labelSeries()) + for (auto axisId : {AxisId::x, AxisId::y}) + if (auto id = channels.at(axisId).labelSeries()) series.erase(*id); for (auto channelId : {LegendId::color, LegendId::lightness}) @@ -340,8 +338,8 @@ void Options::setRange(Channel &channel, bool Options::labelsShownFor(const Data::SeriesIndex &series) const { - return channels.at(ChannelId::x).labelSeries() == series - || channels.at(ChannelId::y).labelSeries() == series + return channels.at(AxisId::x).labelSeries() == series + || channels.at(AxisId::y).labelSeries() == series || (legend.get() && channels.at(toChannel(*legend.get())).labelSeries() == series); diff --git a/src/chart/options/options.h b/src/chart/options/options.h index 2fda34cbc..241a1e690 100644 --- a/src/chart/options/options.h +++ b/src/chart/options/options.h @@ -146,8 +146,8 @@ class Options void intersection(const Options &other); void simplify(); - [[nodiscard]] ChannelId getHorizontalChannel() const; - [[nodiscard]] ChannelId getVerticalChannel() const; + [[nodiscard]] AxisId getHorizontalChannel() const; + [[nodiscard]] AxisId getVerticalChannel() const; [[nodiscard]] const Channel &getHorizontalAxis() const { diff --git a/src/chart/rendering/drawaxes.cpp b/src/chart/rendering/drawaxes.cpp index 53e07b186..6d2060b45 100644 --- a/src/chart/rendering/drawaxes.cpp +++ b/src/chart/rendering/drawaxes.cpp @@ -168,7 +168,7 @@ Geom::Point DrawAxes::getTitleOffset(Gen::AxisId axisIndex, void DrawAxes::drawTitle(Gen::AxisId axisIndex) const { - const auto &titleString = plot->axises.at(axisIndex).common.title; + const auto &titleString = plot->axises.at(axisIndex).title; const auto &titleStyle = rootStyle.plot.getAxis(axisIndex).title; diff --git a/src/chart/rendering/drawlegend.cpp b/src/chart/rendering/drawlegend.cpp index 9b6896672..970989a61 100644 --- a/src/chart/rendering/drawlegend.cpp +++ b/src/chart/rendering/drawlegend.cpp @@ -121,7 +121,7 @@ const Gfx::LinearGradient &DrawLegend::FadeBarGradient::operator()( void DrawLegend::drawTitle(const Info &info) const { plot->axises.at(info.properties.channel) - .common.title.visit( + .title.visit( [this, &info, &rect = info.titleRect, diff --git a/src/chart/rendering/markers/abstractmarker.cpp b/src/chart/rendering/markers/abstractmarker.cpp index b4b929eaa..172dbb04b 100644 --- a/src/chart/rendering/markers/abstractmarker.cpp +++ b/src/chart/rendering/markers/abstractmarker.cpp @@ -6,6 +6,7 @@ #include "base/anim/interpolated.h" #include "base/geom/line.h" +#include "base/math/floating.h" #include "chart/generator/marker.h" #include "chart/main/style.h" #include "chart/options/shapetype.h" diff --git a/src/chart/rendering/markers/connectingmarker.cpp b/src/chart/rendering/markers/connectingmarker.cpp index abc730e45..0d69c41b3 100644 --- a/src/chart/rendering/markers/connectingmarker.cpp +++ b/src/chart/rendering/markers/connectingmarker.cpp @@ -9,6 +9,7 @@ #include "base/math/fuzzybool.h" #include "chart/generator/marker.h" #include "chart/generator/plot.h" +#include "chart/options/channel.h" #include "chart/options/coordsystem.h" #include "chart/options/orientation.h" #include "chart/options/shapetype.h"