Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2008 by Sun Microsystems, Inc.
7 : : *
8 : : * Portions Copright 2011 Thorsten Behrens <tbehrens@novell.com>
9 : : *
10 : : * OpenOffice.org - a multi-platform office productivity suite
11 : : *
12 : : * This file is part of OpenOffice.org.
13 : : *
14 : : * OpenOffice.org is free software: you can redistribute it and/or modify
15 : : * it under the terms of the GNU Lesser General Public License version 3
16 : : * only, as published by the Free Software Foundation.
17 : : *
18 : : * OpenOffice.org is distributed in the hope that it will be useful,
19 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 : : * GNU Lesser General Public License version 3 for more details
22 : : * (a copy is included in the LICENSE file that accompanied this code).
23 : : *
24 : : * You should have received a copy of the GNU Lesser General Public License
25 : : * version 3 along with OpenOffice.org. If not, see
26 : : * <http://www.openoffice.org/license.html>
27 : : * for a copy of the LGPLv3 License.
28 : : *
29 : : ************************************************************************/
30 : :
31 : : #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
32 : : #include <com/sun/star/drawing/PointSequence.hpp>
33 : : #include <com/sun/star/drawing/FlagSequence.hpp>
34 : : #include <basegfx/polygon/b2dpolypolygontools.hxx>
35 : : #include <basegfx/polygon/b2dpolygontools.hxx>
36 : : #include <basegfx/polygon/b2dpolygon.hxx>
37 : : #include <basegfx/curve/b2dcubicbezier.hxx>
38 : :
39 : : #include <basegfx/tools/unotools.hxx>
40 : : #include <comphelper/sequence.hxx>
41 : :
42 : :
43 : : using namespace ::com::sun::star;
44 : :
45 : : namespace basegfx
46 : : {
47 : : namespace unotools
48 : : {
49 : :
50 : 408 : B2DPolyPolygon polyPolygonBezierToB2DPolyPolygon(const drawing::PolyPolygonBezierCoords& rSourcePolyPolygon)
51 : : throw( lang::IllegalArgumentException )
52 : : {
53 : 408 : const sal_Int32 nOuterSequenceCount(rSourcePolyPolygon.Coordinates.getLength());
54 : 408 : B2DPolyPolygon aNewPolyPolygon;
55 : :
56 [ - + ]: 408 : if(rSourcePolyPolygon.Flags.getLength() != nOuterSequenceCount)
57 [ # # ]: 0 : throw lang::IllegalArgumentException();
58 : :
59 : : // get pointers to inner sequence
60 : 408 : const drawing::PointSequence* pInnerSequence = rSourcePolyPolygon.Coordinates.getConstArray();
61 : 408 : const drawing::FlagSequence* pInnerSequenceFlags = rSourcePolyPolygon.Flags.getConstArray();
62 : :
63 [ + + ]: 856 : for(sal_Int32 a(0); a < nOuterSequenceCount; a++)
64 : : {
65 : 448 : const sal_Int32 nInnerSequenceCount(pInnerSequence->getLength());
66 : :
67 [ - + ]: 448 : if(pInnerSequenceFlags->getLength() != nInnerSequenceCount)
68 [ # # ]: 0 : throw lang::IllegalArgumentException();
69 : :
70 : : // prepare new polygon
71 [ + - ]: 448 : basegfx::B2DPolygon aNewPolygon;
72 : 448 : const awt::Point* pArray = pInnerSequence->getConstArray();
73 : 448 : const drawing::PolygonFlags* pArrayFlags = pInnerSequenceFlags->getConstArray();
74 : :
75 : : // get first point and flag
76 : 448 : basegfx::B2DPoint aNewCoordinatePair(pArray->X, pArray->Y); pArray++;
77 : 448 : drawing::PolygonFlags ePolyFlag(*pArrayFlags); pArrayFlags++;
78 : 448 : basegfx::B2DPoint aControlA;
79 : 448 : basegfx::B2DPoint aControlB;
80 : :
81 : : // first point is not allowed to be a control point
82 [ - + ]: 448 : if(drawing::PolygonFlags_CONTROL == ePolyFlag)
83 [ # # ]: 0 : throw lang::IllegalArgumentException();
84 : :
85 : : // add first point as start point
86 [ + - ]: 448 : aNewPolygon.append(aNewCoordinatePair);
87 [ + + ]: 5124 : for(sal_Int32 b(1); b < nInnerSequenceCount;)
88 : : {
89 : : // prepare loop
90 : 4676 : bool bControlA(false);
91 : 4676 : bool bControlB(false);
92 : :
93 : : // get next point and flag
94 : 4676 : aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y);
95 : 4676 : ePolyFlag = *pArrayFlags;
96 : 4676 : pArray++; pArrayFlags++; b++;
97 : :
98 [ + + ][ + + ]: 4676 : if(b < nInnerSequenceCount && drawing::PolygonFlags_CONTROL == ePolyFlag)
99 : : {
100 : 2429 : aControlA = aNewCoordinatePair;
101 : 2429 : bControlA = true;
102 : :
103 : : // get next point and flag
104 : 2429 : aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y);
105 : 2429 : ePolyFlag = *pArrayFlags;
106 : 2429 : pArray++; pArrayFlags++; b++;
107 : : }
108 : :
109 [ + + ][ + + ]: 4676 : if(b < nInnerSequenceCount && drawing::PolygonFlags_CONTROL == ePolyFlag)
110 : : {
111 : 2429 : aControlB = aNewCoordinatePair;
112 : 2429 : bControlB = true;
113 : :
114 : : // get next point and flag
115 : 2429 : aNewCoordinatePair = basegfx::B2DPoint(pArray->X, pArray->Y);
116 : 2429 : ePolyFlag = *pArrayFlags;
117 : 2429 : pArray++; pArrayFlags++; b++;
118 : : }
119 : :
120 : : // two or no control points are consumed, another one would be an error.
121 : : // It's also an error if only one control point was read
122 [ + - ][ - + ]: 4676 : if(drawing::PolygonFlags_CONTROL == ePolyFlag || bControlA != bControlB)
123 [ # # ]: 0 : throw lang::IllegalArgumentException();
124 : :
125 : : // the previous writes used the B2DPolyPoygon -> PolyPolygon converter
126 : : // which did not create minimal PolyPolygons, but created all control points
127 : : // as null vectors (identical points). Because of the former P(CA)(CB)-norm of
128 : : // B2DPolygon and it's unused sign of being the zero-vector and CA and CB being
129 : : // relative to P, an empty edge was exported as P == CA == CB. Luckily, the new
130 : : // export format can be read without errors by the old OOo-versions, so we need only
131 : : // to correct here at read and do not need to export a wrong but compatible version
132 : : // for the future.
133 [ + + + + : 12731 : if(bControlA
+ - ][ + + ]
134 : 2429 : && aControlA.equal(aControlB)
135 [ + - ][ + - ]: 5626 : && aControlA.equal(aNewPolygon.getB2DPoint(aNewPolygon.count() - 1)))
[ + + ][ # # ]
136 : : {
137 : 950 : bControlA = bControlB = false;
138 : : }
139 : :
140 [ + + ]: 4676 : if(bControlA)
141 : : {
142 : : // add bezier edge
143 [ + - ]: 1479 : aNewPolygon.appendBezierSegment(aControlA, aControlB, aNewCoordinatePair);
144 : : }
145 : : else
146 : : {
147 : : // add edge
148 [ + - ]: 3197 : aNewPolygon.append(aNewCoordinatePair);
149 : : }
150 : : }
151 : :
152 : : // next sequence
153 : 448 : pInnerSequence++;
154 : 448 : pInnerSequenceFlags++;
155 : :
156 : : // #i72807# API import uses old line start/end-equal definition for closed,
157 : : // so we need to correct this to closed state here
158 [ + - ]: 448 : basegfx::tools::checkClosed(aNewPolygon);
159 : :
160 : : // add new subpolygon
161 [ + - ]: 448 : aNewPolyPolygon.append(aNewPolygon);
162 [ + - ]: 448 : }
163 : :
164 : 408 : return aNewPolyPolygon;
165 : : }
166 : :
167 : : /////////////////////////////////////////////////////////////////////////////////
168 : :
169 : 692 : void b2DPolyPolygonToPolyPolygonBezier( const basegfx::B2DPolyPolygon& rPolyPoly,
170 : : drawing::PolyPolygonBezierCoords& rRetval )
171 : : {
172 : 692 : rRetval.Coordinates.realloc(rPolyPoly.count());
173 : 692 : rRetval.Flags.realloc(rPolyPoly.count());
174 : :
175 : 692 : drawing::PointSequence* pOuterSequence = rRetval.Coordinates.getArray();
176 : 692 : drawing::FlagSequence* pOuterFlags = rRetval.Flags.getArray();
177 : :
178 [ + + ]: 977 : for(sal_uInt32 a=0;a<rPolyPoly.count();a++)
179 : : {
180 [ + - ]: 285 : const B2DPolygon& rPoly = rPolyPoly.getB2DPolygon(a);
181 [ + - ]: 285 : sal_uInt32 nCount(rPoly.count());
182 [ + - ]: 285 : const bool bClosed(rPoly.isClosed());
183 : :
184 : : // calculate input vertex count
185 [ + + ][ + - ]: 285 : const sal_uInt32 nLoopCount(bClosed ? nCount : (nCount ? nCount - 1L : 0L ));
186 : :
187 [ + - ][ + - ]: 285 : std::vector<awt::Point> aPoints; aPoints.reserve(nLoopCount);
188 [ + - ][ + - ]: 285 : std::vector<drawing::PolygonFlags> aFlags; aFlags.reserve(nLoopCount);
189 : :
190 [ + - ]: 285 : if( nCount )
191 : : {
192 : : // prepare insert index and current point
193 [ + - ]: 285 : basegfx::B2DCubicBezier aBezier;
194 [ + - ]: 285 : aBezier.setStartPoint(rPoly.getB2DPoint(0));
195 : :
196 [ + + ]: 3133 : for(sal_uInt32 b(0L); b<nLoopCount; b++)
197 : : {
198 : : // add current point (always) and remember StartPointIndex for evtl. later corrections
199 : 5696 : const awt::Point aStartPoint(fround(aBezier.getStartPoint().getX()),
200 : 8544 : fround(aBezier.getStartPoint().getY()));
201 : 2848 : const sal_uInt32 nStartPointIndex(aPoints.size());
202 [ + - ]: 2848 : aPoints.push_back(aStartPoint);
203 [ + - ]: 2848 : aFlags.push_back(drawing::PolygonFlags_NORMAL);
204 : :
205 : : // prepare next segment
206 : 2848 : const sal_uInt32 nNextIndex((b + 1) % nCount);
207 [ + - ]: 2848 : aBezier.setEndPoint(rPoly.getB2DPoint(nNextIndex));
208 [ + - ]: 2848 : aBezier.setControlPointA(rPoly.getNextControlPoint(b));
209 [ + - ]: 2848 : aBezier.setControlPointB(rPoly.getPrevControlPoint(nNextIndex));
210 : :
211 [ + + ][ + - ]: 2848 : if(aBezier.isBezier())
212 : : {
213 : : // if one is used, add always two control points due to the old schema
214 : 1966 : aPoints.push_back( awt::Point(fround(aBezier.getControlPointA().getX()),
215 [ + - ]: 2949 : fround(aBezier.getControlPointA().getY())) );
216 [ + - ]: 983 : aFlags.push_back(drawing::PolygonFlags_CONTROL);
217 : :
218 : 1966 : aPoints.push_back( awt::Point(fround(aBezier.getControlPointB().getX()),
219 [ + - ]: 2949 : fround(aBezier.getControlPointB().getY())) );
220 [ + - ]: 983 : aFlags.push_back(drawing::PolygonFlags_CONTROL);
221 : : }
222 : :
223 : : // test continuity with previous control point to set flag value
224 [ + + ][ + + ]: 2848 : if(aBezier.getControlPointA() != aBezier.getStartPoint() && (bClosed || b))
[ + + ][ + - ]
[ + - ][ + + ]
225 : : {
226 [ + - ]: 947 : const basegfx::B2VectorContinuity eCont(rPoly.getContinuityInPoint(b));
227 : :
228 [ + + ]: 947 : if(basegfx::CONTINUITY_C1 == eCont)
229 : : {
230 [ + - ]: 41 : aFlags[nStartPointIndex] = drawing::PolygonFlags_SMOOTH;
231 : : }
232 [ + + ]: 906 : else if(basegfx::CONTINUITY_C2 == eCont)
233 : : {
234 [ + - ]: 264 : aFlags[nStartPointIndex] = drawing::PolygonFlags_SYMMETRIC;
235 : : }
236 : : }
237 : :
238 : : // prepare next polygon step
239 : 2848 : aBezier.setStartPoint(aBezier.getEndPoint());
240 : : }
241 : :
242 [ + + ]: 285 : if(bClosed)
243 : : {
244 : : // add first point again as closing point due to old definition
245 [ + - ]: 251 : aPoints.push_back( aPoints[0] );
246 [ + - ]: 251 : aFlags.push_back(drawing::PolygonFlags_NORMAL);
247 : : }
248 : : else
249 : : {
250 : : // add last point as closing point
251 [ + - ]: 34 : const basegfx::B2DPoint aClosingPoint(rPoly.getB2DPoint(nCount - 1L));
252 : 34 : const awt::Point aEnd(fround(aClosingPoint.getX()),
253 : 68 : fround(aClosingPoint.getY()));
254 [ + - ]: 34 : aPoints.push_back(aEnd);
255 [ + - ]: 34 : aFlags.push_back(drawing::PolygonFlags_NORMAL);
256 [ + - ]: 285 : }
257 : : }
258 : :
259 [ + - ][ + - ]: 285 : *pOuterSequence++ = comphelper::containerToSequence(aPoints);
[ + - ]
260 [ + - ][ + - ]: 285 : *pOuterFlags++ = comphelper::containerToSequence(aFlags);
[ + - ]
261 [ + - ]: 285 : }
262 : 692 : }
263 : :
264 : : }
265 : : }
266 : :
267 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|