1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
25 #include <sal/types.h>
26 #include <o3tl/cow_wrapper.hxx>
27 #include <basegfx/vector/b2enums.hxx>
28 #include <basegfx/basegfxdllapi.h>
38 class SystemDependentData
;
39 class SystemDependentDataManager
;
40 typedef std::shared_ptr
<SystemDependentData
> SystemDependentData_SharedPtr
;
45 class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2DPolygon
48 typedef o3tl::cow_wrapper
< ImplB2DPolygon
> ImplType
;
55 /// diverse constructors
57 B2DPolygon(const B2DPolygon
& rPolygon
);
58 B2DPolygon(B2DPolygon
&& rPolygon
);
59 B2DPolygon(const B2DPolygon
& rPolygon
, sal_uInt32 nIndex
, sal_uInt32 nCount
);
60 B2DPolygon(std::initializer_list
<basegfx::B2DPoint
> rPoints
);
64 /// assignment operator
65 B2DPolygon
& operator=(const B2DPolygon
& rPolygon
);
66 B2DPolygon
& operator=(B2DPolygon
&& rPolygon
);
68 /// unshare this polygon with all internally shared instances
72 bool operator==(const B2DPolygon
& rPolygon
) const;
73 bool operator!=(const B2DPolygon
& rPolygon
) const;
76 sal_uInt32
count() const;
78 /// Coordinate interface
79 basegfx::B2DPoint
const & getB2DPoint(sal_uInt32 nIndex
) const;
80 void setB2DPoint(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
);
82 /// Coordinate insert/append
83 void insert(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPoint
, sal_uInt32 nCount
= 1);
84 void append(const basegfx::B2DPoint
& rPoint
, sal_uInt32 nCount
);
85 void append(const basegfx::B2DPoint
& rPoint
);
86 void reserve(sal_uInt32 nCount
);
88 /// Basic ControlPoint interface
89 basegfx::B2DPoint
getPrevControlPoint(sal_uInt32 nIndex
) const;
90 basegfx::B2DPoint
getNextControlPoint(sal_uInt32 nIndex
) const;
91 void setPrevControlPoint(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
);
92 void setNextControlPoint(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rValue
);
93 void setControlPoints(sal_uInt32 nIndex
, const basegfx::B2DPoint
& rPrev
, const basegfx::B2DPoint
& rNext
);
95 /// ControlPoint resets
96 void resetPrevControlPoint(sal_uInt32 nIndex
);
97 void resetNextControlPoint(sal_uInt32 nIndex
);
98 void resetControlPoints();
100 /// Bezier segment append with control points. The current last polygon point is implicitly taken as start point.
101 void appendBezierSegment(const basegfx::B2DPoint
& rNextControlPoint
,
102 const basegfx::B2DPoint
& rPrevControlPoint
,
103 const basegfx::B2DPoint
& rPoint
);
105 /// This is a shortcut to append a quadratic bezier segment. The current last polygon point is implicitly taken as start point.
106 /// Note that the quadratic bezier control points will be converted to cubic bezier with 2 control points.
107 void appendQuadraticBezierSegment(const basegfx::B2DPoint
& rQuadControlPoint
,
108 const basegfx::B2DPoint
& rPoint
);
110 /// ControlPoint checks
111 bool areControlPointsUsed() const;
112 bool isPrevControlPointUsed(sal_uInt32 nIndex
) const;
113 bool isNextControlPointUsed(sal_uInt32 nIndex
) const;
114 B2VectorContinuity
getContinuityInPoint(sal_uInt32 nIndex
) const;
116 /** bezier segment access
118 This method also works when it is no bezier segment at all and will fill
119 the given B2DCubicBezier as needed.
120 In any case, the given B2DCubicBezier will be filled, if necessary with
121 the single start point (if no valid edge exists).
124 Index of the addressed edge's start point
127 The B2DCubicBezier to be filled. It's data WILL be changed.
129 void getBezierSegment(sal_uInt32 nIndex
, B2DCubicBezier
& rTarget
) const;
131 /** Default adaptive subdivision access
133 This method will return a default adaptive subdivision of the polygon.
134 If the polygon does not contain any bezier curve segments, it will
137 The subdivision is created on first request and buffered, so when using
138 this subdivision You have the guarantee for fast accesses for multiple
139 usages. It is intended for tooling usage for tasks which would be hard
140 to accomplish on bezier segments (e.g. isInEpsilonRange).
142 The current default subdivision uses adaptiveSubdivideByCount with 9
143 subdivisions which gives 10 edges and 11 points per segment and is
144 usually pretty usable for processing purposes. There is no parameter
145 passing here ATM but it may be changed on demand. If needed, a TYPE
146 and PARAMETER (both defaulted) may be added to allow for switching
147 between the different kinds of subdivisioned and passing them one
150 The lifetime of the buffered subdivision is based on polygon changes.
151 When changing the polygon, it will be flushed. It is buffered at the
152 refcounted implementation class, so it will survive copy by value and
153 combinations in PolyPolygons.
156 The default (and buffered) subdivision of this polygon. It may
157 be this polygon itself when it has no bezier segments. It is guaranteed
158 to have no more bezier segments
160 B2DPolygon
const & getDefaultAdaptiveSubdivision() const;
162 /** Get the B2DRange (Rectangle dimensions) of this B2DPolygon
164 A polygon may have up to three ranges:
166 (a) the range of the polygon points
167 (b) the range of the polygon points and control points
168 (c) the outer range of the subdivided bezier curve
170 Ranges (a) and (c) are produced by tools::getRange(); resp. this
171 getB2DRange(). tools::getRangeWithControlPoints handles case (b).
173 To get range (c) a simple solution would be to subdivide the polygon
174 and use getRange() on it. Since subdivision is expensive and decreases
175 the polygon quality, i added this new method. It will use a
176 methodology suggested by HDU. First, it gets the range (a).
177 Then it iterates over the bezier segments and for each it
178 first tests if the outer range of the bezier segment is already
179 contained in the result range.
181 The subdivision itself uses getAllExtremumPositions() to only
182 calculate extremum points and to expand the result accordingly.
183 Thus it calculates maximal four extremum points on the bezier
184 segment, no split is used at all.
187 The outer range of the bezier curve/polygon
189 B2DRange
const & getB2DRange() const;
191 /** append other 2D polygons
193 The default (nIndex ==0 && nCount == 0) will append
200 The index to the first point of rPoly to append
203 The number of points to append from rPoly, starting
204 from nIndex. If zero, as much as possible is appended
206 void append(const B2DPolygon
& rPoly
, sal_uInt32 nIndex
= 0, sal_uInt32 nCount
= 0);
209 void remove(sal_uInt32 nIndex
, sal_uInt32 nCount
= 1);
214 /// closed state interface
215 bool isClosed() const;
216 void setClosed(bool bNew
);
218 /// flip polygon direction
221 /// test if Polygon has double points
222 bool hasDoublePoints() const;
224 /// remove double points, at the begin/end and follow-ups, too
225 void removeDoublePoints();
227 /// apply transformation given in matrix form
228 void transform(const basegfx::B2DHomMatrix
& rMatrix
);
230 // exclusive management op's for SystemDependentData at B2DPolygon
232 std::shared_ptr
<T
> getSystemDependentData() const
234 return std::static_pointer_cast
<T
>(getSystemDependantDataInternal(typeid(T
).hash_code()));
237 template<class T
, class... Args
>
238 std::shared_ptr
<T
> addOrReplaceSystemDependentData(SystemDependentDataManager
& manager
, Args
&&... args
) const
240 std::shared_ptr
<T
> r
= std::make_shared
<T
>(manager
, std::forward
<Args
>(args
)...);
242 // tdf#129845 only add to buffer if a relevant buffer time is estimated
243 if(r
->calculateCombinedHoldCyclesInSeconds() > 0)
245 basegfx::SystemDependentData_SharedPtr
r2(r
);
246 addOrReplaceSystemDependentDataInternal(r2
);
253 void addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr
& rData
) const;
254 SystemDependentData_SharedPtr
getSystemDependantDataInternal(size_t hash_code
) const;
257 // typedef for a vector of B2DPolygons
258 typedef ::std::vector
< B2DPolygon
> B2DPolygonVector
;
260 template< typename charT
, typename traits
>
261 inline std::basic_ostream
<charT
, traits
> & operator <<(
262 std::basic_ostream
<charT
, traits
> & stream
, const B2DPolygon
& poly
)
264 stream
<< "<" << poly
.count() << ":";
265 for (sal_uInt32 i
= 0; i
< poly
.count(); i
++)
269 stream
<< poly
.getB2DPoint(i
);
276 } // end of namespace basegfx
278 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */