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

Fix tooltip on area charts with data series started with zero #561

Merged
merged 11 commits into from
Aug 12, 2024
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## [Unreleased]

### Fixed

- Area charts with data series started with zero: tooltip fixed.

## [0.12.0] - 2024-07-29

### Fixed
Expand Down
37 changes: 9 additions & 28 deletions src/base/geom/circle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,6 @@
namespace Geom
{

Circle::Circle(const Rect &rect, FromRect fromRect)
{
radius = fromRect == FromRect::inscribed
? rect.size.minSize() / 2.0
: fromRect == FromRect::sameWidth ? rect.size.x / 2.0
: fromRect == FromRect::sameHeight ? rect.size.y / 2.0
: fromRect == FromRect::outscribed
? rect.size.diagonal() / 2.0
: throw std::logic_error("invalid circle parameter");
center = rect.pos + rect.size / 2.0;
}

Circle::Circle(const Circle &c0,
const Circle &c1,
double radius,
Expand All @@ -40,27 +28,13 @@ bool Circle::concentric(const Circle &c) const
return center == c.center;
}

bool Circle::colateral(const Circle &c, double tolerance) const
{
return Math::AddTolerance(centerDistance(c), tolerance)
== (radius + c.radius);
}

double Circle::area() const { return M_PI * radius * radius; }

bool Circle::overlaps(const Circle &c, double tolerance) const
bool Circle::overlaps(const Circle &c) const
{
auto d = c.center - center;
auto sumRadius = radius + c.radius;
return Math::AddTolerance(d.sqrAbs(), tolerance)
< sumRadius * sumRadius;
}

double Circle::overlapFactor(const Circle &c) const
{
auto d = centerDistance(c);
auto r = radius + c.radius;
return d == 0 ? 0 : r / d;
return Math::AddTolerance(d.sqrAbs()) < sumRadius * sumRadius;
}

Rect Circle::boundary() const
Expand All @@ -74,6 +48,13 @@ bool Circle::contains(const Point &point) const
return (point - center).sqrAbs() <= radius * radius;
}

double Circle::distance(const Point &point) const
{
return std::max(0.0,
(point - center).abs() - radius,
Math::Floating::less);
}

double Circle::centerDistance(const Circle &c) const
{
return (center - c.center).abs();
Expand Down
16 changes: 2 additions & 14 deletions src/base/geom/circle.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,6 @@ namespace Geom
class Circle
{
public:
enum class FromRect {
inscribed,
sameWidth,
sameHeight,
outscribed
};

Point center;
double radius;

Expand All @@ -30,8 +23,6 @@ class Circle
radius(radius)
{}

Circle(const Rect &rect, FromRect fromRect);

Circle(const Circle &c0,
const Circle &c1,
double radius,
Expand All @@ -48,13 +39,10 @@ class Circle
}

[[nodiscard]] double area() const;
[[nodiscard]] bool overlaps(const Circle &c,
double tolerance) const;
[[nodiscard]] double overlapFactor(const Circle &c) const;
[[nodiscard]] bool colateral(const Circle &c,
double tolerance) const;
[[nodiscard]] bool overlaps(const Circle &c) const;
[[nodiscard]] Rect boundary() const;
[[nodiscard]] bool contains(const Point &point) const;
[[nodiscard]] double distance(const Point &point) const;
[[nodiscard]] double distance(const Circle &c) const;
[[nodiscard]] Solutions<Point, 2> intersection(
const Circle &c) const;
Expand Down
2 changes: 2 additions & 0 deletions src/base/geom/line.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ struct Line

[[nodiscard]] double distance(const Point &point) const
{
if (isPoint()) return (point - begin).abs();

auto projection = ((point - begin).dot(getDirection()))
/ (length() * length());

Expand Down
77 changes: 62 additions & 15 deletions src/base/geom/point.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,56 +18,56 @@ struct Point
double x{0.0};
double y{0.0};

static Point Invalid() { return {NAN, NAN}; }
[[nodiscard]] static Point Invalid() { return {NAN, NAN}; }

static Point Max()
[[nodiscard]] static Point Max()
{
return {std::numeric_limits<double>::max(),
std::numeric_limits<double>::max()};
}

static Point Min()
[[nodiscard]] static Point Min()
{
return {std::numeric_limits<double>::lowest(),
std::numeric_limits<double>::lowest()};
}

static Point Ident(bool horizontal)
[[nodiscard]] static Point Ident(bool horizontal)
{
return {horizontal ? 1.0 : 0.0, horizontal ? 0.0 : 1.0};
}

static Point Polar(double radius, double angle)
[[nodiscard]] static Point Polar(double radius, double angle)
{
return {radius * cos(angle), radius * sin(angle)};
}

static Point X(double x) { return {x, 0}; }
[[nodiscard]] static Point X(double x) { return {x, 0}; }

static Point Y(double y) { return {0, y}; }
[[nodiscard]] static Point Y(double y) { return {0, y}; }

Point operator*(double factor) const
[[nodiscard]] Point operator*(double factor) const
{
return {x * factor, y * factor};
}

Point operator/(double divisor) const
[[nodiscard]] Point operator/(double divisor) const
{
if (Math::Floating::is_zero(divisor)) return Invalid();
return {x / divisor, y / divisor};
}

Point operator+(const Point &other) const
[[nodiscard]] Point operator+(const Point &other) const
{
return {x + other.x, y + other.y};
}

Point operator-(const Point &other) const
[[nodiscard]] Point operator-(const Point &other) const
{
return {x - other.x, y - other.y};
}

Point operator*(const Point &other) const
[[nodiscard]] Point operator*(const Point &other) const
{
return {x * other.x, y * other.y};
}
Expand All @@ -77,18 +77,65 @@ struct Point
return x * other.x + y * other.y;
}

Point operator/(const Point &other) const
[[nodiscard]] Point operator/(const Point &other) const
{
using Math::Floating::is_zero;
if (is_zero(other.x) || is_zero(other.y)) return Invalid();
return {x / other.x, y / other.y};
}

double operator^(const Point &p) const
[[nodiscard]] double operator^(const Point &p) const
{
return x * p.y - y * p.x;
}

Point &operator+=(const Point &other)
{
x += other.x;
y += other.y;
return *this;
}

Point &operator-=(const Point &other)
{
x -= other.x;
y -= other.y;
return *this;
}

Point &operator*=(double factor)
{
x *= factor;
y *= factor;
return *this;
}

Point &operator/=(double divisor)
{
if (Math::Floating::is_zero(divisor))
return *this = Invalid();
x /= divisor;
y /= divisor;
return *this;
}

Point &operator*=(const Point &other)
{
x *= other.x;
y *= other.y;
return *this;
}

Point &operator/=(const Point &other)
{
using Math::Floating::is_zero;
if (is_zero(other.x) || is_zero(other.y))
return *this = Invalid();
x /= other.x;
y /= other.y;
return *this;
}

[[nodiscard]] Point flip() const { return {y, x}; }

[[nodiscard]] Point flipX() const { return {-x, y}; }
Expand Down Expand Up @@ -214,7 +261,7 @@ struct Size : Point
std::min(s1.y, s2.y, less)};
}

