1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 #ifndef _BGFX_POLYPOLYGON_B2DPOLYGONTOOLS_HXX
23 #define _BGFX_POLYPOLYGON_B2DPOLYGONTOOLS_HXX
24 
25 #include <basegfx/point/b2dpoint.hxx>
26 #include <basegfx/vector/b2dvector.hxx>
27 #include <basegfx/polygon/b2dpolygon.hxx>
28 #include <basegfx/polygon/b3dpolypolygon.hxx>
29 #include <com/sun/star/drawing/PointSequenceSequence.hpp>
30 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
31 #include <vector>
32 #include <set>
33 
34 namespace rtl
35 {
36     class OUString;
37 }
38 
39 //////////////////////////////////////////////////////////////////////////////
40 
41 namespace basegfx
42 {
43 	// predefinitions
44 	class B2DPolyPolygon;
45 	class B2DRange;
46 
47 	namespace tools
48 	{
49 		// B2DPolyPolygon tools
50 
51 		// Check and evtl. correct orientations of all contained Polygons so that
52 		// the orientations of contained polygons will variate to express areas and
53 		// holes
54 		B2DPolyPolygon correctOrientations(const B2DPolyPolygon& rCandidate);
55 
56 		// make sure polygon with index 0L is not a hole. This may evtl. change the
57 		// sequence of polygons, but allows to use polygon with index 0L to
58 		// get the correct normal for the whole polyPolygon
59 		B2DPolyPolygon correctOutmostPolygon(const B2DPolyPolygon& rCandidate);
60 
61 		// Subdivide all contained curves. Use distanceBound value if given.
62 		B2DPolyPolygon adaptiveSubdivideByDistance(const B2DPolyPolygon& rCandidate, double fDistanceBound = 0.0);
63 
64 		// Subdivide all contained curves. Use distanceBound value if given. Else, a convenient one
65 		// is created.
66 		B2DPolyPolygon adaptiveSubdivideByAngle(const B2DPolyPolygon& rCandidate, double fAngleBound = 0.0);
67 
68 		// Subdivide all contained curves. Use nCount divisions if given. Else, a convenient one
69 		// is created.
70 		B2DPolyPolygon adaptiveSubdivideByCount(const B2DPolyPolygon& rCandidate, sal_uInt32 nCount = 0L);
71 
72         // isInside test for B2dPoint. On border is not inside as long as not true is given
73 		// in bWithBorder flag. It is assumed that the orientations of the given polygon are correct.
74 		bool isInside(const B2DPolyPolygon& rCandidate, const B2DPoint& rPoint, bool bWithBorder = false);
75 
76 		/** get range of PolyPolygon. Control points are included.
77 
78 			For detailed description look at getRangeWithControlPoints(const B2DPolygon&).
79 			This method just expands by the range of every sub-Polygon.
80 
81 			@param rCandidate
82 			The B2DPolyPolygon eventually containing bezier segments
83 
84 			@return
85 			The outer range including control points
86 		*/
87 		B2DRange getRangeWithControlPoints(const B2DPolyPolygon& rCandidate);
88 
89 		/** Get the range of a polyPolygon
90 
91 			For detailed description look at getRange(const B2DPolygon&).
92 			This method just expands by the range of every sub-Polygon.
93 
94 			@param rCandidate
95 			The B2DPolyPolygon eventually containing bezier segments
96 
97 			@return
98 			The outer range of the polygon
99 		*/
100 		B2DRange getRange(const B2DPolyPolygon& rCandidate);
101 
102 		// get signed area of polygon
103 		double getSignedArea(const B2DPolyPolygon& rCandidate);
104 
105 		// get area of polygon
106 		double getArea(const B2DPolyPolygon& rCandidate);
107 
108         /** Apply given LineDashing to given polyPolygon
109 
110 			For a description see applyLineDashing in b2dpolygontoos.hxx
111 		*/
112 		void applyLineDashing(
113 			const B2DPolyPolygon& rCandidate,
114 			const ::std::vector<double>& rDotDashArray,
115 			B2DPolyPolygon* pLineTarget,
116             B2DPolyPolygon* pGapTarget = 0,
117 			double fFullDashDotLen = 0.0);
118 
119 		// test if point is inside epsilon-range around the given PolyPolygon. Can be used
120 		// for HitTesting. The epsilon-range is defined to be the tube around the PolyPolygon
121 		// with distance fDistance and rounded edges (start and end point).
122 		bool isInEpsilonRange(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPosition, double fDistance);
123 
124         /** Helper class to transport PointIndices to a PolyPolygon,
125             with an operator< for convenient sorting in a std::set usage
126          */
127         class PointIndex
128         {
129         private:
130             sal_uInt32 mnPolygonIndex;
131             sal_uInt32 mnPointIndex;
132 
133         public:
PointIndex(sal_uInt32 nPolygonIndex,sal_uInt32 nPointIndex)134             PointIndex(sal_uInt32 nPolygonIndex, sal_uInt32 nPointIndex)
135             :   mnPolygonIndex(nPolygonIndex),
136                 mnPointIndex(nPointIndex)
137             {}
138 
getPolygonIndex() const139             sal_uInt32 getPolygonIndex() const { return mnPolygonIndex; }
getPointIndex() const140             sal_uInt32 getPointIndex() const { return mnPointIndex; }
141             bool operator<(const PointIndex& rComp) const;
142         };
143 
144         /** the PointIndexSet itself; it allows to define a 'selection'of
145             points in a PolyPolygon by giving the polygon and point index.
146             Adding points double makes no sense, hence the std::set
147          */
148         typedef std::set< PointIndex > PointIndexSet;
149 
150         /** Read poly-polygon from SVG.
151 
152             This function imports a poly-polygon from an SVG-D
153             attribute. Currently, elliptical arc elements are not yet
154             supported (and ignored during parsing).
155 
156             @param o_rPolyPoly
157             The output poly-polygon
158 
159             @param rSvgDAttribute
160             A valid SVG-D attribute string
161 
162             @param bHandleRelativeNextPointCompatible
163             If set to true, the old error that after a relative 'z' command
164             the current point was not reset to the first point of the current
165             polygon is kept; this is needed to read odf files.
166             If false, pure svg is used; this is needed for svg import.
167 
168             @param pHelpPointIndexSet
169             If given, all points created in the target PolyPolygon
170             which are only helper points are added here using their
171             point indices; this are currently points created from
172             import of the 'a' and 'A' svg:d statements which create
173             bezier curve info as representation and maybe points
174             which are no 'real' svg:d points, but helper points. It
175             is necessary to identify these e.g. when markers need to
176             be created in the svg import
177 
178             @return true, if the string was successfully parsed
179          */
180 
181         bool importFromSvgD(
182             B2DPolyPolygon& o_rPolyPoly,
183             const ::rtl::OUString& rSvgDAttribute,
184             bool bHandleRelativeNextPointCompatible,
185             PointIndexSet* pHelpPointIndexSet);
186 
187 		// grow for polyPolygon. Move all geometry in each point in the direction of the normal in that point
188 		// with the given amount. Value may be negative.
189 		B2DPolyPolygon growInNormalDirection(const B2DPolyPolygon& rCandidate, double fValue);
190 
191 		// This method will correct a pair of polyPolygons where the goal is to keep same point count
192 		// to allow direct point association and also to remove self-intersections produced by shrinks.
193 		// This method will eventually change both polyPolygons to reach that goal because there are cases
194 		// where it is necessary to add new cut points to the original
195 		void correctGrowShrinkPolygonPair(B2DPolyPolygon& rOriginal, B2DPolyPolygon& rGrown);
196 
197 		// force all sub-polygons to a point count of nSegments
198 		B2DPolyPolygon reSegmentPolyPolygon(const B2DPolyPolygon& rCandidate, sal_uInt32 nSegments);
199 
200 		// create polygon state at t from 0.0 to 1.0 between the two polygons. Both polygons must have the same
201 		// organisation, e.g. same amount of polygons
202 		B2DPolyPolygon interpolate(const B2DPolyPolygon& rOld1, const B2DPolyPolygon& rOld2, double t);
203 
204 		// create 3d PolyPolygon from given 2d PolyPolygon. The given fZCoordinate is used to expand the
205 		// third coordinate.
206 		B3DPolyPolygon createB3DPolyPolygonFromB2DPolyPolygon(const B2DPolyPolygon& rCandidate, double fZCoordinate = 0.0);
207 
208 		// create 2d PolyPolygon from given 3d PolyPolygon. All coordinates are transformed using the given
209 		// matrix and the resulting x,y is used to form the new polygon.
210 		B2DPolyPolygon createB2DPolyPolygonFromB3DPolyPolygon(const B3DPolyPolygon& rCandidate, const B3DHomMatrix& rMat);
211 
212 		// for each contained edge in each contained polygon calculate the smallest distance. Return the index to the smallest
213 		// edge in rEdgeIndex and the index to the polygon in rPolygonIndex. The relative position on the edge is returned in rCut.
214 		// If nothing was found (e.g. empty input plygon), DBL_MAX is returned.
215 		double getSmallestDistancePointToPolyPolygon(const B2DPolyPolygon& rCandidate, const B2DPoint& rTestPoint, sal_uInt32& rPolygonIndex, sal_uInt32& rEdgeIndex, double& rCut);
216 
217 		// distort PolyPolygon. rOriginal describes the original range, where the given points describe the distorted
218 		// corresponding points.
219 		B2DPolyPolygon distort(const B2DPolyPolygon& rCandidate, const B2DRange& rOriginal, const B2DPoint& rTopLeft, const B2DPoint& rTopRight, const B2DPoint& rBottomLeft, const B2DPoint& rBottomRight);
220 
221 		// rotate PolyPolygon around given point with given angle.
222 		B2DPolyPolygon rotateAroundPoint(const B2DPolyPolygon& rCandidate, const B2DPoint& rCenter, double fAngle);
223 
224 		// expand all segments (which are not yet) to curve segments. This is done with setting the control
225 		// vectors on the 1/3 resp. 2/3 distances on each segment.
226 		B2DPolyPolygon expandToCurve(const B2DPolyPolygon& rCandidate);
227 
228 		// set continuity for the whole curve. If not a curve, nothing will change. Non-curve points are not changed, too.
229 		B2DPolyPolygon setContinuity(const B2DPolyPolygon& rCandidate, B2VectorContinuity eContinuity);
230 
231         /** Predicate whether a given poly-polygon is a rectangle.
232 
233         	@param rPoly
234             PolyPolygon to check
235 
236             @return true, if the poly-polygon describes a rectangle
237             (contains exactly one polygon, polygon is closed, and the
238             points are either cw or ccw enumerations of a rectangle's
239             vertices). Note that intermediate points and duplicate
240             points are ignored.
241          */
242         bool isRectangle( const B2DPolyPolygon& rPoly );
243 
244         /** Export poly-polygon to SVG.
245 
246         	This function exports a poly-polygon into an SVG-D
247         	statement. Currently, output of relative point sequences
248         	is not yet supported (might cause slightly larger output)
249 
250             @param rPolyPoly
251             The poly-polygon to export
252 
253             @param bUseRelativeCoordinates
254             When true, all coordinate values are exported as relative
255             to the current position. This tends to save some space,
256             since fewer digits needs to be written.
257 
258             @param bDetectQuadraticBeziers
259             When true, the export tries to detect cubic bezier
260             segments in the input polygon, which can be represented by
261             quadratic bezier segments. Note that the generated string
262             causes versions prior to OOo2.0 to crash.
263 
264             @param bHandleRelativeNextPointCompatible
265             If set to true, the old error that after a relative 'z' command
266             the current point was not reset to the first point of the current
267             polygon is kept; this is needed to read odf files.
268             If false, pure svg is used; this is needed for svg import.
269 
270             @return the generated SVG-D statement (the XML d attribute
271             value alone, without any "<path ...>" or "d="...")
272          */
273         ::rtl::OUString exportToSvgD(
274             const B2DPolyPolygon& rPolyPoly,
275             bool bUseRelativeCoordinates,
276             bool bDetectQuadraticBeziers,
277             bool bHandleRelativeNextPointCompatible);
278 
279 		// #i76891# Try to remove existing curve segments if they are simply edges
280 		B2DPolyPolygon simplifyCurveSegments(const B2DPolyPolygon& rCandidate);
281 
282         /** split each edge of a polyPolygon in exactly nSubEdges equidistant edges
283 
284             @param rCandidate
285             The source polyPolygon. If too small (no edges), nSubEdges too small (<2)
286             or neither bHandleCurvedEdgesnor bHandleStraightEdges it will just be returned.
287             Else for each edge nSubEdges will be created. Closed state is preserved.
288 
289             @param nSubEdges
290             @param bHandleCurvedEdges
291             @param bHandleStraightEdges
292             Please take a look at reSegmentPolygonEdges description, these are the same.
293         */
294 		B2DPolyPolygon reSegmentPolyPolygonEdges(const B2DPolyPolygon& rCandidate, sal_uInt32 nSubEdges, bool bHandleCurvedEdges, bool bHandleStraightEdges);
295 
296 		//////////////////////////////////////////////////////////////////////
297 		// comparators with tolerance for 2D PolyPolygons
298 		bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB, const double& rfSmallValue);
299 		bool equal(const B2DPolyPolygon& rCandidateA, const B2DPolyPolygon& rCandidateB);
300 
301 		/** snap some polygon coordinates to discrete coordinates
302 
303 			This method allows to snap some polygon points to discrete (integer) values
304 			which equals e.g. a snap to discrete coordinates. It will snap points of
305 			horizontal and vertical edges
306 
307 			@param rCandidate
308 			The source polygon
309 
310 			@return
311 			The modified version of the source polygon
312 		*/
313 		B2DPolyPolygon snapPointsOfHorizontalOrVerticalEdges(const B2DPolyPolygon& rCandidate);
314 
315         /** returns true if the Polygon only contains horizontal or vertical edges
316             so that it could be represented by RegionBands
317         */
318         bool containsOnlyHorizontalAndVerticalEdges(const B2DPolyPolygon& rCandidate);
319 
320         /// converters for com::sun::star::drawing::PointSequence
321         B2DPolyPolygon UnoPointSequenceSequenceToB2DPolyPolygon(
322             const com::sun::star::drawing::PointSequenceSequence& rPointSequenceSequenceSource,
323             bool bCheckClosed = true);
324         void B2DPolyPolygonToUnoPointSequenceSequence(
325             const B2DPolyPolygon& rPolyPolygon,
326             com::sun::star::drawing::PointSequenceSequence& rPointSequenceSequenceRetval);
327 
328         /// converters for com::sun::star::drawing::PolyPolygonBezierCoords (curved polygons)
329         B2DPolyPolygon UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
330             const com::sun::star::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsSource,
331             bool bCheckClosed = true);
332         void B2DPolyPolygonToUnoPolyPolygonBezierCoords(
333             const B2DPolyPolygon& rPolyPolygon,
334             com::sun::star::drawing::PolyPolygonBezierCoords& rPolyPolygonBezierCoordsRetval);
335 
336     } // end of namespace tools
337 } // end of namespace basegfx
338 
339 #endif /* _BGFX_POLYPOLYGON_B2DPOLYGONTOOLS_HXX */
340