Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Axis fixes #573

Merged
merged 6 commits into from
Sep 9, 2024
Merged
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: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
- Axis: line, title, labels, guides, interlacing, ticks
- Legend: title, dimension markers, measure extrema labels
- Marker: line with connections
- Fix negative ranges on x, y, color (measure) and lightness.
- Fix axis step parameter if not match with the range sign (neg/pos).
- Fix axis interpolation. From now the axis and axis labels are following the markers.
- Fix measure axis labels when the range started after the 2000th step value from origo.

### Added

Expand Down
2 changes: 1 addition & 1 deletion src/base/anim/interpolated.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ template <typename Type> class Interpolated
return false;
}

template <class T, class U>
template <class T = double, class U>
[[nodiscard]] T factor(const U &value) const
{
double res{};
Expand Down
5 changes: 0 additions & 5 deletions src/base/math/range.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,6 @@ template <std::floating_point T> struct Range
return is_zero(s) ? 0.5 : (value - min) / s;
}

[[nodiscard]] Range<T> rescale(const Range<T> &range) const
{
return Range<T>(rescale(range.min), rescale(range.max));
}

[[nodiscard]] T scale(const T &value) const
{
return value * size() + min;
Expand Down
72 changes: 69 additions & 3 deletions src/chart/generator/axis.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "axis.h"

#include <algorithm>
#include <cmath>
#include <limits>
#include <map>
#include <optional>
#include <string>
Expand Down Expand Up @@ -42,7 +44,13 @@ MeasureAxis::MeasureAxis(Math::Range<double> interval,
unit(std::string{unit}),
origMeasureName(std::string{measName}),
step(step ? *step : Math::Renard::R5().ceil(range.size() / 5.0))
{}
{
if (Math::Floating::is_zero(range.size()))
this->step->value = 0;
else if (std::signbit(this->step->value)
!= std::signbit(range.size()))
this->step->value *= -1;
}

bool MeasureAxis::operator==(const MeasureAxis &other) const
{
Expand All @@ -68,8 +76,66 @@ MeasureAxis interpolate(const MeasureAxis &op0,
interpolate(op0.origMeasureName, op1.origMeasureName, factor);

if (op0.enabled.get() && op1.enabled.get()) {
res.range = Math::interpolate(op0.range, op1.range, factor);
res.step = interpolate(op0.step, op1.step, factor);
constexpr auto MAX = std::numeric_limits<double>::max() / 2;
using Math::Floating::is_zero;

const auto s0 = op0.range.size();
const auto s1 = op1.range.size();

if (auto s0Zero = is_zero(s0); s0Zero || is_zero(s1)) {
res.range = Math::Range<double>::Raw(
Math::interpolate(op0.range.getMin(),
op1.range.getMin(),
factor),
Math::interpolate(op0.range.getMax(),
op1.range.getMax(),
factor));
res.step = s0Zero ? op1.step : op0.step;
}
else {
auto s0Inv = 1 / s0;
auto s1Inv = 1 / s1;

const auto interp =
Math::interpolate(s0Inv, s1Inv, factor);

const auto s = is_zero(interp) ? MAX : 1 / interp;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of s a more descriptive name would be good


res.range = Math::Range<double>::Raw(
Math::interpolate(op0.range.getMin() * s0Inv,
op1.range.getMin() * s1Inv,
factor)
* s,
Math::interpolate(op0.range.getMax() * s0Inv,
op1.range.getMax() * s1Inv,
factor)
* s);

auto step = Math::interpolate(op0.step.get() * s0Inv,
op1.step.get() * s1Inv,
factor)
* s;

if (auto op0sign = std::signbit(op0.step.get());
op0sign == std::signbit(op1.step.get()))
res.step = interpolate(op0.step,
op1.step,
Math::Range<double>::Raw(op0.step.get(),
op1.step.get())
.rescale(step));
else if (auto max = std::copysign(MAX, step);
op0sign == std::signbit(step))
res.step = interpolate(op0.step,
Anim::Interpolated{max},
Math::Range<double>::Raw(op0.step.get(), max)
.rescale(step));
else
res.step = interpolate(op1.step,
Anim::Interpolated{max},
Math::Range<double>::Raw(op1.step.get(), max)
.rescale(step));
}

res.unit = interpolate(op0.unit, op1.unit, factor);
}
else if (op0.enabled.get()) {
Expand Down
18 changes: 12 additions & 6 deletions src/chart/generator/plotbuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -355,23 +355,26 @@ void PlotBuilder::normalizeXY()
}

plot->getOptions()->setAutoRange(
!std::signbit(boundRect.positive().hSize().getMin()),
!std::signbit(boundRect.positive().vSize().getMin()));
!std::signbit(boundRect.hSize().getMin()),
!std::signbit(boundRect.vSize().getMin()));

boundRect.setHSize(xrange.getRange(boundRect.hSize()));
boundRect.setVSize(yrange.getRange(boundRect.vSize()));

for (auto &marker : plot->markers) {
if (!boundRect.intersects(marker.toRectangle().positive()))
if (!boundRect.positive().intersects(
marker.toRectangle().positive()))
marker.enabled = false;

auto rect = marker.toRectangle();
auto newRect = boundRect.normalize(rect);
marker.fromRectangle(newRect);
}

getMeasTrackRange(ChannelId::x) = boundRect.hSize();
getMeasTrackRange(ChannelId::y) = boundRect.vSize();
getMeasTrackRange(ChannelId::x) =
Math::Range<double>::Raw(boundRect.left(), boundRect.right());
getMeasTrackRange(ChannelId::y) =
Math::Range<double>::Raw(boundRect.bottom(), boundRect.top());
}

void PlotBuilder::calcMeasureAxises(const Data::DataTable &dataTable)
Expand Down Expand Up @@ -478,7 +481,10 @@ void PlotBuilder::addAlignment(const Buckets &subBuckets) const

if (std::signbit(
plot->axises.at(plot->getOptions()->subAxisType())
.measure.range.getMin()))
.measure.range.getMin())
|| std::signbit(
plot->axises.at(plot->getOptions()->subAxisType())
.measure.range.getMax()))
return;

