diff options
Diffstat (limited to 'include/basegfx/polygon')
-rw-r--r-- | include/basegfx/polygon/WaveLine.hxx | 38 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dlinegeometry.hxx | 145 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolygon.hxx | 281 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolygonclipper.hxx | 65 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolygoncutandtouch.hxx | 47 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolygontools.hxx | 548 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolygontriangulator.hxx | 71 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolypolygon.hxx | 171 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolypolygoncutter.hxx | 144 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dpolypolygontools.hxx | 297 | ||||
-rw-r--r-- | include/basegfx/polygon/b2dtrapezoid.hxx | 108 | ||||
-rw-r--r-- | include/basegfx/polygon/b3dpolygon.hxx | 120 | ||||
-rw-r--r-- | include/basegfx/polygon/b3dpolygontools.hxx | 129 | ||||
-rw-r--r-- | include/basegfx/polygon/b3dpolypolygon.hxx | 113 | ||||
-rw-r--r-- | include/basegfx/polygon/b3dpolypolygontools.hxx | 132 |
15 files changed, 2409 insertions, 0 deletions
diff --git a/include/basegfx/polygon/WaveLine.hxx b/include/basegfx/polygon/WaveLine.hxx new file mode 100644 index 0000000000..b839c75198 --- /dev/null +++ b/include/basegfx/polygon/WaveLine.hxx @@ -0,0 +1,38 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <basegfx/basegfxdllapi.h> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/range/b2drectangle.hxx> + +namespace basegfx +{ +// Creates a polygon of a wave line in the input rectangle. +// +// The polygon is created with points at the center of the rectangle, +// and the quadratic control points at the upper and lower side. See +// the diagram below. +// +// *----Q---------------Q------------* +// | | +// |P-------P-------P-------P-------P| +// | | +// *------------Q---------------Q----* +// +// P is the point +// Q is the quadratic bezier control point +// +BASEGFX_DLLPUBLIC B2DPolygon createWaveLinePolygon(basegfx::B2DRectangle const& rRectangle); + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dlinegeometry.hxx b/include/basegfx/polygon/b2dlinegeometry.hxx new file mode 100644 index 0000000000..ab9e54652c --- /dev/null +++ b/include/basegfx/polygon/b2dlinegeometry.hxx @@ -0,0 +1,145 @@ +/* -*- 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 <basegfx/numeric/ftools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <com/sun/star/drawing/LineCap.hpp> +#include <basegfx/basegfxdllapi.h> + +namespace basegfx::utils +{ + /** Create line start/end geometry element, mostly arrows and things like that. + + @param rCandidate + The polygon which needs to get that line ends and needs to have two points + at least. + + @param rArrow + The line start/end geometry. It is assumed that the tip is pointing + upwards. Result will be rotated and scaled to fit. + + @param bStart + describes if creation is for start or end of candidate. + + @param fWidth + defines the size of the element, it's describing the target width in X + of the arrow. + + @param fDockingPosition needs to be in [0.0 ..1.0] range, where 0.0 means + that the tip of the arrow will be aligned with the polygon start, 1.0 means + the bottom. The default of 0.5 describes a centered arrow. + + @param pConsumedLength + Using this parameter it is possible to get back how much from the candidate + geometry is overlapped by the created element (consumed). + + @param fCandidateLength + This should contain the length of rCandidate to allow work without + again calculating the length (which may be expensive with beziers). If 0.0 is + given, the length is calculated on demand. + + @param fShift + When it is necessary to count with the thickness of the line, it + makes sense to move the start position slightly - so define the shift. + + @return + The Line start and end polygon, correctly rotated and scaled + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon createAreaGeometryForLineStartEnd( + const B2DPolygon& rCandidate, + const B2DPolyPolygon& rArrow, + bool bStart, + double fWidth, + double fCandidateLength, // 0.0 -> calculate self + double fDockingPosition, // 0->top, 1->bottom + double* pConsumedLength = nullptr, + double fShift = 0.0); + + /** create filled polygon geometry for lines with a line width + + This method will create bezier based, fillable polygons which + will resample the curve if it was extended for the given half + line width. It will remove extrema positions from contained + bezier segments and get as close as possible and defined by + the given parameters to the ideal result. + + It will check edges for trivial bezier to avoid unnecessary + bezier polygons. Care is taken to produce the in-between + polygon points (the ones original on the source polygon) since + it has showed that without those, the raster converters leave + non-filled gaps. + + @param rCandidate + The source polygon defining the hairline polygon path + + @param fHalfLineWidth + The width of the line to one side + + @param eJoin + The LineJoin if the edges meeting in a point do not have a C1 + or C2 continuity + + @param eCap + The kind of cap, which is added to the line. + + @param fMaxAllowedAngle + Allows to hand over the maximum allowed angle between an edge and + it's control vectors. The smaller, the more subdivisions will be + needed to create the filled geometry. Allowed range is cropped to + [M_PI_2 .. 0.01 * M_PI_2]. + + @param fMaxPartOfEdge + Allows to influence from with relative length of a control vector + compared to its edge a split is forced. The smaller, the more + subdivisions will be needed to create the filled geometry. Allowed + range is cropped to [1.0 .. 0.01] + + @param fMiterMinimumAngle + The minimum wanted angle between two edges when edge rounding + is using miter. When an edge is smaller than this (tighter) + the usual fallback to bevel is used. Allowed range is cropped + to [M_PI .. 0.01 * M_PI]. + + Commit 51b5b93092d6231615de470c62494c24e54828a1 needs + revert, we need the triangulation for X11 fat line drawing + + @param pTriangles + If given, the method will additionally add the created geometry as + B2DTriangle's + + @return + The tools::PolyPolygon containing the geometry of the extended line by + it's line width. Contains bezier segments and edge roundings as + needed and defined. + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon createAreaGeometry( + const B2DPolygon& rCandidate, + double fHalfLineWidth, + B2DLineJoin eJoin, + css::drawing::LineCap eCap, + double fMaxAllowedAngle = basegfx::deg2rad(12.5), + double fMaxPartOfEdge = 0.4, + double fMiterMinimumAngle = basegfx::deg2rad(15.0)); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 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: */ diff --git a/include/basegfx/polygon/b2dpolygonclipper.hxx b/include/basegfx/polygon/b2dpolygonclipper.hxx new file mode 100644 index 0000000000..a6a2ce9d2f --- /dev/null +++ b/include/basegfx/polygon/b2dpolygonclipper.hxx @@ -0,0 +1,65 @@ +/* -*- 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 <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/basegfxdllapi.h> + +namespace basegfx +{ + class B2DRange; +} + +namespace basegfx::utils +{ + // This method clips the given tools::PolyPolygon against a horizontal or vertical axis (parallel to X or Y axis). The axis is + // defined by bParallelToXAxis (true -> it's parallel to the X-Axis of the coordinate system, else to the Y-Axis) and the + // fValueOnOtherAxis (gives the translation to the coordinate system axis). For example, when You want to define + // a clip axis parallel to X.Axis and 100 above it, use bParallelToXAxis = true and fValueOnOtherAxis = 100. + // The value bAboveAxis defines on which side the return value will be (true -> above X, right of Y). + // The switch bStroke decides if the polygon is interpreted as area (false) or strokes (true). + B2DPolyPolygon clipPolyPolygonOnParallelAxis(const B2DPolyPolygon& rCandidate, bool bParallelToXAxis, bool bAboveAxis, double fValueOnOtherAxis, bool bStroke); + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolygonOnParallelAxis(const B2DPolygon& rCandidate, bool bParallelToXAxis, bool bAboveAxis, double fValueOnOtherAxis, bool bStroke); + + // Clip the given tools::PolyPolygon against the given range. bInside defines if the result will contain the + // parts which are contained in the range or vice versa. + // The switch bStroke decides if the polygon is interpreted as area (false) or strokes (true). + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolyPolygonOnRange(const B2DPolyPolygon& rCandidate, const B2DRange& rRange, bool bInside, bool bStroke); + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolygonOnRange(const B2DPolygon& rCandidate, const B2DRange& rRange, bool bInside, bool bStroke); + + // Clip given tools::PolyPolygon against given clipping polygon. + // The switch bStroke decides if the polygon is interpreted as area (false) or strokes (true). + // With stroke polygons, You get all line snippets inside rCip. + // With filled polygons, You get all tools::PolyPolygon parts which were inside rClip. + // The switch bInside decides if the parts inside the clip polygon or outside shall be created. + // The clip polygon is always assumed closed, even when it's isClosed() is false. + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolyPolygonOnPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPolyPolygon& rClip, + bool bInside, bool bStroke, size_t *pPointLimit = nullptr); + BASEGFX_DLLPUBLIC B2DPolyPolygon clipPolygonOnPolyPolygon(const B2DPolygon& rCandidate, const B2DPolyPolygon& rClip, bool bInside, bool bStroke); + + // clip the given polygon against the given range. the resulting polygon will always contain + // the inside parts which will always be interpreted as areas. the incoming polygon is expected + // to be a simple triangle list. the result is also a simple triangle list. + BASEGFX_DLLPUBLIC B2DPolygon clipTriangleListOnRange( const B2DPolygon& rCandidate, const B2DRange& rRange ); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolygoncutandtouch.hxx b/include/basegfx/polygon/b2dpolygoncutandtouch.hxx new file mode 100644 index 0000000000..600ad1c5cd --- /dev/null +++ b/include/basegfx/polygon/b2dpolygoncutandtouch.hxx @@ -0,0 +1,47 @@ +/* -*- 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 <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> + +namespace basegfx::utils +{ + +// look for self-intersections and self-touches (points on an edge) in given polygon and add +// extra points there. Result will have no touches or intersections on an edge, only on points +B2DPolygon addPointsAtCutsAndTouches(const B2DPolygon& rCandidate, size_t* pPointLimit = nullptr); + +// look for polypolygon-intersections and polypolygon-touches (point of poly A on an edge of poly B) in given tools::PolyPolygon and add +// extra points there. Result will have no touches or intersections between contained polygons on an edge, only on points. For +// convenience, the correction for self-intersections for each member polygon will be used, too. +B2DPolyPolygon addPointsAtCutsAndTouches(const B2DPolyPolygon& rCandidate, size_t* pPointLimit = nullptr); + +// look for intersections of rCandidate with the edge from rStart to rEnd and add extra points there. +// Points are only added in the range of the edge, not on the endless vector. +B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPoint& rStart, const B2DPoint& rEnd); + +// look for intersections of rCandidate with the mask Polygon and add extra points there. +// The mask polygon is assumed to be closed, even when it's not explicitly. +B2DPolygon addPointsAtCuts(const B2DPolygon& rCandidate, const B2DPolyPolygon& rMask); + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolygontools.hxx b/include/basegfx/polygon/b2dpolygontools.hxx new file mode 100644 index 0000000000..d21d0bb63b --- /dev/null +++ b/include/basegfx/polygon/b2dpolygontools.hxx @@ -0,0 +1,548 @@ +/* -*- 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 <vector> +#include <functional> + +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <basegfx/range/b2drectangle.hxx> +#include <basegfx/polygon/b3dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontriangulator.hxx> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/drawing/FlagSequence.hpp> +#include <basegfx/basegfxdllapi.h> +#include <o3tl/typed_flags_set.hxx> + + +namespace basegfx { class B2DPolyPolygon; } + +// Definitions for the cut flags used from the findCut methods +enum class CutFlagValue +{ + NONE = 0x0000, + LINE = 0x0001, + START1 = 0x0002, + START2 = 0x0004, + END1 = 0x0008, + END2 = 0x0010, + ALL = LINE|START1|START2|END1|END2, + DEFAULT = LINE|START2|END2, +}; +namespace o3tl +{ + template<> struct typed_flags<CutFlagValue> : is_typed_flags<CutFlagValue, 0x1f> {}; +} + +namespace basegfx +{ + class B2DPolygon; + class B2DRange; +} + +namespace basegfx::utils +{ + // B2DPolygon tools + + // open/close with point add/remove and control point corrections + BASEGFX_DLLPUBLIC void openWithGeometryChange(B2DPolygon& rCandidate); + BASEGFX_DLLPUBLIC void closeWithGeometryChange(B2DPolygon& rCandidate); + + /** Check if given polygon is closed. + + This is kind of a 'classic' method to support old polygon + definitions. Those old polygon definitions define the + closed state of the polygon using identical start and + endpoints. This method corrects this (removes double + start/end points) and sets the Closed()-state of the + polygon correctly. + */ + BASEGFX_DLLPUBLIC void checkClosed(B2DPolygon& rCandidate); + + // Get successor and predecessor indices. Returning the same index means there + // is none. Same for successor. + BASEGFX_DLLPUBLIC sal_uInt32 getIndexOfPredecessor(sal_uInt32 nIndex, const B2DPolygon& rCandidate); + BASEGFX_DLLPUBLIC sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B2DPolygon& rCandidate); + + // Get orientation of Polygon + BASEGFX_DLLPUBLIC B2VectorOrientation getOrientation(const B2DPolygon& rCandidate); + + // isInside tests for B2dPoint and other B2dPolygon. On border is not inside as long as + // not true is given in bWithBorder flag. + BASEGFX_DLLPUBLIC bool isInside(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder = false); + BASEGFX_DLLPUBLIC bool isInside(const B2DPolygon& rCandidate, const B2DPolygon& rPolygon, bool bWithBorder = false); + + /** Get the range of a polygon + + This method creates the outer range of the subdivided bezier curve. + For detailed discussion see B2DPolygon::getB2DRange() + + @param rCandidate + The B2DPolygon possibly containing bezier segments + + @return + The outer range of the bezier curve + */ + BASEGFX_DLLPUBLIC B2DRange getRange(const B2DPolygon& rCandidate); + + // get signed area of polygon + BASEGFX_DLLPUBLIC double getSignedArea(const B2DPolygon& rCandidate); + + // get area of polygon + BASEGFX_DLLPUBLIC double getArea(const B2DPolygon& rCandidate); + + /** get length of polygon edge from point nIndex to nIndex + 1 */ + BASEGFX_DLLPUBLIC double getEdgeLength(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + /** get length of polygon */ + BASEGFX_DLLPUBLIC double getLength(const B2DPolygon& rCandidate, bool bApproximateBezierLength = false); + + // get position on polygon for absolute given distance. If + // length is given, it is assumed the correct polygon length, if 0.0 it is calculated + // using getLength(...) + BASEGFX_DLLPUBLIC B2DPoint getPositionAbsolute(const B2DPolygon& rCandidate, double fDistance, double fLength = 0.0); + + // get position on polygon for relative given distance in range [0.0 .. 1.0]. If + // length is given, it is assumed the correct polygon length, if 0.0 it is calculated + // using getLength(...) + BASEGFX_DLLPUBLIC B2DPoint getPositionRelative(const B2DPolygon& rCandidate, double fDistance, double fLength = 0.0); + + // get a snippet from given polygon for absolute distances. The polygon is assumed + // to be opened (not closed). fFrom and fTo need to be in range [0.0 .. fLength], where + // fTo >= fFrom. If length is given, it is assumed the correct polygon length, + // if 0.0 it is calculated using getLength(...) + BASEGFX_DLLPUBLIC B2DPolygon getSnippetAbsolute(const B2DPolygon& rCandidate, double fFrom, double fTo, double fLength = 0.0); + + // Continuity check for point with given index + BASEGFX_DLLPUBLIC B2VectorContinuity getContinuityInPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + // Subdivide all contained curves. Use distanceBound value if given. + BASEGFX_DLLPUBLIC B2DPolygon adaptiveSubdivideByDistance(const B2DPolygon& rCandidate, double fDistanceBound, int nRecurseLimit = 30); + + // Subdivide all contained curves. Use angleBound value if given. + BASEGFX_DLLPUBLIC B2DPolygon adaptiveSubdivideByAngle(const B2DPolygon& rCandidate, double fAngleBound = 0.0); + + // This version works with two points and vectors to define the + // edges for the cut test. + BASEGFX_DLLPUBLIC CutFlagValue findCut( + const B2DPoint& rEdge1Start, const B2DVector& rEdge1Delta, + const B2DPoint& rEdge2Start, const B2DVector& rEdge2Delta, + CutFlagValue aCutFlags = CutFlagValue::DEFAULT, + double* pCut1 = nullptr, double* pCut2 = nullptr); + + // test if point is on the given edge in range ]0.0..1.0[ without + // the start/end points. If so, return true and put the parameter + // value in pCut (if provided) + BASEGFX_DLLPUBLIC bool isPointOnEdge( + const B2DPoint& rPoint, + const B2DPoint& rEdgeStart, + const B2DVector& rEdgeDelta, + double* pCut = nullptr); + + /** Apply given LineDashing to given polygon + + This method is used to cut down line polygons to the needed + pieces when a dashing needs to be applied. + It is now capable of keeping contained bezier segments. + It is also capable of delivering line and non-line portions + depending on what target polygons You provide. This is useful + e.g. for dashed lines with two colors. + If the last and the first snippet in one of the results have + a common start/end ppoint, they will be merged to achieve as + view as needed result line snippets. This is also relevant for + further processing the results. + + @param rCandidate + The polygon based on which the snippets will be created. + + @param rDotDashArray + The line pattern given as array of length values + + @param pLineTarget + The target for line snippets, e.g. the first entry will be + a line segment with length rDotDashArray[0]. The given + polygon will be emptied as preparation. + + @param pGapTarget + The target for gap snippets, e.g. the first entry will be + a line segment with length rDotDashArray[1]. The given + polygon will be emptied as preparation. + + @param fFullDashDotLen + The summed-up length of the rDotDashArray. If zero, it will + be calculated internally. + + There is now a 2nd version that allows to provide callback + functions that get called when a snippet of a line/gap is + produced and needs to be added. This allows to use it like + a 'pipeline'. When using this (e.g. the 1st version uses + this internally to guarantee the same algorithm is used) + it is not needed to accumulate a potentially huge number + of polygons in the result-polyPolygons, but e.g. consume + them directly in the caller. Example is rendering a + dashed line but without creating the potentially huge amount + of polygons. + The 2nd version will also merge first/last line/gap snippets + if the input polygon is closed and the start/end-points match + accordingly - at the cost that this will be delivered last. + */ + BASEGFX_DLLPUBLIC void applyLineDashing( + const B2DPolygon& rCandidate, + const std::vector<double>& rDotDashArray, + const std::function<void(const basegfx::B2DPolygon& rSnippet)>& rLineTargetCallback, + const std::function<void(const basegfx::B2DPolygon& rSnippet)>& rGapTargetCallback = std::function<void(const basegfx::B2DPolygon&)>(), + double fDotDashLength = 0.0); + BASEGFX_DLLPUBLIC void applyLineDashing( + const B2DPolygon& rCandidate, + const ::std::vector<double>& rDotDashArray, + B2DPolyPolygon* pLineTarget, + B2DPolyPolygon* pGapTarget = nullptr, + double fDotDashLength = 0.0); + + // test if point is inside epsilon-range around an edge defined + // by the two given points. Can be used for HitTesting. The epsilon-range + // is defined to be the rectangle centered to the given edge, using height + // 2 x fDistance, and the circle around both points with radius fDistance. + BASEGFX_DLLPUBLIC bool isInEpsilonRange(const B2DPoint& rEdgeStart, const B2DPoint& rEdgeEnd, const B2DPoint& rTestPosition, double fDistance); + + // test if point is inside epsilon-range around the given Polygon. Can be used + // for HitTesting. The epsilon-range is defined to be the rectangle centered + // to the given edge, using height 2 x fDistance, and the circle around both points + // with radius fDistance. + BASEGFX_DLLPUBLIC bool isInEpsilonRange(const B2DPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance); + + /** Create a polygon from a rectangle. + + @param rRect + The rectangle which describes the polygon size + + @param fRadiusX + @param fRadiusY + Radius of the edge rounding, relative to the rectangle size. 0.0 means no + rounding, 1.0 will lead to an ellipse + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromRect( const B2DRectangle& rRect, double fRadiusX, double fRadiusY ); + + /** Create a polygon from a rectangle. + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromRect( const B2DRectangle& rRect ); + + /** Create the unit polygon + */ + BASEGFX_DLLPUBLIC B2DPolygon const & createUnitPolygon(); + + /** Create a circle polygon with given radius. + + This method creates a circle approximation consisting of + 12 cubic bezier segments, which approximate the given + circle with an error of less than 0.5 percent. + + @param rCenter + Center point of the circle + + @param fRadius + Radius of the circle + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromCircle( const B2DPoint& rCenter, double fRadius ); + + /// create half circle centered on (0,0) from [0 .. M_PI] + B2DPolygon const & createHalfUnitCircle(); + + /** create a polygon which describes the unit circle and close it + + @param nStartQuadrant + To be able to rebuild the old behaviour where the circles started at bottom, + this parameter is used. Default is 0 which is the first quadrant and the + polygon's start point will be the rightmost one. When using e.g. 1, the + first created quadrant will start at the YMax-position (with Y down on screens, + this is the lowest one). This is needed since when lines are dashed, toe old + geometry started at bottom point, else it would look different. + */ + BASEGFX_DLLPUBLIC B2DPolygon const & createPolygonFromUnitCircle(sal_uInt32 nStartQuadrant = 0); + + /** Create an ellipse polygon with given radii. + + This method creates an ellipse approximation consisting of + 12 cubic bezier segments, which approximate the given + ellipse with an error of less than 0.5 percent. + + @param rCenter + Center point of the circle + + @param fRadiusX + Radius of the ellipse in X direction + + @param fRadiusY + Radius of the ellipse in Y direction + + @param nStartQuadrant + With Y down on screens, 0 = 3 o'clock, 1 = 6 o'clock, 2 = 9 o'clock, 3 = 12 o'clock + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromEllipse( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, sal_uInt32 nStartQuadrant = 0); + + /** Create a unit ellipse polygon with the given angles, from start to end + */ + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromEllipseSegment( const B2DPoint& rCenter, double fRadiusX, double fRadiusY, double fStart, double fEnd ); + + BASEGFX_DLLPUBLIC B2DPolygon createPolygonFromUnitEllipseSegment( double fStart, double fEnd ); + + /** Predicate whether a given polygon is a rectangle. + + @param rPoly + Polygon to check + + @return true, if the polygon describes a rectangle + (polygon is closed, and the points are either cw or ccw + enumerations of a rectangle's vertices). Note that + intermediate points and duplicate points are ignored. + */ + BASEGFX_DLLPUBLIC bool isRectangle( const B2DPolygon& rPoly ); + + // create 3d polygon from given 2d polygon. The given fZCoordinate is used to expand the + // third coordinate. + BASEGFX_DLLPUBLIC B3DPolygon createB3DPolygonFromB2DPolygon(const B2DPolygon& rCandidate, double fZCoordinate = 0.0); + + // create 2d tools::PolyPolygon from given 3d PolyPolygon. All coordinates are transformed using the given + // matrix and the resulting x,y is used to form the new polygon. + BASEGFX_DLLPUBLIC B2DPolygon createB2DPolygonFromB3DPolygon(const B3DPolygon& rCandidate, const B3DHomMatrix& rMat); + + // calculate the smallest distance to given edge and return. The relative position on the edge is returned in Cut. + // That position is in the range [0.0 .. 1.0] and the returned distance is adapted accordingly to the start or end + // point of the edge + BASEGFX_DLLPUBLIC double getSmallestDistancePointToEdge(const B2DPoint& rPointA, const B2DPoint& rPointB, const B2DPoint& rTestPoint, double& rCut); + + // for each contained edge calculate the smallest distance. Return the index to the smallest + // edge in rEdgeIndex. The relative position on the edge is returned in rCut. + // If nothing was found (e.g. empty input plygon), DBL_MAX is returned. + BASEGFX_DLLPUBLIC double getSmallestDistancePointToPolygon(const B2DPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rEdgeIndex, double& rCut); + + // distort single point. rOriginal describes the original range, where the given points describe the distorted corresponding points. + BASEGFX_DLLPUBLIC B2DPoint distort(const B2DPoint& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight); + + // distort polygon. rOriginal describes the original range, where the given points describe the distorted corresponding points. + BASEGFX_DLLPUBLIC B2DPolygon distort(const B2DPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight); + + // expand all segments (which are not yet) to curve segments. This is done with setting the control + // vectors on the 1/3 resp. 2/3 distances on each segment. + BASEGFX_DLLPUBLIC B2DPolygon expandToCurve(const B2DPolygon& rCandidate); + + // expand given segment to curve segment. This is done with setting the control + // vectors on the 1/3 resp. 2/3 distances. The return value describes if a change took place. + BASEGFX_DLLPUBLIC bool expandToCurveInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex); + + // set continuity for given index. If not a curve, nothing will change. Non-curve points are not changed, too. + // The return value describes if a change took place. + BASEGFX_DLLPUBLIC bool setContinuityInPoint(B2DPolygon& rCandidate, sal_uInt32 nIndex, B2VectorContinuity eContinuity); + + // test if polygon contains neutral points. A neutral point is one whose orientation is neutral + // e.g. positioned on the edge of its predecessor and successor + BASEGFX_DLLPUBLIC bool hasNeutralPoints(const B2DPolygon& rCandidate); + + // remove neutral points. A neutral point is one whose orientation is neutral + // e.g. positioned on the edge of its predecessor and successor + BASEGFX_DLLPUBLIC B2DPolygon removeNeutralPoints(const B2DPolygon& rCandidate); + + // tests if polygon is convex + BASEGFX_DLLPUBLIC bool isConvex(const B2DPolygon& rCandidate); + + // calculates the orientation at edge nIndex + BASEGFX_DLLPUBLIC B2VectorOrientation getOrientationForIndex(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + // calculates if given point is on given line, taking care of the numerical epsilon + BASEGFX_DLLPUBLIC bool isPointOnLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidate, bool bWithPoints); + + // calculates if given point is on given polygon, taking care of the numerical epsilon. Uses + // isPointOnLine internally + BASEGFX_DLLPUBLIC bool isPointOnPolygon(const B2DPolygon& rCandidate, const B2DPoint& rPoint, bool bWithPoints = true); + + // test if candidate is inside triangle + BASEGFX_DLLPUBLIC bool isPointInTriangle(const B2DPoint& rA, const B2DPoint& rB, const B2DPoint& rC, const B2DPoint& rCandidate, bool bWithBorder); + + // test if candidateA and candidateB are on the same side of the given line + bool arePointsOnSameSideOfLine(const B2DPoint& rStart, const B2DPoint& rEnd, const B2DPoint& rCandidateA, const B2DPoint& rCandidateB, bool bWithLine); + + // add triangles for given rCandidate to rTarget. For each triangle, 3 points will be added to rCandidate. + // All triangles will go from the start point of rCandidate to two consecutive points, building (rCandidate.count() - 2) + // triangles. + void addTriangleFan( + const B2DPolygon& rCandidate, + triangulator::B2DTriangleVector& rTarget); + + // grow for polygon. Move all geometry in each point in the direction of the normal in that point + // with the given amount. Value may be negative. + BASEGFX_DLLPUBLIC B2DPolygon growInNormalDirection(const B2DPolygon& rCandidate, double fValue); + + // force all sub-polygons to a point count of nSegments + BASEGFX_DLLPUBLIC B2DPolygon reSegmentPolygon(const B2DPolygon& rCandidate, sal_uInt32 nSegments); + + // create polygon state at t from 0.0 to 1.0 between the two polygons. Both polygons must have the same + // organisation, e.g. same amount of points + BASEGFX_DLLPUBLIC B2DPolygon interpolate(const B2DPolygon& rOld1, const B2DPolygon& rOld2, double t); + + // #i76891# Try to remove existing curve segments if they are simply edges + BASEGFX_DLLPUBLIC B2DPolygon simplifyCurveSegments(const B2DPolygon& rCandidate); + + // makes the given indexed point the new polygon start point. To do that, the points in the + // polygon will be rotated. This is only valid for closed polygons, for non-closed ones + // an assertion will be triggered + BASEGFX_DLLPUBLIC B2DPolygon makeStartPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndexOfNewStatPoint); + + /** create edges of given length along given B2DPolygon + + @param rCandidate + The polygon to move along. Points at the given polygon are created, starting + at position fStart and stopping at less or equal to fEnd. The closed state is + preserved. + The polygon is subdivided if curve segments are included. That subdivision is the base + for the newly created points. + If the source is closed, the indirectly existing last edge may NOT have the + given length. + If the source is open, all edges will have the given length. You may use the last + point of the original when You want to add the last edge Yourself. + + @param fLength + The length of the created edges. If less or equal zero, an empty polygon is returned. + + @param fStart + The start distance for the first to be generated point. Use 0.0 to get the + original start point. Negative values are truncated to 0.0. + + @param fEnd + The maximum distance for the last point. No more points behind this distance will be created. + Use 0.0 to process the whole polygon. Negative values are truncated to 0.0. It also + needs to be more or equal to fStart, else it is truncated to fStart. + + @return + The newly created polygon + */ + B2DPolygon createEdgesOfGivenLength(const B2DPolygon& rCandidate, double fLength, double fStart = 0.0, double fEnd = 0.0); + + /** Create Waveline along given polygon + The implementation is based on createEdgesOfGivenLength and creates a curve + segment with the given dimensions for each created line segment. The polygon + is treated as if opened (closed state will be ignored) and only for whole + edges a curve segment will be created (no rest handling) + + @param rCandidate + The polygon along which the waveline will be created + + @param fWaveWidth + The length of a single waveline curve segment + + @param fgWaveHeight + The height of the waveline (amplitude) + */ + BASEGFX_DLLPUBLIC B2DPolygon createWaveline(const B2DPolygon& rCandidate, double fWaveWidth, double fWaveHeight); + + /** snap some polygon coordinates to discrete coordinates + + This method allows to snap some polygon points to discrete (integer) values + which equals e.g. a snap to discrete coordinates. It will snap points of + horizontal and vertical edges + + @param rCandidate + The source polygon + + @return + The modified version of the source polygon + */ + BASEGFX_DLLPUBLIC B2DPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolygon& rCandidate); + + /// get the tangent with which the given point is entered seen from the previous + /// polygon path data. Take into account all stuff like closed state, zero-length edges and others. + BASEGFX_DLLPUBLIC B2DVector getTangentEnteringPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + /// get the tangent with which the given point is left seen from the following + /// polygon path data. Take into account all stuff like closed state, zero-length edges and others. + BASEGFX_DLLPUBLIC B2DVector getTangentLeavingPoint(const B2DPolygon& rCandidate, sal_uInt32 nIndex); + + /// converters for css::drawing::PointSequence + BASEGFX_DLLPUBLIC B2DPolygon UnoPointSequenceToB2DPolygon( + const css::drawing::PointSequence& rPointSequenceSource); + BASEGFX_DLLPUBLIC void B2DPolygonToUnoPointSequence( + const B2DPolygon& rPolygon, + css::drawing::PointSequence& rPointSequenceRetval); + + /* converters for css::drawing::PointSequence and + css::drawing::FlagSequence to B2DPolygon (curved polygons) + */ + B2DPolygon UnoPolygonBezierCoordsToB2DPolygon( + const css::drawing::PointSequence& rPointSequenceSource, + const css::drawing::FlagSequence& rFlagSequenceSource); + void B2DPolygonToUnoPolygonBezierCoords( + const B2DPolygon& rPolyPolygon, + css::drawing::PointSequence& rPointSequenceRetval, + css::drawing::FlagSequence& rFlagSequenceRetval); + + /** Read poly-polygon from SVG. + + This function imports a poly-polygon from an SVG points + attribute (a plain list of coordinate pairs). + + @param o_rPoly + The output polygon. Note that svg:points can only define a + single polygon + + @param rSvgPointsAttribute + A valid SVG points attribute string + + @return true, if the string was successfully parsed + */ + BASEGFX_DLLPUBLIC bool importFromSvgPoints( B2DPolygon& o_rPoly, + std::u16string_view rSvgPointsAttribute ); + + /** Write poly-polygon to SVG. + + This function imports a non-bezier polygon to SVG points + (a plain list of coordinate pairs). + + @param rPoly + The polygon to export + + @param rSvgPointsAttribute + A valid SVG points attribute string + + @return true, if the string was successfully parsed + */ + BASEGFX_DLLPUBLIC OUString exportToSvgPoints( const B2DPolygon& rPoly ); + + /** Reduces the number of points using the Ramer-Douglas-Peucker (RDP) algorithm. If the input + polygon has control points or less than three points, the input polygon is returned + unchanged. Otherwise, a simplified polygon is returned. If the input polygon is closed, + the caller is expected to ensure that the first and last points of the polygon are + identical. The polygon is treated as open in this case. Closing the result polygon is not + performed here, but left to the caller. + + @param rCandidate + The source polygon from which the reduced polygon is generated + + @param fTolerance + The tolerance for the RDP algorithm. + + @return + A newly created polygon with reduced point count. + */ + BASEGFX_DLLPUBLIC B2DPolygon createSimplifiedPolygon(const B2DPolygon& rCandidate, + const double fTolerance); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolygontriangulator.hxx b/include/basegfx/polygon/b2dpolygontriangulator.hxx new file mode 100644 index 0000000000..1fb2c9d542 --- /dev/null +++ b/include/basegfx/polygon/b2dpolygontriangulator.hxx @@ -0,0 +1,71 @@ +/* -*- 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 <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/basegfxdllapi.h> + +#include <vector> + +namespace basegfx { class B2DPolyPolygon; } + +namespace basegfx::triangulator +{ + // Simple B2D-based triangle. Main reason is to + // keep the data types separated (before a B2DPolygon + // was used with the convention that three points in + // a row define a triangle) + class BASEGFX_DLLPUBLIC B2DTriangle + { + // positions + basegfx::B2DPoint maA; + basegfx::B2DPoint maB; + basegfx::B2DPoint maC; + + public: + B2DTriangle( + const basegfx::B2DPoint& rA, + const basegfx::B2DPoint& rB, + const basegfx::B2DPoint& rC) + : maA(rA), + maB(rB), + maC(rC) + { + } + + // get positions + const basegfx::B2DPoint& getA() const { return maA; } + const basegfx::B2DPoint& getB() const { return maB; } + const basegfx::B2DPoint& getC() const { return maC; } + }; + + // typedef for a vector of B2DTriangle + typedef ::std::vector< B2DTriangle > B2DTriangleVector; + + // triangulate given polygon + BASEGFX_DLLPUBLIC B2DTriangleVector triangulate(const ::basegfx::B2DPolygon& rCandidate); + + // triangulate given PolyPolygon + BASEGFX_DLLPUBLIC B2DTriangleVector triangulate(const ::basegfx::B2DPolyPolygon& rCandidate); + +} // end of namespace basegfx::triangulator + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolypolygon.hxx b/include/basegfx/polygon/b2dpolypolygon.hxx new file mode 100644 index 0000000000..d3177e3c4c --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygon.hxx @@ -0,0 +1,171 @@ +/* -*- 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 <ostream> +#include <vector> + +#include <sal/types.h> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/range/b2drange.hxx> +#include <basegfx/basegfxdllapi.h> +#include <basegfx/polygon/b2dpolygon.hxx> + +namespace basegfx +{ + class B2DHomMatrix; + class ImplB2DPolyPolygon; + + class BASEGFX_DLLPUBLIC B2DPolyPolygon + { + private: + o3tl::cow_wrapper<ImplB2DPolyPolygon, o3tl::ThreadSafeRefCountingPolicy> mpPolyPolygon; + + public: + B2DPolyPolygon(); + B2DPolyPolygon(const B2DPolyPolygon& rPolyPolygon); + B2DPolyPolygon(B2DPolyPolygon&& rPolyPolygon); + explicit B2DPolyPolygon(const B2DPolygon& rPolygon); + ~B2DPolyPolygon(); + + // assignment operator + B2DPolyPolygon& operator=(const B2DPolyPolygon& rPolyPolygon); + B2DPolyPolygon& operator=(B2DPolyPolygon&& rPolyPolygon); + + /// unshare this poly-polygon (and all included polygons) with all internally shared instances + void makeUnique(); + + // compare operators + bool operator==(const B2DPolyPolygon& rPolyPolygon) const; + bool operator!=(const B2DPolyPolygon& rPolyPolygon) const; + + // polygon interface + sal_uInt32 count() const; + + B2DPolygon const & getB2DPolygon(sal_uInt32 nIndex) const; + void setB2DPolygon(sal_uInt32 nIndex, const B2DPolygon& rPolygon); + + // test for curve + bool areControlPointsUsed() const; + + // insert/append single polygon + void insert(sal_uInt32 nIndex, const B2DPolygon& rPolygon, sal_uInt32 nCount = 1); + void append(const B2DPolygon& rPolygon, sal_uInt32 nCount = 1); + void reserve(sal_uInt32 nCount); + + /** Default adaptive subdivision access + + For details refer to B2DPolygon::getDefaultAdaptiveSubdivision() + + @return + The default subdivision of this polygon + */ + B2DPolyPolygon getDefaultAdaptiveSubdivision() const; + + /** Get the B2DRange (Rectangle dimensions) of this B2DPolyPolygon + + For details refer to B2DPolygon::getB2DRange() + + @return + The outer range of the bezier curve/polygon + */ + B2DRange getB2DRange() const; + + // insert/append multiple polygons + void insert(sal_uInt32 nIndex, const B2DPolyPolygon& rPolyPolygon); + void append(const B2DPolyPolygon& rPolyPolygon); + + // remove + void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1); + + // reset to empty state + void clear(); + + // closed state + bool isClosed() const; + void setClosed(bool bNew); + + // flip polygon direction + void flip(); + + // test if tools::PolyPolygon 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 to the polygon + void transform(const basegfx::B2DHomMatrix& rMatrix); + + // polygon iterators (same iterator validity conditions as for vector) + const B2DPolygon* begin() const; + const B2DPolygon* end() const; + B2DPolygon* begin(); + B2DPolygon* end(); + + // 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; + }; + + // typedef for a vector of B2DPolyPolygons + typedef ::std::vector< B2DPolyPolygon > B2DPolyPolygonVector; + + template< typename charT, typename traits > + inline std::basic_ostream<charT, traits> & operator <<( + std::basic_ostream<charT, traits> & stream, const B2DPolyPolygon& poly ) + { + stream << "[" << poly.count() << ":"; + for (sal_uInt32 i = 0; i < poly.count(); i++) + { + if (i > 0) + stream << ","; + stream << poly.getB2DPolygon(i); + } + stream << "]"; + + return stream; + } + +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolypolygoncutter.hxx b/include/basegfx/polygon/b2dpolypolygoncutter.hxx new file mode 100644 index 0000000000..55dd29cf8e --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygoncutter.hxx @@ -0,0 +1,144 @@ +/* -*- 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 <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/basegfxdllapi.h> + + +namespace basegfx::utils +{ + /** Solve all crossovers (aka self-intersections) in a polyPolygon. + + This re-layouts all contained polygons so that the result + will contain only non-cutting polygons. For that reason, + points will be added at crossover and touch points and the + single Polygons may be re-combined. The orientations of + the contained polygons in not changed but used as + topological information. Self crossovers of the contained + sub-polygons are implicitly handled, but to not lose the + topological information, it may be necessary to remove + self-intersections of the contained sub-polygons in a + preparing step and to explicitly correct their + orientations. + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon solveCrossovers(const B2DPolyPolygon& rCandidate, + size_t* pPointLimit = nullptr); + + /** Solve all crossovers (aka self-intersections) in a Polygon + + Same as above, but for single polygons. Result will be + free of self-intersections. When result contains multiple + polygons, it may be necessary to rearrange their + orientations since holes may have been created (possibly use + correctOrientations). + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon solveCrossovers(const B2DPolygon& rCandidate); + + /** Strip neutral polygons from PolyPolygon. + + Neutral polygons are ones who's orientation is neutral, so + normally they have no volume -> just closed paths. A + polygon with the same positive and negative oriented + volume is also neutral, so this may not be wanted. It is + safe to call with self-intersection-free polygons, though + (that's where it's mostly used). + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon stripNeutralPolygons(const B2DPolyPolygon& rCandidate); + + /** Remove unnecessary/non-displayed polygons. + + Works only correct with self-intersection-free + polygons. For each polygon, the depth for the PolyPolygon + is calculated. The orientation is used to identify holes. + Start value for holes is -1, for polygons it's zero. Ech + time a polygon is contained in another one, it's depth is + increased when inside a polygon, decreased when inside a + hole. The result is a depth which e.g. is -1 for holes + outside everything, 1 for a polygon covered by another + polygon and zero for e.g. holes in a polygon or polygons + outside everything else. In the 2nd step, all polygons + with depth other than zero are removed. If bKeepAboveZero + is used, all polygons < 1 are removed. The bKeepAboveZero + mode is useful for clipping, e.g. just append one polygon + to another and use this mode -> only parts where two + polygons overlapped will be kept. In combination with + correct orientation of the input orientations and the + SolveCrossover calls this can be combined for logical + polygon operations or polygon clipping. + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon stripDispensablePolygons(const B2DPolyPolygon& rCandidate, bool bKeepAboveZero = false); + + /** Emulate nonzero winding rule filling. + + Geometrically convert PolyPolygons which are proposed to + use nonzero fill rule to a representation where evenodd + paint will give the same result. To do this all + intersections and self-intersections get solved (the + polygons will be rearranged if needed). Then all polygons + which are inside another one with the same orientation get + deleted + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon createNonzeroConform(const B2DPolyPolygon& rCandidate); + + // For convenience: the four basic operations OR, XOR, AND and DIFF for + // two PolyPolygons. These are combinations of the above methods. To not be forced + // to do evtl. already done preparations twice, You have to do the operations Yourself. + + // A source preparation consists of preparing it to be seen as XOR-Rule PolyPolygon, + // so it is freed of intersections, self-intersections and the orientations are corrected. + // Important is that it will define the same areas as before, but is intersection-free. + // As an example think about a single polygon looping in itself and having holes. To + // topologically correctly handle this, it is necessary to remove all intersections and + // to correct the orientations. The orientation of the isolated holes e.g. will be negative. + // Topologically it is necessary to prepare each polygon which is seen as entity. It is + // not sufficient just to concatenate them and prepare the result, this may be topologically + // different since the simple concatenation will be seen as XOR. To work correctly, You + // may need to OR those polygons. + + /// prep for ops - solve self-intersections and intersections, remove neutral parts and check orientations. + BASEGFX_DLLPUBLIC B2DPolyPolygon prepareForPolygonOperation(const B2DPolygon& rCandidate); + /// prep for ops - solve self-intersections and intersections, remove neutral parts and check orientations. + BASEGFX_DLLPUBLIC B2DPolyPolygon prepareForPolygonOperation(const B2DPolyPolygon& rCandidate); + + /// OR: Return all areas where CandidateA or CandidateB exist + BASEGFX_DLLPUBLIC B2DPolyPolygon solvePolygonOperationOr(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB); + + /// XOR: Return all areas where CandidateA or CandidateB exist, but not both + BASEGFX_DLLPUBLIC B2DPolyPolygon solvePolygonOperationXor(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB); + + /// AND: Return all areas where CandidateA and CandidateB exist + BASEGFX_DLLPUBLIC B2DPolyPolygon solvePolygonOperationAnd(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB); + + /// DIFF: Return all areas where CandidateA is not covered by CandidateB (cut B out of A) + BASEGFX_DLLPUBLIC B2DPolyPolygon solvePolygonOperationDiff(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB); + + /** merge all single PolyPolygons to a single, OR-ed PolyPolygon + + @param rInput + The source PolyPolygons + + @return A single tools::PolyPolygon containing the Or-merged result + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon mergeToSinglePolyPolygon(const B2DPolyPolygonVector& rInput); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dpolypolygontools.hxx b/include/basegfx/polygon/b2dpolypolygontools.hxx new file mode 100644 index 0000000000..8960946332 --- /dev/null +++ b/include/basegfx/polygon/b2dpolypolygontools.hxx @@ -0,0 +1,297 @@ +/* -*- 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 <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b3dpolypolygon.hxx> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <vector> +#include <basegfx/basegfxdllapi.h> +#include <o3tl/sorted_vector.hxx> + +namespace com::sun::star::drawing { struct PolyPolygonBezierCoords; } + +namespace basegfx +{ + class B2DPolyPolygon; + class B2DRange; +} + +namespace basegfx::utils +{ + // B2DPolyPolygon tools + + // Check and evtl. correct orientations of all contained Polygons so that + // the orientations of contained polygons will variate to express areas and + // holes + BASEGFX_DLLPUBLIC B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate); + + // make sure polygon with index 0L is not a hole. This may evtl. change the + // sequence of polygons, but allows to use polygon with index 0L to + // get the correct normal for the whole polyPolygon + BASEGFX_DLLPUBLIC B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate); + + // Subdivide all contained curves. Use distanceBound value if given. + BASEGFX_DLLPUBLIC B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound, int nRecurseLimit = 30); + + // Subdivide all contained curves. Use distanceBound value if given. Else, a convenient one + // is created. + BASEGFX_DLLPUBLIC B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound = 0.0); + + // isInside test for B2dPoint. On border is not inside as long as not true is given + // in bWithBorder flag. It is assumed that the orientations of the given polygon are correct. + BASEGFX_DLLPUBLIC bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder = false); + + /** Get the range of a polyPolygon + + For detailed description look at getRange(const B2DPolygon&). + This method just expands by the range of every sub-Polygon. + + @param rCandidate + The B2DPolyPolygon possibly containing bezier segments + + @return + The outer range of the polygon + */ + BASEGFX_DLLPUBLIC B2DRange getRange(const B2DPolyPolygon& rCandidate); + + // get signed area of polygon + BASEGFX_DLLPUBLIC double getSignedArea(const B2DPolyPolygon& rCandidate); + + // get area of polygon + BASEGFX_DLLPUBLIC double getArea(const B2DPolyPolygon& rCandidate); + + /** Apply given LineDashing to given polyPolygon + + For a description see applyLineDashing in b2dpolygontoos.hxx + */ + BASEGFX_DLLPUBLIC void applyLineDashing( + const B2DPolyPolygon& rCandidate, + const ::std::vector<double>& rDotDashArray, + B2DPolyPolygon* pLineTarget, + double fFullDashDotLen = 0.0); + + // test if point is inside epsilon-range around the given PolyPolygon. Can be used + // for HitTesting. The epsilon-range is defined to be the tube around the PolyPolygon + // with distance fDistance and rounded edges (start and end point). + BASEGFX_DLLPUBLIC bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance); + + /** Helper class to transport PointIndices to a PolyPolygon, + with an operator< for convenient sorting in a std::set usage + */ + class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC PointIndex + { + private: + sal_uInt32 mnPolygonIndex; + sal_uInt32 mnPointIndex; + + public: + PointIndex(sal_uInt32 nPolygonIndex, sal_uInt32 nPointIndex) + : mnPolygonIndex(nPolygonIndex), + mnPointIndex(nPointIndex) + {} + + sal_uInt32 getPolygonIndex() const { return mnPolygonIndex; } + sal_uInt32 getPointIndex() const { return mnPointIndex; } + bool operator<(const PointIndex& rComp) const; + }; + + /** the PointIndexSet itself; it allows to define a 'selection'of + points in a tools::PolyPolygon by giving the polygon and point index. + Adding points double makes no sense, hence the std::set + */ + typedef o3tl::sorted_vector< PointIndex > PointIndexSet; + + /** Read poly-polygon from SVG. + + This function imports a poly-polygon from an SVG-D + attribute. + + @param o_rPolyPoly + The output poly-polygon + + @param rSvgDAttribute + A valid SVG-D attribute string + + @param bHandleRelativeNextPointCompatible + If set to true, the old error that after a relative 'z' command + the current point was not reset to the first point of the current + polygon is kept; this is needed to read odf files. + If false, pure svg is used; this is needed for svg import. + + @param pHelpPointIndexSet + If given, all points created in the target PolyPolygon + which are only helper points are added here using their + point indices; this are currently points created from + import of the 'a' and 'A' svg:d statements which create + bezier curve info as representation and maybe points + which are no 'real' svg:d points, but helper points. It + is necessary to identify these e.g. when markers need to + be created in the svg import + + @return true, if the string was successfully parsed + */ + BASEGFX_DLLPUBLIC bool importFromSvgD( + B2DPolyPolygon& o_rPolyPoly, + std::u16string_view rSvgDAttribute, + bool bHandleRelativeNextPointCompatible, + PointIndexSet* pHelpPointIndexSet); + + // grow for polyPolygon. Move all geometry in each point in the direction of the normal in that point + // with the given amount. Value may be negative. + BASEGFX_DLLPUBLIC B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue); + + // force all sub-polygons to a point count of nSegments + BASEGFX_DLLPUBLIC B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments); + + // create polygon state at t from 0.0 to 1.0 between the two polygons. Both polygons must have the same + // organisation, e.g. same amount of polygons + BASEGFX_DLLPUBLIC B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t); + + // create 3d tools::PolyPolygon from given 2d PolyPolygon. The given fZCoordinate is used to expand the + // third coordinate. + BASEGFX_DLLPUBLIC B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate = 0.0); + + // create 2d tools::PolyPolygon from given 3d PolyPolygon. All coordinates are transformed using the given + // matrix and the resulting x,y is used to form the new polygon. + BASEGFX_DLLPUBLIC B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat); + + // for each contained edge in each contained polygon calculate the smallest distance. Return the index to the smallest + // edge in rEdgeIndex and the index to the polygon in rPolygonIndex. The relative position on the edge is returned in rCut. + // If nothing was found (e.g. empty input plygon), DBL_MAX is returned. + BASEGFX_DLLPUBLIC double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut); + + // distort PolyPolygon. rOriginal describes the original range, where the given points describe the distorted + // corresponding points. + BASEGFX_DLLPUBLIC B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight); + + // expand all segments (which are not yet) to curve segments. This is done with setting the control + // vectors on the 1/3 resp. 2/3 distances on each segment. + BASEGFX_DLLPUBLIC B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate); + + /** Predicate whether a given poly-polygon is a rectangle. + + @param rPoly + tools::PolyPolygon to check + + @return true, if the poly-polygon describes a rectangle + (contains exactly one polygon, polygon is closed, and the + points are either cw or ccw enumerations of a rectangle's + vertices). Note that intermediate points and duplicate + points are ignored. + */ + BASEGFX_DLLPUBLIC bool isRectangle( const B2DPolyPolygon& rPoly ); + + /** Export poly-polygon to SVG. + + This function exports a poly-polygon into an SVG-D + statement. Currently, output of relative point sequences + is not yet supported (might cause slightly larger output) + + @param rPolyPoly + The poly-polygon to export + + @param bUseRelativeCoordinates + When true, all coordinate values are exported as relative + to the current position. This tends to save some space, + since fewer digits needs to be written. + + @param bDetectQuadraticBeziers + When true, the export tries to detect cubic bezier + segments in the input polygon, which can be represented by + quadratic bezier segments. Note that the generated string + causes versions prior to OOo2.0 to crash. + + @param bHandleRelativeNextPointCompatible + If set to true, the old error that after a relative 'z' command + the current point was not reset to the first point of the current + polygon is kept; this is needed to read odf files. + If false, pure svg is used; this is needed for svg import. + + @param bOOXMLMotionPath + If set to true, export string format that is acceptable for + for animation motion path for PowerPoint: always space delimited, + never neglect command char, always end with E, and do not export + H or V. + + @return the generated SVG-D statement (the XML d attribute + value alone, without any "<path ...>" or "d="...") + */ + BASEGFX_DLLPUBLIC OUString exportToSvgD( + const B2DPolyPolygon& rPolyPoly, + bool bUseRelativeCoordinates, + bool bDetectQuadraticBeziers, + bool bHandleRelativeNextPointCompatible, + bool bOOXMLMotionPath = false); + + // #i76891# Try to remove existing curve segments if they are simply edges + BASEGFX_DLLPUBLIC B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate); + + /** Creates polypolygon for seven-segment display number + + This function takes an integer number between 0 and 9 and + convert it into the well-known seven-segment display + number (like most digital clocks show their numbers). The + digit will exactly fit the unit rectangle. The polypolygon + will be a line polygon, i.e. if you need the segment parts + to have width, use createAreaGeometry() on the result. + + @param cNumber + Number from '0' to '9' as ASCII char, or '-', 'E' and '.' + to convert to 7 segment code + + @param bLitSegments + When true, return a polygon containing the segments that + are 'lit' for the given number. Return un-lit segments + otherwise. + */ + B2DPolyPolygon createSevenSegmentPolyPolygon(char cNumber, bool bLitSegments); + + /** snap some polygon coordinates to discrete coordinates + + This method allows to snap some polygon points to discrete (integer) values + which equals e.g. a snap to discrete coordinates. It will snap points of + horizontal and vertical edges + + @param rCandidate + The source polygon + + @return + The modified version of the source polygon + */ + BASEGFX_DLLPUBLIC B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate); + + /// converters for css::drawing::PointSequence + BASEGFX_DLLPUBLIC B2DPolyPolygon UnoPointSequenceSequenceToB2DPolyPolygon( + const css::drawing::PointSequenceSequence& rPointSequenceSequenceSource); + BASEGFX_DLLPUBLIC void B2DPolyPolygonToUnoPointSequenceSequence( + const B2DPolyPolygon& rPolyPolygon, + css::drawing::PointSequenceSequence& rPointSequenceSequenceRetval); + + /// converters for css::drawing::PolyPolygonBezierCoords (curved polygons) + BASEGFX_DLLPUBLIC B2DPolyPolygon UnoPolyPolygonBezierCoordsToB2DPolyPolygon( + const css::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsSource); + BASEGFX_DLLPUBLIC void B2DPolyPolygonToUnoPolyPolygonBezierCoords( + const B2DPolyPolygon& rPolyPolygon, + css::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsRetval); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b2dtrapezoid.hxx b/include/basegfx/polygon/b2dtrapezoid.hxx new file mode 100644 index 0000000000..aeed7148e2 --- /dev/null +++ b/include/basegfx/polygon/b2dtrapezoid.hxx @@ -0,0 +1,108 @@ +/* -*- 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 <config_options.h> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <vector> +#include <basegfx/basegfxdllapi.h> + + +namespace basegfx { class B2DPolyPolygon; } +namespace basegfx { class B2DPoint; } + +namespace basegfx +{ + // class to hold a single trapezoid + class UNLESS_MERGELIBS(BASEGFX_DLLPUBLIC) B2DTrapezoid + { + private: + // Geometry data. YValues are down-oriented, this means bottom should + // be bigger than top to be below it. The constructor implementation + // guarantees: + + // - mfBottomY >= mfTopY + // - mfTopXRight >= mfTopXLeft + // - mfBottomXRight >= mfBottomXLeft + double mfTopXLeft; + double mfTopXRight; + double mfTopY; + double mfBottomXLeft; + double mfBottomXRight; + double mfBottomY; + + public: + // constructor + B2DTrapezoid( + const double& rfTopXLeft, + const double& rfTopXRight, + const double& rfTopY, + const double& rfBottomXLeft, + const double& rfBottomXRight, + const double& rfBottomY); + + // data read access + const double& getTopXLeft() const { return mfTopXLeft; } + const double& getTopXRight() const { return mfTopXRight; } + const double& getTopY() const { return mfTopY; } + const double& getBottomXLeft() const { return mfBottomXLeft; } + const double& getBottomXRight() const { return mfBottomXRight; } + const double& getBottomY() const { return mfBottomY; } + + // convenience method to get content as Polygon + B2DPolygon getB2DPolygon() const; + }; + + typedef ::std::vector< B2DTrapezoid > B2DTrapezoidVector; + +} // end of namespace basegfx + + +namespace basegfx::utils +{ + // convert SourcePolyPolygon to trapezoids. The trapezoids will be appended to + // ro_Result. ro_Result will not be cleared. If SourcePolyPolygon contains curves, + // it's default AdaptiveSubdivision will be used. + // CAUTION: Trapezoids are orientation-dependent in the sense that the upper and lower + // lines have to be parallel to the X-Axis, thus this subdivision is NOT simply usable + // for primitive decompositions. To use it, the shear and rotate parts of the + // involved transformations HAVE to be taken into account. + BASEGFX_DLLPUBLIC void trapezoidSubdivide( + B2DTrapezoidVector& ro_Result, + const B2DPolyPolygon& rSourcePolyPolygon); + + // directly create trapezoids from given edge. Depending on the given geometry, + // none up to three trapezoids will be created + void createLineTrapezoidFromEdge( + B2DTrapezoidVector& ro_Result, + const B2DPoint& rPointA, + const B2DPoint& rPointB, + double fLineWidth); + + // create trapezoids for all edges of the given polygon. The closed state of + // the polygon is taken into account. If curves are contained, the default + // AdaptiveSubdivision will be used. + void createLineTrapezoidFromB2DPolygon( + B2DTrapezoidVector& ro_Result, + const B2DPolygon& rPolygon, + double fLineWidth); +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b3dpolygon.hxx b/include/basegfx/polygon/b3dpolygon.hxx new file mode 100644 index 0000000000..13f8ed293f --- /dev/null +++ b/include/basegfx/polygon/b3dpolygon.hxx @@ -0,0 +1,120 @@ +/* -*- 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 <sal/types.h> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/basegfxdllapi.h> + +class ImplB3DPolygon; + +namespace basegfx +{ + class B3DPoint; + class B3DHomMatrix; + class B3DVector; + class B2DPoint; + class B2DHomMatrix; + class BColor; +} + +namespace basegfx +{ + class BASEGFX_DLLPUBLIC B3DPolygon + { + public: + typedef o3tl::cow_wrapper< ImplB3DPolygon, o3tl::ThreadSafeRefCountingPolicy > ImplType; + + private: + // internal data. + ImplType mpPolygon; + + public: + B3DPolygon(); + B3DPolygon(const B3DPolygon& rPolygon); + B3DPolygon(B3DPolygon&& rPolygon); + ~B3DPolygon(); + + // assignment operator + B3DPolygon& operator=(const B3DPolygon& rPolygon); + B3DPolygon& operator=(B3DPolygon&& rPolygon); + + // compare operators + bool operator==(const B3DPolygon& rPolygon) const; + + // member count + sal_uInt32 count() const; + + // Coordinate interface + B3DPoint const & getB3DPoint(sal_uInt32 nIndex) const; + void setB3DPoint(sal_uInt32 nIndex, const B3DPoint& rValue); + + // Coordinate append + void append(const B3DPoint& rPoint, sal_uInt32 nCount = 1); + + // BColor interface + BColor const & getBColor(sal_uInt32 nIndex) const; + void setBColor(sal_uInt32 nIndex, const BColor& rValue); + bool areBColorsUsed() const; + void clearBColors(); + + // Normals interface + B3DVector const & getNormal() const; // plane normal + B3DVector const & getNormal(sal_uInt32 nIndex) const; // normal in each point + void setNormal(sal_uInt32 nIndex, const B3DVector& rValue); + void transformNormals(const B3DHomMatrix& rMatrix); + bool areNormalsUsed() const; + void clearNormals(); + + // TextureCoordinate interface + B2DPoint const & getTextureCoordinate(sal_uInt32 nIndex) const; + void setTextureCoordinate(sal_uInt32 nIndex, const B2DPoint& rValue); + void transformTextureCoordinates(const B2DHomMatrix& rMatrix); + bool areTextureCoordinatesUsed() const; + void clearTextureCoordinates(); + + // append other 2D polygons + void append(const B3DPolygon& rPoly, sal_uInt32 nIndex = 0, sal_uInt32 nCount = 0); + + // remove + void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1); + + // clear all points + void clear(); + + // closed state + 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 to the polygon + void transform(const B3DHomMatrix& rMatrix); + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b3dpolygontools.hxx b/include/basegfx/polygon/b3dpolygontools.hxx new file mode 100644 index 0000000000..2f890809cf --- /dev/null +++ b/include/basegfx/polygon/b3dpolygontools.hxx @@ -0,0 +1,129 @@ +/* -*- 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 <vector> +#include <functional> + +#include <basegfx/point/b3dpoint.hxx> +#include <basegfx/vector/b3dvector.hxx> +#include <basegfx/basegfxdllapi.h> + +namespace basegfx +{ + class B3DPolyPolygon; + class B3DPolygon; + class B3DRange; +} + +namespace basegfx::utils +{ + // B3DPolygon tools + + /** Check if given polygon is closed. This is kind of a + 'classic' method to support old polygon definitions. + Those old polygon definitions define the closed state + of the polygon using identical start and endpoints. This + method corrects this (removes double start/end points) + and sets the Closed()-state of the polygon correctly. + */ + BASEGFX_DLLPUBLIC void checkClosed(B3DPolygon& rCandidate); + + // Get successor and predecessor indices. Returning the same index means there + // is none. Same for successor. + BASEGFX_DLLPUBLIC sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate); + + // get size of polygon. Control vectors are included in that ranges. + BASEGFX_DLLPUBLIC B3DRange getRange(const B3DPolygon& rCandidate); + + // get length of polygon + BASEGFX_DLLPUBLIC double getLength(const B3DPolygon& rCandidate); + + /** Apply given LineDashing to given polygon + + For a description see applyLineDashing in b2dpolygontoos.hxx + Also 2nd version with callbacks, see comments in 2D version + */ + void applyLineDashing( + const B3DPolygon& rCandidate, + const std::vector<double>& rDotDashArray, + const std::function<void(const basegfx::B3DPolygon& rSnippet)>& rLineTargetCallback, + double fDotDashLength = 0.0); + BASEGFX_DLLPUBLIC void applyLineDashing( + const B3DPolygon& rCandidate, + const ::std::vector<double>& rDotDashArray, + B3DPolyPolygon* pLineTarget, + double fDotDashLength = 0.0); + + /** Create/replace normals for given 3d geometry with default normals from given center to outside. + rCandidate: the 3d geometry to change + rCenter: the center of the 3d geometry + */ + B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter); + + /** invert normals for given 3d geometry. + */ + BASEGFX_DLLPUBLIC B3DPolygon invertNormals( const B3DPolygon& rCandidate); + + /** Create/replace texture coordinates for given 3d geometry with parallel projected one + rRange: the full range of the 3d geometry + If bChangeX, x texture coordinate will be recalculated. + If bChangeY, y texture coordinate will be recalculated. + */ + B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY); + + /** Create/replace texture coordinates for given 3d geometry with spherical one + rCenter: the centre of the used 3d geometry + If bChangeX, x texture coordinate will be recalculated. + If bChangeY, y texture coordinate will be recalculated. + */ + B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY); + + // isInside tests for B3DPoint. On border is not inside as long as not true is given in bWithBorder flag. + BASEGFX_DLLPUBLIC bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder); + + // calculates if given point is on given line, taking care of the numerical epsilon + BASEGFX_DLLPUBLIC bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint& rCandidate, bool bWithPoints); + + // calculates if given point is on given polygon, taking care of the numerical epsilon. Uses + // isPointOnLine internally + BASEGFX_DLLPUBLIC bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint); + + // helper to get a fCut position between a plane (given with normal and a point) + // and a line given by start and end point + BASEGFX_DLLPUBLIC bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut); + + /** snap some polygon coordinates to discrete coordinates + + This method allows to snap some polygon points to discrete (integer) values + which equals e.g. a snap to discrete coordinates. It will snap points of + horizontal and vertical edges + + @param rCandidate + The source polygon + + @return + The modified version of the source polygon + */ + BASEGFX_DLLPUBLIC B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b3dpolypolygon.hxx b/include/basegfx/polygon/b3dpolypolygon.hxx new file mode 100644 index 0000000000..14a062c08c --- /dev/null +++ b/include/basegfx/polygon/b3dpolypolygon.hxx @@ -0,0 +1,113 @@ +/* -*- 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 <sal/types.h> +#include <o3tl/cow_wrapper.hxx> +#include <basegfx/basegfxdllapi.h> + +class ImplB3DPolyPolygon; + +namespace basegfx +{ + class B3DPolygon; + class B3DHomMatrix; + class B2DHomMatrix; +} + +namespace basegfx +{ + class BASEGFX_DLLPUBLIC B3DPolyPolygon + { + public: + typedef o3tl::cow_wrapper< ImplB3DPolyPolygon, o3tl::ThreadSafeRefCountingPolicy > ImplType; + + private: + ImplType mpPolyPolygon; + + public: + B3DPolyPolygon(); + B3DPolyPolygon(const B3DPolyPolygon& rPolyPolygon); + B3DPolyPolygon(B3DPolyPolygon&& rPolygon); + explicit B3DPolyPolygon(const B3DPolygon& rPolygon); + ~B3DPolyPolygon(); + + // assignment operator + B3DPolyPolygon& operator=(const B3DPolyPolygon& rPolyPolygon); + B3DPolyPolygon& operator=(B3DPolyPolygon&& rPolyPolygon); + + // compare operators + bool operator==(const B3DPolyPolygon& rPolyPolygon) const; + bool operator!=(const B3DPolyPolygon& rPolyPolygon) const; + + // polygon interface + sal_uInt32 count() const; + + // B3DPolygon interface + B3DPolygon const & getB3DPolygon(sal_uInt32 nIndex) const; + void setB3DPolygon(sal_uInt32 nIndex, const B3DPolygon& rPolygon); + + // BColor interface + bool areBColorsUsed() const; + void clearBColors(); + + // Normals interface + void transformNormals(const B3DHomMatrix& rMatrix); + bool areNormalsUsed() const; + void clearNormals(); + + // TextureCoordinate interface + void transformTextureCoordinates(const B2DHomMatrix& rMatrix); + bool areTextureCoordinatesUsed() const; + void clearTextureCoordinates(); + + // append single polygon + void append(const B3DPolygon& rPolygon, sal_uInt32 nCount = 1); + + // append multiple polygons + void append(const B3DPolyPolygon& rPolyPolygon); + + // remove + void remove(sal_uInt32 nIndex, sal_uInt32 nCount = 1); + + // reset to empty state + void clear(); + + // flip polygon direction + void flip(); + + // test if tools::PolyPolygon 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 to the polygon + void transform(const basegfx::B3DHomMatrix& rMatrix); + + // polygon iterators (same iterator validity conditions as for vector) + const B3DPolygon* begin() const; + const B3DPolygon* end() const; + B3DPolygon* begin(); + B3DPolygon* end(); + }; +} // end of namespace basegfx + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/include/basegfx/polygon/b3dpolypolygontools.hxx b/include/basegfx/polygon/b3dpolypolygontools.hxx new file mode 100644 index 0000000000..d201696dc8 --- /dev/null +++ b/include/basegfx/polygon/b3dpolypolygontools.hxx @@ -0,0 +1,132 @@ +/* -*- 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 <basegfx/point/b3dpoint.hxx> +#include <basegfx/basegfxdllapi.h> + +namespace com::sun::star::drawing { struct PolyPolygonShape3D; } + +namespace basegfx +{ + class B3DPolyPolygon; + class B3DRange; +} + +namespace basegfx::utils +{ + // B3DPolyPolygon tools + + // get size of PolyPolygon. Control vectors are included in that ranges. + BASEGFX_DLLPUBLIC B3DRange getRange(const B3DPolyPolygon& rCandidate); + + /** Create a unit 3D line polyPolygon which defines a cube. + */ + B3DPolyPolygon const & createUnitCubePolyPolygon(); + + /** Create a unit 3D fill polyPolygon which defines a cube. + */ + B3DPolyPolygon const & createUnitCubeFillPolyPolygon(); + + /** Create a 3D line polyPolygon from a B3DRange which defines a cube. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createCubePolyPolygonFromB3DRange( const B3DRange& rRange); + + /** Create a 3D fill polyPolygon from a B3DRange which defines a cube. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createCubeFillPolyPolygonFromB3DRange( const B3DRange& rRange); + + /** Create a unit 3D line polyPolygon which defines a sphere with the given count of hor and ver segments. + Result will be centered at (0.0, 0.0, 0.0) and sized [-1.0 .. 1.0] in all dimensions. + If nHorSeg == 0 and/or nVerSeg == 0, a default will be calculated to have a step at least each 15 degrees. + With VerStart, VerStop and hor range in cartesian may be specified to create a partial sphere only. + */ + B3DPolyPolygon createUnitSpherePolyPolygon( + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + double fVerStart = M_PI_2, double fVerStop = -M_PI_2, + double fHorStart = 0.0, double fHorStop = 2 * M_PI); + + /** Create a 3D line polyPolygon from a B3DRange which defines a sphere with the given count of hor and ver segments. + If nHorSeg == 0 and/or nVerSeg == 0, a default will be calculated to have a step at least each 15 degrees. + With VerStart, VerStop and hor range in cartesian may be specified to create a partial sphere only. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createSpherePolyPolygonFromB3DRange( + const B3DRange& rRange, + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + double fVerStart = M_PI_2, double fVerStop = -M_PI_2, + double fHorStart = 0.0, double fHorStop = 2 * M_PI); + + /** same as createUnitSpherePolyPolygon, but creates filled polygons (closed and oriented) + There is one extra, the bool bNormals defines if normals will be set, default is false + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createUnitSphereFillPolyPolygon( + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + bool bNormals = false, + double fVerStart = M_PI_2, double fVerStop = -M_PI_2, + double fHorStart = 0.0, double fHorStop = 2 * M_PI); + + /** same as createSpherePolyPolygonFromB3DRange, but creates filled polygons (closed and oriented) + There is one extra, the bool bNormals defines if normals will be set, default is false + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon createSphereFillPolyPolygonFromB3DRange( + const B3DRange& rRange, + sal_uInt32 nHorSeg, sal_uInt32 nVerSeg, + bool bNormals = false, + double fVerStart = M_PI_2, double fVerStop = -M_PI_2, + double fHorStart = 0.0, double fHorStop = 2 * M_PI); + + /** Create/replace normals for given 3d geometry with default normals from given center to outside. + rCandidate: the 3d geometry to change + rCenter: the center of the 3d geometry + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon applyDefaultNormalsSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter); + + /** invert normals for given 3d geometry. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon invertNormals( const B3DPolyPolygon& rCandidate); + + /** Create/replace texture coordinates for given 3d geometry with parallel projected one + rRange: the full range of the 3d geometry + If bChangeX, x texture coordinate will be recalculated. + If bChangeY, y texture coordinate will be recalculated. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bChangeX = true, bool bChangeY = true); + + /** Create/replace texture coordinates for given 3d geometry with spherical one + rCenter: the centre of the used 3d geometry + If bChangeX, x texture coordinate will be recalculated. + If bChangeY, y texture coordinate will be recalculated. + */ + BASEGFX_DLLPUBLIC B3DPolyPolygon applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX = true, bool bChangeY = true); + + // isInside test for B3DPoint. On border is not inside. + // It is assumed that the orientations of the given polygon are correct. + BASEGFX_DLLPUBLIC bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint); + + /// converters for css::drawing::PolyPolygonShape3D + BASEGFX_DLLPUBLIC B3DPolyPolygon UnoPolyPolygonShape3DToB3DPolyPolygon( + const css::drawing::PolyPolygonShape3D& rPolyPolygonShape3DSource); + BASEGFX_DLLPUBLIC void B3DPolyPolygonToUnoPolyPolygonShape3D( + const B3DPolyPolygon& rPolyPolygonSource, + css::drawing::PolyPolygonShape3D& rPolyPolygonShape3DRetval); + +} // end of namespace basegfx::utils + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |