1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
|
/* -*- 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 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;
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(SystemDependentDataManager& manager, Args&&... args) const
{
std::shared_ptr<T> r = std::make_shared<T>(manager, 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 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: */
|