if (plot->getOptions()->align == Base::Align::Type::none) return;
Expand Down
5 changes: 3 additions & 2 deletions src/chart/options/channelrange.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ ChannelExtrema::operator std::string() const
Math::Range<double> ChannelRange::getRange(
const Math::Range<double> &original) const
{
return {getExtrema(min, original.getMin(), original),
getExtrema(max, original.getMax(), original)};
return Math::Range<double>::Raw(
getExtrema(min, original.getMin(), original),
getExtrema(max, original.getMax(), original));
}

double ChannelRange::getExtrema(const OptionalChannelExtrema &extrema,
Expand Down
4 changes: 2 additions & 2 deletions src/chart/rendering/drawaxes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ void DrawAxes::drawTitle(Gen::ChannelId axisIndex) const
? titleStyle.orientation->get_or_first(index)
.value
== Styles::AxisTitle::Orientation::vertical
: titleStyle.orientation->factor<double>(
: titleStyle.orientation->factor(
Styles::AxisTitle::Orientation::vertical));

auto orientedSize =
Expand Down Expand Up @@ -336,7 +336,7 @@ void DrawAxes::drawDimensionLabel(bool horizontal,
labelStyle.position->interpolates()
? labelStyle.side->get_or_first(index).value
== Styles::AxisLabel::Side::negative
: labelStyle.side->factor<double>(
: labelStyle.side->factor(
Styles::AxisLabel::Side::negative);

auto sign = 1 - 2 * under;
Expand Down
3 changes: 1 addition & 2 deletions src/chart/rendering/drawguides.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ void DrawGuides::draw(bool horizontal)
const auto &axis = axises.at(axisId).dimension;

if (axis.enabled && *guideStyle.lineWidth > 0
&& (static_cast<double>(plot->guides.at(axisId).axisGuides)
> 0)) {
&& plot->guides.at(axisId).axisGuides != false) {
canvas.setLineWidth(*guideStyle.lineWidth);

for (auto it = axis.begin(); it != axis.end(); ++it) {
Expand Down
22 changes: 13 additions & 9 deletions src/chart/rendering/drawinterlacing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "base/geom/rect.h"
#include "base/gfx/colortransform.h"
#include "base/gfx/font.h"
#include "base/math/floating.h"
#include "base/math/range.h"
#include "base/math/renard.h"
#include "base/text/smartstring.h"
Expand Down Expand Up @@ -79,7 +80,7 @@ void DrawInterlacing::draw(bool horizontal, bool text) const
}
else {
auto highWeight =
Math::Range(stepLow, stepHigh).rescale(step);
Math::Range<double>::Raw(stepLow, stepHigh).rescale(step);

auto lowWeight = (1.0 - highWeight) * enabled;
highWeight *= enabled;
Expand Down Expand Up @@ -119,9 +120,8 @@ void DrawInterlacing::draw(

const auto origo = plot->axises.origo();

if (static_cast<double>(enabled.interlacings || enabled.axisSticks
|| enabled.labels)
> 0) {
if ((enabled.interlacings || enabled.axisSticks || enabled.labels)
!= false) {
auto interlaceIntensity = Math::FuzzyBool::And<double>(weight,
enabled.interlacings);
auto interlaceColor =
Expand All @@ -133,15 +133,19 @@ void DrawInterlacing::draw(
auto textAlpha =
Math::FuzzyBool::And<double>(weight, enabled.labels);

if (rangeSize <= 0) return;
if (std::signbit(rangeSize) != std::signbit(stepSize)
|| Math::Floating::is_zero(rangeSize))
return;

auto stripWidth = stepSize / rangeSize;

auto axisBottom = axis.origo() + stripWidth;

auto iMin = axisBottom > 0 ? static_cast<int>(
std::floor(-axis.origo() / (2 * stripWidth)))
: 0;
auto iMin =
axisBottom > 0 ? static_cast<int>(
std::floor(-axis.origo() / (2 * stripWidth)))
: static_cast<int>(
(axis.range.getMin() - stepSize) / 2);

if (stripWidth <= 0) return;
auto interlaceCount = 0U;
Expand Down Expand Up @@ -270,7 +274,7 @@ void DrawInterlacing::drawDataLabel(
auto under = labelStyle.position->interpolates()
? labelStyle.side->get_or_first(index).value
== Styles::AxisLabel::Side::negative
: labelStyle.side->factor<double>(
: labelStyle.side->factor(
Styles::AxisLabel::Side::negative);

auto &&posDir =
Expand Down
2 changes: 1 addition & 1 deletion src/chart/rendering/drawlegend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ void DrawLegend::drawMarker(Info &info,
info.canvas.setLineColor(color);
info.canvas.setLineWidth(0);

auto radius = rootStyle.legend.marker.type->factor<double>(
auto radius = rootStyle.legend.marker.type->factor(
Styles::Legend::Marker::Type::circle)
* rect.size.minSize() / 2.0;

Expand Down
9 changes: 4 additions & 5 deletions src/chart/rendering/markerrenderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ void MarkerRenderer::drawLines(Gfx::ICanvas &canvas,
auto center = Geom::Point{blended.center};
center.x = Math::interpolate(center.x,
1.0,
getOptions().coordSystem.factor<double>(
getOptions().coordSystem.factor(
Gen::CoordSystem::polar));
canvas.setLineColor(yLineColor);
auto axisPoint = center.yComp() + origo.xComp();
Expand Down Expand Up @@ -142,9 +142,8 @@ void MarkerRenderer::drawMarkers(Gfx::ICanvas &canvas,
const auto &blended0 =
index == ::Anim::second ? *other : blended;

auto lineFactor =
getOptions().geometry.factor<double>(
Gen::ShapeType::line);
auto lineFactor = getOptions().geometry.factor(
Gen::ShapeType::line);

draw(canvas,
painter,
Expand Down Expand Up @@ -335,7 +334,7 @@ void MarkerRenderer::drawLabel(Gfx::ICanvas &canvas,
return abstractMarker.getLabelPos(position, coordSys);
});

auto centered = labelStyle.position->factor<double>(
auto centered = labelStyle.position->factor(
Styles::MarkerLabel::Position::center);

OrientedLabel{{ctx()}}.draw(canvas,
Expand Down
4 changes: 1 addition & 3 deletions src/chart/rendering/markers/rectanglemarker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,7 @@ RectangleMarker::RectangleMarker(const Gen::Marker &marker,
const Styles::Chart &style) :
SingleDrawMarker(marker, options, Gen::ShapeType::rectangle)
{
linear =
options.coordSystem.factor<double>(Gen::CoordSystem::polar)
== 0;
linear = options.coordSystem.factor(Gen::CoordSystem::polar) == 0;
border = Math::FuzzyBool(true);

auto spacing = Geom::Size{
Expand Down
2 changes: 1 addition & 1 deletion src/chart/rendering/painter/coordinatesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ namespace Vizzu::Draw
PolarDescartesTransform::PolarDescartesTransform(
const Anim::Interpolated<Gen::CoordSystem> &coordSystem) :
zoomOut{true},
polar(coordSystem.factor<double>(Gen::CoordSystem::polar))
polar(coordSystem.factor(Gen::CoordSystem::polar))
{}

Geom::Point PolarDescartesTransform::convert(
Expand Down
Loading