[[nodiscard]] bool isSquare(double toleranceFactor = 0.0) const
[[nodiscard]] bool isSquare(double toleranceFactor) const
{
using Math::Floating::is_zero;
if (is_zero(y)) return false;
Expand Down
41 changes: 6 additions & 35 deletions src/base/geom/quadrilateral.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,33 +7,12 @@
namespace Geom
{

ConvexQuad::ConvexQuad(const Rect &rect)
{
points[0] = rect.pos;
points[1] = rect.pos + Point{rect.size.x, 0.0};
points[2] = rect.pos + rect.size;
points[3] = rect.pos + Point{0.0, rect.size.y};
}

Rect ConvexQuad::boundary() const { return Rect::Boundary(points); }

ConvexQuad ConvexQuad::Square(Point p0, Point p2)
{
auto center = (p0 + p2) / 2;
auto halfDiagonal = (p2 - p0) / 2;
auto p1 = center + halfDiagonal.normal(false);
auto p3 = center + halfDiagonal.normal(true);
return ConvexQuad({p0, p1, p2, p3});
}

ConvexQuad ConvexQuad::Isosceles(Point base0Middle,
Point base1Middle,
double base0Length,
double base1Length)
{
auto dir = base1Middle == base0Middle
? Point{0, 1}
: (base1Middle - base0Middle).normalized();
auto dir = (base1Middle - base0Middle).normalized();

return ConvexQuad(
{base0Middle + dir.normal(false) * (base0Length / 2),
Expand All @@ -42,20 +21,12 @@ ConvexQuad ConvexQuad::Isosceles(Point base0Middle,
base1Middle + dir.normal(false) * (base1Length / 2)});
}

bool ConvexQuad::contains(const Point &p, double tolerance) const
{
auto boundaryArea = Triangle{{points[0], points[1], p}}.area()
+ Triangle{{points[1], points[2], p}}.area()
+ Triangle{{points[2], points[3], p}}.area()
+ Triangle{{points[3], points[0], p}}.area();

return Math::AddTolerance(boundaryArea, tolerance) <= area();
}

double ConvexQuad::area() const
double ConvexQuad::distance(const Point &point) const
{
return Triangle{{points[0], points[1], points[2]}}.area()
+ Triangle{{points[2], points[3], points[0]}}.area();
return std::min(
Triangle{{points[0], points[1], points[2]}}.distance(point),
Triangle{{points[2], points[3], points[0]}}.distance(point),
Math::Floating::less);
}

}
8 changes: 2 additions & 6 deletions src/base/geom/quadrilateral.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,12 @@ class ConvexQuad

ConvexQuad() = default;
explicit ConvexQuad(const Points &points) : points(points) {}
explicit ConvexQuad(const Rect &rect);
[[nodiscard]] static ConvexQuad Square(Point p0, Point p2);
[[nodiscard]] static ConvexQuad Isosceles(Point base0Middle,
Point base1Middle,
double base0Length,
double base1Length);
[[nodiscard]] bool contains(const Point &p,
double tolerance = 0.0) const;
[[nodiscard]] double area() const;
[[nodiscard]] Rect boundary() const;

[[nodiscard]] double distance(const Point &point) const;
};

}
Expand Down
16 changes: 0 additions & 16 deletions src/base/geom/rect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,6 @@ namespace Geom

Rect Rect::Ident() { return {Geom::Point(), Geom::Size::Identity()}; }

Rect Rect::CenteredMax()
{
return {Geom::Point::Min() / 2, {Geom::Size::Max()}};
}

Rect Rect::boundary(const Rect &rect) const
{
using Math::Floating::less;
Expand All @@ -24,17 +19,6 @@ Rect Rect::boundary(const Rect &rect) const
return res;
}

Rect Rect::boundary(const Point &p) const
{
using Math::Floating::less;
Rect res = positive();
res.setLeft(std::min(res.left(), p.x, less));
res.setBottom(std::min(res.bottom(), p.y, less));
res.setRight(std::max(res.right(), p.x, less));
res.setTop(std::max(res.top(), p.y, less));
return res;
}

Point Rect::normalize(const Point &p) const
{
using Math::Floating::is_zero;
Expand Down
Loading