summaryrefslogtreecommitdiffstats
path: root/include/basegfx/polygon/b2dpolygon.hxx
diff options
context:
space:
mode:
Diffstat (limited to 'include/basegfx/polygon/b2dpolygon.hxx')
-rw-r--r--include/basegfx/polygon/b2dpolygon.hxx281
1 files changed, 281 insertions, 0 deletions
diff --git a/include/basegfx/polygon/b2dpolygon.hxx b/include/basegfx/polygon/b2dpolygon.hxx
new file mode 100644
index 0000000000..c63bda845d
--- /dev/null
+++ b/include/basegfx/polygon/b2dpolygon.hxx
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <ostream>
+#include <vector>
+
+#include <sal/types.h>
+#include <o3tl/cow_wrapper.hxx>
+#include <basegfx/vector/b2enums.hxx>
+#include <basegfx/basegfxdllapi.h>
+
+class ImplB2DPolygon;
+
+namespace basegfx
+{
+ class B2DPoint;
+ class B2DRange;
+ class B2DHomMatrix;
+ class B2DCubicBezier;
+ class B2DVector;
+ class SystemDependentData;
+ class SystemDependentDataManager;
+ typedef std::shared_ptr<SystemDependentData> SystemDependentData_SharedPtr;
+}
+
+namespace basegfx
+{
+ class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2DPolygon
+ {
+ public:
+ typedef o3tl::cow_wrapper< ImplB2DPolygon > ImplType;
+
+ private:
+ // internal data.
+ ImplType mpPolygon;
+
+ public:
+ /// diverse constructors
+ B2DPolygon();
+ B2DPolygon(const B2DPolygon& rPolygon);
+ B2DPolygon(B2DPolygon&& rPolygon);
+ B2DPolygon(const B2DPolygon& rPolygon, sal_uInt32 nIndex, sal_uInt32 nCount);
+ B2DPolygon(std::initializer_list<basegfx::B2DPoint> rPoints);
+
+ ~B2DPolygon();
+
+ /// assignment operator
+ B2DPolygon& operator=(const B2DPolygon& rPolygon);
+ B2DPolygon& operator=(B2DPolygon&& rPolygon);
+
+ /// unshare this polygon with all internally shared instances
+ void makeUnique();
+
+ /// compare operators
+ bool operator==(const B2DPolygon& rPolygon) const;
+
+ /// member count
+ sal_uInt32 count() const;
+
+ /// Coordinate interface
+ basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const;
+ void setB2DPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue);
+
+ /// Coordinate insert/append
+ void insert(sal_uInt32 nIndex, const basegfx::B2DPoint& rPoint, sal_uInt32 nCount = 1);
+ void append(const basegfx::B2DPoint& rPoint, sal_uInt32 nCount);
+ void append(const basegfx::B2DPoint& rPoint);
+ void reserve(sal_uInt32 nCount);
+
+ /// Basic ControlPoint interface
+ basegfx::B2DPoint getPrevControlPoint(sal_uInt32 nIndex) const;
+ basegfx::B2DPoint getNextControlPoint(sal_uInt32 nIndex) const;
+ void setPrevControlPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue);
+ void setNextControlPoint(sal_uInt32 nIndex, const basegfx::B2DPoint& rValue);
+ void setControlPoints(sal_uInt32 nIndex, const basegfx::B2DPoint& rPrev, const basegfx::B2DPoint& rNext);
+
+ /// ControlPoint resets
+ void resetPrevControlPoint(sal_uInt32 nIndex);
+ void resetNextControlPoint(sal_uInt32 nIndex);
+ void resetControlPoints();
+
+ /// Bezier segment append with control points. The current last polygon point is implicitly taken as start point.
+ void appendBezierSegment(const basegfx::B2DPoint& rNextControlPoint,
+ const basegfx::B2DPoint& rPrevControlPoint,
+ const basegfx::B2DPoint& rPoint);
+
+ /// This is a shortcut to append a quadratic bezier segment. The current last polygon point is implicitly taken as start point.
+ /// Note that the quadratic bezier control points will be converted to cubic bezier with 2 control points.
+ void appendQuadraticBezierSegment(const basegfx::B2DPoint& rQuadControlPoint,
+ const basegfx::B2DPoint& rPoint);
+
+ /// ControlPoint checks
+ bool areControlPointsUsed() const;
+ bool isPrevControlPointUsed(sal_uInt32 nIndex) const;
+ bool isNextControlPointUsed(sal_uInt32 nIndex) const;
+ B2VectorContinuity getContinuityInPoint(sal_uInt32 nIndex) const;
+
+ /** bezier segment access
+
+ This method also works when it is no bezier segment at all and will fill
+ the given B2DCubicBezier as needed.
+ In any case, the given B2DCubicBezier will be filled, if necessary with
+ the single start point (if no valid edge exists).
+
+ @param nIndex
+ Index of the addressed edge's start point
+
+ @param rTarget
+ The B2DCubicBezier to be filled. It's data WILL be changed.
+ */
+ void getBezierSegment(sal_uInt32 nIndex, B2DCubicBezier& rTarget) const;
+
+ /** Default adaptive subdivision access
+
+ This method will return a default adaptive subdivision of the polygon.
+ If the polygon does not contain any bezier curve segments, it will
+ just return itself.
+
+ The subdivision is created on first request and buffered, so when using
+ this subdivision You have the guarantee for fast accesses for multiple
+ usages. It is intended for tooling usage for tasks which would be hard
+ to accomplish on bezier segments (e.g. isInEpsilonRange).
+
+ The current default subdivision uses adaptiveSubdivideByCount with 9
+ subdivisions which gives 10 edges and 11 points per segment and is
+ usually pretty usable for processing purposes. There is no parameter
+ passing here ATM but it may be changed on demand. If needed, a TYPE
+ and PARAMETER (both defaulted) may be added to allow for switching
+ between the different kinds of subdivisioned and passing them one
+ parameter.
+
+ The lifetime of the buffered subdivision is based on polygon changes.
+ When changing the polygon, it will be flushed. It is buffered at the
+ refcounted implementation class, so it will survive copy by value and
+ combinations in PolyPolygons.
+
+ @return
+ The default (and buffered) subdivision of this polygon. It may
+ be this polygon itself when it has no bezier segments. It is guaranteed
+ to have no more bezier segments
+ */
+ B2DPolygon const & getDefaultAdaptiveSubdivision() const;
+
+ /** Get the B2DRange (Rectangle dimensions) of this B2DPolygon
+
+ A polygon may have up to three ranges:
+
+ (a) the range of the polygon points
+ (b) the range of the polygon points and control points
+ (c) the outer range of the subdivided bezier curve
+
+ Ranges (a) and (c) are produced by tools::getRange(); resp. this
+ getB2DRange(). tools::getRangeWithControlPoints handles case (b).
+
+ To get range (c) a simple solution would be to subdivide the polygon
+ and use getRange() on it. Since subdivision is expensive and decreases
+ the polygon quality, i added this new method. It will use a
+ methodology suggested by HDU. First, it gets the range (a).
+ Then it iterates over the bezier segments and for each it
+ first tests if the outer range of the bezier segment is already
+ contained in the result range.
+
+ The subdivision itself uses getAllExtremumPositions() to only
+ calculate extremum points and to expand the result accordingly.
+ Thus it calculates maximal four extremum points on the bezier
+ segment, no split is used at all.
+
+ @return
+ The outer range of the bezier curve/polygon
+ */
+ B2DRange const & getB2DRange() const;
+
+ /** append other 2D polygons
+
+ The default (nIndex ==0 && nCount == 0) will append
+ the whole rPoly
+
+ @param rPoly
+ The source polygon
+
+ @param nIndex
+ The index to the first point of rPoly to append
+
+ @param nCount
+ The number of points to append from rPoly, starting
+ from nIndex. If zero, as much as possible is appended
+ */
+ void append(const B2DPolygon& rPoly, sal_uInt32 nIndex = 0, sal_uInt32 nCount = 0);
+
+ /// remove points
+ void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1);
+
+ /// clear all points
+ void clear();
+
+ /// closed state interface
+ bool isClosed() const;
+ void setClosed(bool bNew);
+
+ /// flip polygon direction
+ void flip();
+
+ /// test if Polygon has double points
+ bool hasDoublePoints() const;
+
+ /// remove double points, at the begin/end and follow-ups, too
+ void removeDoublePoints();
+
+ /// apply transformation given in matrix form
+ void transform(const basegfx::B2DHomMatrix& rMatrix);
+
+ // exclusive management op's for SystemDependentData at B2DPolygon
+ template<class T>
+ std::shared_ptr<T> getSystemDependentData() const
+ {
+ return std::static_pointer_cast<T>(getSystemDependantDataInternal(typeid(T).hash_code()));
+ }
+
+ template<class T, class... Args>
+ std::shared_ptr<T> addOrReplaceSystemDependentData(Args&&... args) const
+ {
+ std::shared_ptr<T> r = std::make_shared<T>(std::forward<Args>(args)...);
+
+ // tdf#129845 only add to buffer if a relevant buffer time is estimated
+ if(r->calculateCombinedHoldCyclesInSeconds() > 0)
+ {
+ basegfx::SystemDependentData_SharedPtr r2(r);
+ addOrReplaceSystemDependentDataInternal(r2);
+ }
+
+ return r;
+ }
+
+ private:
+ void addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const;
+ SystemDependentData_SharedPtr getSystemDependantDataInternal(size_t hash_code) const;
+ const basegfx::B2DVector& getPrevControlVector(sal_uInt32 nIndex) const;
+ const basegfx::B2DVector& getNextControlVector(sal_uInt32 nIndex) const;
+ };
+
+ // typedef for a vector of B2DPolygons
+ typedef ::std::vector< B2DPolygon > B2DPolygonVector;
+
+ template< typename charT, typename traits >
+ inline std::basic_ostream<charT, traits> & operator <<(
+ std::basic_ostream<charT, traits> & stream, const B2DPolygon& poly )
+ {
+ stream << "<" << poly.count() << ":";
+ for (sal_uInt32 i = 0; i < poly.count(); i++)
+ {
+ if (i > 0)
+ stream << "--";
+ stream << poly.getB2DPoint(i);
+ }
+ stream << ">";
+
+ return stream;
+ }
+
+} // end of namespace basegfx
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */