From ab2650a48473cff0175c8efab2444857f9ecbb20 Mon Sep 17 00:00:00 2001 From: PBS Date: Thu, 20 Jul 2023 13:03:34 +0900 Subject: [PATCH] Update 2geom and migrate code Fixes https://gitlab.com/inkscape/inkscape/-/issues/4445 Fixes https://gitlab.com/inkscape/inkscape/-/issues/4341 Also 'fixes' these pseudo non-bugs Fixes https://gitlab.com/inkscape/lib2geom/-/issues/65 Fixes https://gitlab.com/inkscape/inbox/-/issues/8912 --- src/3rdparty/2geom | 2 +- src/display/control/canvas-item.h | 6 --- src/helper/geom.cpp | 61 --------------------- src/helper/geom.h | 1 - src/live_effects/lpe-tiling.cpp | 2 +- src/trace/potrace/inkscape-potrace.cpp | 4 +- src/trace/potrace/inkscape-potrace.h | 14 +---- src/ui/widget/canvas.cpp | 1 - src/ui/widget/canvas/stores.cpp | 9 ++-- testfiles/CMakeLists.txt | 1 - testfiles/src/min-bbox-test.cpp | 73 -------------------------- 11 files changed, 10 insertions(+), 164 deletions(-) delete mode 100644 testfiles/src/min-bbox-test.cpp diff --git a/src/display/control/canvas-item.h b/src/display/control/canvas-item.h index 3a5387d9e91..205234ff787 100644 --- a/src/display/control/canvas-item.h +++ b/src/display/control/canvas-item.h @@ -148,12 +148,6 @@ protected: } // namespace Inkscape -// Todo: Move to lib2geom. -inline auto &operator<<(std::ostream &s, Geom::OptRect const &rect) -{ - return rect ? (s << *rect) : (s << "(empty)"); -} - #endif // SEEN_CANVAS_ITEM_H /* diff --git a/src/helper/geom.cpp b/src/helper/geom.cpp index 30111cb8d9d..6a282a18433 100644 --- a/src/helper/geom.cpp +++ b/src/helper/geom.cpp @@ -1010,67 +1010,6 @@ bool approx_dihedral(Geom::Affine const &affine, double eps) return arr == std::array {1, 0, 0, 1 } || arr == std::array{ 0, 1, 1, 0 }; } -/** - * Computes the rotation which puts a set of points in a position where they can be wrapped in the - * smallest possible axis-aligned rectangle, and returns it along with the rectangle. - */ -std::pair min_bounding_box(std::vector const &pts) -{ - // Compute the convex hull. - auto const hull = Geom::ConvexHull(pts); - - // Move the point i along until it maximises distance in the direction n. - auto advance = [&] (int &i, Geom::Point const &n) { - auto ih = Geom::dot(hull[i], n); - while (true) { - int j = (i + 1) % hull.size(); - auto jh = Geom::dot(hull[j], n); - if (ih >= jh) break; - i = j; - ih = jh; - } - }; - - double mina = std::numeric_limits::max(); - std::pair result; - - // Run rotating callipers. - int j, k, l; - for (int i = 0; i < hull.size(); i++) { - // Get the current segment. - auto &p1 = hull[i]; - auto &p2 = hull[(i + 1) % hull.size()]; - auto v = (p2 - p1).normalized(); - auto n = Geom::Point(-v.y(), v.x()); - - if (i == 0) { - // Initialise the points. - j = 0; advance(j, v); - k = j; advance(k, n); - l = k; advance(l, -v); - } else { - // Advance the points. - advance(j, v); - advance(k, n); - advance(l, -v); - } - - // Compute the dimensions of the unconstrained rectangle. - auto w = Geom::dot(hull[j] - hull[l], v); - auto h = Geom::dot(hull[k] - hull[i], n); - auto a = w * h; - - // Track the minimum. - if (a < mina) { - mina = a; - result = std::make_pair(Geom::Affine(v.x(), -v.y(), v.y(), v.x(), 0.0, 0.0), - Geom::Rect::from_xywh(Geom::dot(hull[l], v), Geom::dot(hull[i], n), w, h)); - } - } - - return result; -} - /* Local Variables: mode:c++ diff --git a/src/helper/geom.h b/src/helper/geom.h index 50e434da780..59542e7d44f 100644 --- a/src/helper/geom.h +++ b/src/helper/geom.h @@ -45,7 +45,6 @@ void recursive_bezier4(const double x1, const double y1, const double x2, const std::vector &pointlist, int level); bool approx_dihedral(Geom::Affine const &affine, double eps = 0.0001); -std::pair min_bounding_box(std::vector const &pts); /// Returns signed area of triangle given by points; may be negative. inline Geom::Coord triangle_area(Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) diff --git a/src/live_effects/lpe-tiling.cpp b/src/live_effects/lpe-tiling.cpp index b4913c79b2d..5bd88801475 100644 --- a/src/live_effects/lpe-tiling.cpp +++ b/src/live_effects/lpe-tiling.cpp @@ -442,7 +442,7 @@ LPETiling::doAfterEffect (SPLPEItem const* lpeitem, SPCurve *curve) auto p = Geom::Point(xset + offset_x - random_x[counter], yset + offset_y - random_y[counter]); auto translate = p * gap.inverse(); Geom::Affine finalit = (transformoriginal * Geom::Translate(spcenter_base).inverse() * mirror * Geom::Translate(spcenter_base)); - finalit *= gapp.inverse() * Geom::Translate(spcenter).inverse() * originatrans.withoutTranslation().inverse() * r * translate * Geom::Translate(spcenter) ; + finalit *= gapp.inverse() * Geom::Translate(spcenter).inverse() * originatrans.withoutTranslation().inverse() * r * Geom::Translate(translate) * Geom::Translate(spcenter); item->doWriteTransform(finalit); item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); forcewrite = forcewrite || write; diff --git a/src/trace/potrace/inkscape-potrace.cpp b/src/trace/potrace/inkscape-potrace.cpp index a6c7f65f92a..e51a5afb104 100644 --- a/src/trace/potrace/inkscape-potrace.cpp +++ b/src/trace/potrace/inkscape-potrace.cpp @@ -93,7 +93,7 @@ void PotraceTracingEngine::setTurdSize(int turdsize) * Recursively descend the potrace_path_t node tree \a paths, writing paths to \a builder. * The \a points set is used to prevent redundant paths. */ -void PotraceTracingEngine::writePaths(potrace_path_t *paths, Geom::PathBuilder &builder, std::unordered_set &points, Async::Progress &progress) const +void PotraceTracingEngine::writePaths(potrace_path_t *paths, Geom::PathBuilder &builder, std::unordered_set &points, Async::Progress &progress) const { auto to_geom = [] (potrace_dpoint_t const &c) { return Geom::Point(c.x, c.y); @@ -280,7 +280,7 @@ Geom::PathVector PotraceTracingEngine::grayMapToPath(GrayMap const &grayMap, Asy // Extract the paths into a pathvector and return it. Geom::PathBuilder builder; - std::unordered_set points; + std::unordered_set points; writePaths(potraceState->plist, builder, points, progress); return builder.peek(); } diff --git a/src/trace/potrace/inkscape-potrace.h b/src/trace/potrace/inkscape-potrace.h index 0e4a9c62eeb..f30568369b2 100644 --- a/src/trace/potrace/inkscape-potrace.h +++ b/src/trace/potrace/inkscape-potrace.h @@ -45,18 +45,6 @@ enum class TraceType AUTOTRACE_CENTERLINE }; -// Todo: Make lib2geom types hashable. -struct geom_point_hash -{ - std::size_t operator()(Geom::Point const &pt) const - { - std::size_t hash = 0; - boost::hash_combine(hash, pt.x()); - boost::hash_combine(hash, pt.y()); - return hash; - } -}; - class PotraceTracingEngine final : public TracingEngine { @@ -119,7 +107,7 @@ private: Geom::PathVector grayMapToPath(GrayMap const &gm, Async::Progress &progress); - void writePaths(potrace_path_t *paths, Geom::PathBuilder &builder, std::unordered_set &points, Async::Progress &progress) const; + void writePaths(potrace_path_t *paths, Geom::PathBuilder &builder, std::unordered_set &points, Async::Progress &progress) const; }; } // namespace Potrace diff --git a/src/ui/widget/canvas.cpp b/src/ui/widget/canvas.cpp index 7274d0a30f5..86fb95a54c7 100644 --- a/src/ui/widget/canvas.cpp +++ b/src/ui/widget/canvas.cpp @@ -18,7 +18,6 @@ #include #include #include -#include <2geom/convex-hull.h> #include "canvas.h" diff --git a/src/ui/widget/canvas/stores.cpp b/src/ui/widget/canvas/stores.cpp index 70327f5a48b..e51598de456 100644 --- a/src/ui/widget/canvas/stores.cpp +++ b/src/ui/widget/canvas/stores.cpp @@ -4,6 +4,7 @@ #include <2geom/transforms.h> #include <2geom/parallelogram.h> #include <2geom/point.h> +#include <2geom/convex-hull.h> #include "helper/geom.h" #include "ui/util.h" #include "stores.h" @@ -61,8 +62,7 @@ auto region_affine_approxinwards(Cairo::RefPtr const ®, Geom:: double fx = min(absolute(Geom::Point(1.0, 0.0) * affine.withoutTranslation())); double fy = min(absolute(Geom::Point(0.0, 1.0) * affine.withoutTranslation())); - for (int i = 0; i < regsrc->get_num_rectangles(); i++) - { + for (int i = 0; i < regsrc->get_num_rectangles(); i++) { auto rect = cairo_to_geom(regsrc->get_rectangle(i)); int nx = std::ceil(rect.width() * fx / d); int ny = std::ceil(rect.height() * fy / d); @@ -147,8 +147,9 @@ void Stores::snapshot_combine(Fragment const &view) add_rect(Geom::Parallelogram(_snapshot.rect) * _snapshot.affine.inverse() * view.affine); // Compute their minimum-area bounding box as a fragment - an (affine, rect) pair. - auto [affine, rect] = min_bounding_box(pts); - affine = view.affine * affine; + auto const [rot, optrect] = Geom::ConvexHull(pts).minAreaRotation(); + auto rect = *optrect; // non-empty since pts is non-empty + auto affine = view.affine * rot; // Check if the paste transform takes the snapshot store exactly onto the new fragment, possibly with a dihedral transformation. auto paste = Geom::Scale(_snapshot.rect.dimensions()) diff --git a/testfiles/CMakeLists.txt b/testfiles/CMakeLists.txt index dc0cbd6ac45..15f68eb439d 100644 --- a/testfiles/CMakeLists.txt +++ b/testfiles/CMakeLists.txt @@ -69,7 +69,6 @@ set(TEST_SOURCES attributes-test color-profile-test dir-util-test - min-bbox-test oklab-color-test sp-object-test sp-object-tags-test diff --git a/testfiles/src/min-bbox-test.cpp b/testfiles/src/min-bbox-test.cpp deleted file mode 100644 index ccacd625a83..00000000000 --- a/testfiles/src/min-bbox-test.cpp +++ /dev/null @@ -1,73 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -#include <2geom/convex-hull.h> -#include <2geom/transforms.h> -#include -#include - -// Get the axis-aligned bouding box of a set of points, transforming by affine first. -auto aligned_bbox(std::vector const &pts, Geom::Affine const &affine = Geom::identity()) -{ - Geom::OptRect rect; - for (auto &pt : pts) { - rect.expandTo(pt * affine); - } - return rect; -} - -double area(Geom::OptRect const &rect) -{ - return rect ? rect->area() : 0.0; -} - -// Get an approximation to the minimum bouding box area. -double approx_min(std::vector const &pts) -{ - int constexpr N = 100; - - double min = std::numeric_limits::max(); - - for (int i = 0; i < N; i++) { - auto t = (double)i / N * M_PI * 0.5; - min = std::min(min, area(aligned_bbox(pts, Geom::Rotate(t)))); - } - - return min; -} - -// Get a crude random double. -double ranf() -{ - int constexpr N = 1000; - return (double)(rand() % N) / N; -} - -// Get a random collection of points. -auto randpts() -{ - std::vector pts; - - int count = 5 + (rand() % 10); - for (int i = 0; i < count; i++) { - pts.emplace_back(ranf(), ranf()); - } - - return pts; -} - -TEST(MinBBoxTest, random) -{ - for (int i = 0; i < 100; i++) { - auto const pts = randpts(); - auto [affine, rect] = min_bounding_box(pts); - - ASSERT_TRUE(affine.isRotation()); - - auto rect2 = aligned_bbox(pts, affine); - for (int i = 0; i < 2; i++) { - ASSERT_NEAR(rect.min()[i], rect2->min()[i], 1e-5); - ASSERT_NEAR(rect.max()[i], rect2->max()[i], 1e-5); - } - - ASSERT_LE(rect.area(), approx_min(pts)); - } -} -- GitLab