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 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include <osl/diagnose.h>
30 : : #include <basegfx/polygon/b3dpolygontools.hxx>
31 : : #include <basegfx/polygon/b3dpolygon.hxx>
32 : : #include <basegfx/numeric/ftools.hxx>
33 : : #include <basegfx/range/b3drange.hxx>
34 : : #include <basegfx/point/b2dpoint.hxx>
35 : : #include <basegfx/matrix/b3dhommatrix.hxx>
36 : : #include <basegfx/polygon/b2dpolygon.hxx>
37 : : #include <basegfx/polygon/b2dpolygontools.hxx>
38 : : #include <basegfx/tuple/b3ituple.hxx>
39 : : #include <numeric>
40 : :
41 : : //////////////////////////////////////////////////////////////////////////////
42 : :
43 : : namespace basegfx
44 : : {
45 : : namespace tools
46 : : {
47 : : // B3DPolygon tools
48 : 1501 : void checkClosed(B3DPolygon& rCandidate)
49 : : {
50 [ + - ]: 9006 : while(rCandidate.count() > 1L
[ + - + + ]
[ + + ]
51 [ + - ][ + - ]: 6004 : && rCandidate.getB3DPoint(0L).equal(rCandidate.getB3DPoint(rCandidate.count() - 1L)))
[ + - ][ + - ]
[ + - ]
[ # # # # ]
52 : : {
53 : 1501 : rCandidate.setClosed(true);
54 : 1501 : rCandidate.remove(rCandidate.count() - 1L);
55 : : }
56 : 1501 : }
57 : :
58 : 0 : sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate)
59 : : {
60 : : OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)");
61 : :
62 [ # # ]: 0 : if(nIndex + 1L < rCandidate.count())
63 : : {
64 : 0 : return nIndex + 1L;
65 : : }
66 : : else
67 : : {
68 : 0 : return 0L;
69 : : }
70 : : }
71 : :
72 : 33301 : B3DRange getRange(const B3DPolygon& rCandidate)
73 : : {
74 : 33301 : B3DRange aRetval;
75 : 33301 : const sal_uInt32 nPointCount(rCandidate.count());
76 : :
77 [ + + ]: 160225 : for(sal_uInt32 a(0L); a < nPointCount; a++)
78 : : {
79 [ + - ]: 126924 : const B3DPoint aTestPoint(rCandidate.getB3DPoint(a));
80 [ + - ]: 126924 : aRetval.expand(aTestPoint);
81 : 126924 : }
82 : :
83 : 33301 : return aRetval;
84 : : }
85 : :
86 : 438 : B3DVector getNormal(const B3DPolygon& rCandidate)
87 : : {
88 : 438 : return rCandidate.getNormal();
89 : : }
90 : :
91 : 0 : double getLength(const B3DPolygon& rCandidate)
92 : : {
93 : 0 : double fRetval(0.0);
94 : 0 : const sal_uInt32 nPointCount(rCandidate.count());
95 : :
96 [ # # ]: 0 : if(nPointCount > 1L)
97 : : {
98 [ # # ]: 0 : const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
99 : :
100 [ # # ]: 0 : for(sal_uInt32 a(0L); a < nLoopCount; a++)
101 : : {
102 [ # # ]: 0 : const sal_uInt32 nNextIndex(getIndexOfSuccessor(a, rCandidate));
103 [ # # ]: 0 : const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a));
104 [ # # ]: 0 : const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
105 : 0 : const B3DVector aVector(aNextPoint - aCurrentPoint);
106 [ # # ]: 0 : fRetval += aVector.getLength();
107 : 0 : }
108 : : }
109 : :
110 : 0 : return fRetval;
111 : : }
112 : :
113 : 0 : void applyLineDashing(const B3DPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B3DPolyPolygon* pLineTarget, B3DPolyPolygon* pGapTarget, double fDotDashLength)
114 : : {
115 : 0 : const sal_uInt32 nPointCount(rCandidate.count());
116 : 0 : const sal_uInt32 nDotDashCount(rDotDashArray.size());
117 : :
118 [ # # ]: 0 : if(fTools::lessOrEqual(fDotDashLength, 0.0))
119 : : {
120 : 0 : fDotDashLength = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
121 : : }
122 : :
123 [ # # ][ # # ]: 0 : if(fTools::more(fDotDashLength, 0.0) && (pLineTarget || pGapTarget) && nPointCount)
[ # # ][ # # ]
[ # # ][ # # ]
124 : : {
125 : : // clear targets
126 [ # # ]: 0 : if(pLineTarget)
127 : : {
128 [ # # ]: 0 : pLineTarget->clear();
129 : : }
130 : :
131 [ # # ]: 0 : if(pGapTarget)
132 : : {
133 [ # # ]: 0 : pGapTarget->clear();
134 : : }
135 : :
136 : : // prepare current edge's start
137 [ # # ]: 0 : B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
138 [ # # ][ # # ]: 0 : const sal_uInt32 nEdgeCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
139 : :
140 : : // prepare DotDashArray iteration and the line/gap switching bool
141 : 0 : sal_uInt32 nDotDashIndex(0);
142 : 0 : bool bIsLine(true);
143 [ # # ]: 0 : double fDotDashMovingLength(rDotDashArray[0]);
144 [ # # ]: 0 : B3DPolygon aSnippet;
145 : :
146 : : // iterate over all edges
147 [ # # ]: 0 : for(sal_uInt32 a(0); a < nEdgeCount; a++)
148 : : {
149 : : // update current edge
150 : 0 : double fLastDotDashMovingLength(0.0);
151 : 0 : const sal_uInt32 nNextIndex((a + 1) % nPointCount);
152 [ # # ]: 0 : const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
153 [ # # ]: 0 : const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength());
154 : :
155 [ # # ]: 0 : while(fTools::less(fDotDashMovingLength, fEdgeLength))
156 : : {
157 : : // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
158 [ # # ][ # # ]: 0 : const bool bHandleLine(bIsLine && pLineTarget);
159 [ # # ][ # # ]: 0 : const bool bHandleGap(!bIsLine && pGapTarget);
160 : :
161 [ # # ][ # # ]: 0 : if(bHandleLine || bHandleGap)
162 : : {
163 [ # # ][ # # ]: 0 : if(!aSnippet.count())
164 : : {
165 [ # # ]: 0 : aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
166 : : }
167 : :
168 [ # # ]: 0 : aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));
169 : :
170 [ # # ]: 0 : if(bHandleLine)
171 : : {
172 [ # # ]: 0 : pLineTarget->append(aSnippet);
173 : : }
174 : : else
175 : : {
176 [ # # ]: 0 : pGapTarget->append(aSnippet);
177 : : }
178 : :
179 [ # # ]: 0 : aSnippet.clear();
180 : : }
181 : :
182 : : // prepare next DotDashArray step and flip line/gap flag
183 : 0 : fLastDotDashMovingLength = fDotDashMovingLength;
184 [ # # ]: 0 : fDotDashMovingLength += rDotDashArray[(++nDotDashIndex) % nDotDashCount];
185 : 0 : bIsLine = !bIsLine;
186 : : }
187 : :
188 : : // append snippet [fLastDotDashMovingLength, fEdgeLength]
189 [ # # ][ # # ]: 0 : const bool bHandleLine(bIsLine && pLineTarget);
190 [ # # ][ # # ]: 0 : const bool bHandleGap(!bIsLine && pGapTarget);
191 : :
192 [ # # ][ # # ]: 0 : if(bHandleLine || bHandleGap)
193 : : {
194 [ # # ][ # # ]: 0 : if(!aSnippet.count())
195 : : {
196 [ # # ]: 0 : aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
197 : : }
198 : :
199 [ # # ]: 0 : aSnippet.append(aNextPoint);
200 : : }
201 : :
202 : : // prepare move to next edge
203 : 0 : fDotDashMovingLength -= fEdgeLength;
204 : :
205 : : // prepare next edge step (end point gets new start point)
206 [ # # ]: 0 : aCurrentPoint = aNextPoint;
207 : 0 : }
208 : :
209 : : // append last intermediate results (if exists)
210 [ # # ][ # # ]: 0 : if(aSnippet.count())
211 : : {
212 [ # # ][ # # ]: 0 : if(bIsLine && pLineTarget)
213 : : {
214 [ # # ]: 0 : pLineTarget->append(aSnippet);
215 : : }
216 [ # # ][ # # ]: 0 : else if(!bIsLine && pGapTarget)
217 : : {
218 [ # # ]: 0 : pGapTarget->append(aSnippet);
219 : : }
220 : : }
221 : :
222 : : // check if start and end polygon may be merged
223 [ # # ]: 0 : if(pLineTarget)
224 : : {
225 [ # # ]: 0 : const sal_uInt32 nCount(pLineTarget->count());
226 : :
227 [ # # ]: 0 : if(nCount > 1)
228 : : {
229 : : // these polygons were created above, there exists none with less than two points,
230 : : // thus dircet point access below is allowed
231 [ # # ]: 0 : const B3DPolygon aFirst(pLineTarget->getB3DPolygon(0));
232 [ # # ]: 0 : B3DPolygon aLast(pLineTarget->getB3DPolygon(nCount - 1));
233 : :
234 [ # # ][ # # ]: 0 : if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1)))
[ # # ][ # # ]
235 : : {
236 : : // start of first and end of last are the same -> merge them
237 [ # # ]: 0 : aLast.append(aFirst);
238 [ # # ]: 0 : aLast.removeDoublePoints();
239 [ # # ]: 0 : pLineTarget->setB3DPolygon(0, aLast);
240 [ # # ]: 0 : pLineTarget->remove(nCount - 1);
241 [ # # ][ # # ]: 0 : }
242 : : }
243 : : }
244 : :
245 [ # # ]: 0 : if(pGapTarget)
246 : : {
247 [ # # ]: 0 : const sal_uInt32 nCount(pGapTarget->count());
248 : :
249 [ # # ]: 0 : if(nCount > 1)
250 : : {
251 : : // these polygons were created above, there exists none with less than two points,
252 : : // thus dircet point access below is allowed
253 [ # # ]: 0 : const B3DPolygon aFirst(pGapTarget->getB3DPolygon(0));
254 [ # # ]: 0 : B3DPolygon aLast(pGapTarget->getB3DPolygon(nCount - 1));
255 : :
256 [ # # ][ # # ]: 0 : if(aFirst.getB3DPoint(0).equal(aLast.getB3DPoint(aLast.count() - 1)))
[ # # ][ # # ]
257 : : {
258 : : // start of first and end of last are the same -> merge them
259 [ # # ]: 0 : aLast.append(aFirst);
260 [ # # ]: 0 : aLast.removeDoublePoints();
261 [ # # ]: 0 : pGapTarget->setB3DPolygon(0, aLast);
262 [ # # ]: 0 : pGapTarget->remove(nCount - 1);
263 [ # # ][ # # ]: 0 : }
264 : : }
265 [ # # ]: 0 : }
266 : : }
267 : : else
268 : : {
269 : : // parameters make no sense, just add source to targets
270 [ # # ]: 0 : if(pLineTarget)
271 : : {
272 : 0 : pLineTarget->append(rCandidate);
273 : : }
274 : :
275 [ # # ]: 0 : if(pGapTarget)
276 : : {
277 : 0 : pGapTarget->append(rCandidate);
278 : : }
279 : : }
280 : 0 : }
281 : :
282 : 0 : B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter)
283 : : {
284 : 0 : B3DPolygon aRetval(rCandidate);
285 : :
286 [ # # ][ # # ]: 0 : for(sal_uInt32 a(0L); a < aRetval.count(); a++)
287 : : {
288 [ # # ]: 0 : B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
289 [ # # ]: 0 : aVector.normalize();
290 [ # # ]: 0 : aRetval.setNormal(a, aVector);
291 : 0 : }
292 : :
293 : 0 : return aRetval;
294 : : }
295 : :
296 : 0 : B3DPolygon invertNormals( const B3DPolygon& rCandidate)
297 : : {
298 : 0 : B3DPolygon aRetval(rCandidate);
299 : :
300 [ # # ][ # # ]: 0 : if(aRetval.areNormalsUsed())
301 : : {
302 [ # # ][ # # ]: 0 : for(sal_uInt32 a(0L); a < aRetval.count(); a++)
303 : : {
304 [ # # ][ # # ]: 0 : aRetval.setNormal(a, -aRetval.getNormal(a));
305 : : }
306 : : }
307 : :
308 : 0 : return aRetval;
309 : : }
310 : :
311 : 144 : B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
312 : : {
313 : 144 : B3DPolygon aRetval(rCandidate);
314 : :
315 [ # # ][ - + ]: 144 : if(bChangeX || bChangeY)
316 : : {
317 : : // create projection of standard texture coordinates in (X, Y) onto
318 : : // the 3d coordinates straight
319 [ + - ]: 144 : const double fWidth(rRange.getWidth());
320 [ + - ]: 144 : const double fHeight(rRange.getHeight());
321 : 144 : const bool bWidthSet(!fTools::equalZero(fWidth));
322 : 144 : const bool bHeightSet(!fTools::equalZero(fHeight));
323 : 144 : const double fOne(1.0);
324 : :
325 [ + - ][ + + ]: 720 : for(sal_uInt32 a(0L); a < aRetval.count(); a++)
326 : : {
327 [ + - ]: 576 : const B3DPoint aPoint(aRetval.getB3DPoint(a));
328 [ + - ]: 576 : B2DPoint aTextureCoordinate(aRetval.getTextureCoordinate(a));
329 : :
330 [ + - ]: 576 : if(bChangeX)
331 : : {
332 [ + - ]: 576 : if(bWidthSet)
333 : : {
334 [ + - ]: 576 : aTextureCoordinate.setX((aPoint.getX() - rRange.getMinX()) / fWidth);
335 : : }
336 : : else
337 : : {
338 : 0 : aTextureCoordinate.setX(0.0);
339 : : }
340 : : }
341 : :
342 [ + - ]: 576 : if(bChangeY)
343 : : {
344 [ + - ]: 576 : if(bHeightSet)
345 : : {
346 [ + - ]: 576 : aTextureCoordinate.setY(fOne - ((aPoint.getY() - rRange.getMinY()) / fHeight));
347 : : }
348 : : else
349 : : {
350 : 0 : aTextureCoordinate.setY(fOne);
351 : : }
352 : : }
353 : :
354 [ + - ]: 576 : aRetval.setTextureCoordinate(a, aTextureCoordinate);
355 : 576 : }
356 : : }
357 : :
358 : 144 : return aRetval;
359 : : }
360 : :
361 : 0 : B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
362 : : {
363 : 0 : B3DPolygon aRetval(rCandidate);
364 : :
365 [ # # ][ # # ]: 0 : if(bChangeX || bChangeY)
366 : : {
367 : : // create texture coordinates using sphere projection to cartesian coordinates,
368 : : // use object's center as base
369 : 0 : const double fOne(1.0);
370 [ # # ]: 0 : const sal_uInt32 nPointCount(aRetval.count());
371 : 0 : bool bPolarPoints(false);
372 : : sal_uInt32 a;
373 : :
374 : : // create center cartesian coordinates to have a possibility to decide if on boundary
375 : : // transitions which value to choose
376 [ # # ]: 0 : const B3DRange aPlaneRange(getRange(rCandidate));
377 [ # # ]: 0 : const B3DPoint aPlaneCenter(aPlaneRange.getCenter() - rCenter);
378 : 0 : const double fXCenter(fOne - ((atan2(aPlaneCenter.getZ(), aPlaneCenter.getX()) + F_PI) / F_2PI));
379 : :
380 [ # # ]: 0 : for(a = 0L; a < nPointCount; a++)
381 : : {
382 [ # # ]: 0 : const B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
383 : 0 : const double fY(fOne - ((atan2(aVector.getY(), aVector.getXZLength()) + F_PI2) / F_PI));
384 [ # # ]: 0 : B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));
385 : :
386 [ # # ]: 0 : if(fTools::equalZero(fY))
387 : : {
388 : : // point is a north polar point, no useful X-coordinate can be created.
389 [ # # ]: 0 : if(bChangeY)
390 : : {
391 : 0 : aTexCoor.setY(0.0);
392 : :
393 [ # # ]: 0 : if(bChangeX)
394 : : {
395 : 0 : bPolarPoints = true;
396 : : }
397 : : }
398 : : }
399 [ # # ]: 0 : else if(fTools::equal(fY, fOne))
400 : : {
401 : : // point is a south polar point, no useful X-coordinate can be created. Set
402 : : // Y-coordinte, though
403 [ # # ]: 0 : if(bChangeY)
404 : : {
405 : 0 : aTexCoor.setY(fOne);
406 : :
407 [ # # ]: 0 : if(bChangeX)
408 : : {
409 : 0 : bPolarPoints = true;
410 : : }
411 : : }
412 : : }
413 : : else
414 : : {
415 : 0 : double fX(fOne - ((atan2(aVector.getZ(), aVector.getX()) + F_PI) / F_2PI));
416 : :
417 : : // correct cartesinan point coordiante dependent from center value
418 [ # # ]: 0 : if(fX > fXCenter + 0.5)
419 : : {
420 : 0 : fX -= fOne;
421 : : }
422 [ # # ]: 0 : else if(fX < fXCenter - 0.5)
423 : : {
424 : 0 : fX += fOne;
425 : : }
426 : :
427 [ # # ]: 0 : if(bChangeX)
428 : : {
429 : 0 : aTexCoor.setX(fX);
430 : : }
431 : :
432 [ # # ]: 0 : if(bChangeY)
433 : : {
434 : 0 : aTexCoor.setY(fY);
435 : : }
436 : : }
437 : :
438 [ # # ]: 0 : aRetval.setTextureCoordinate(a, aTexCoor);
439 : 0 : }
440 : :
441 [ # # ]: 0 : if(bPolarPoints)
442 : : {
443 : : // correct X-texture coordinates if polar points are contained. Those
444 : : // coordinates cannot be correct, so use prev or next X-coordinate
445 [ # # ]: 0 : for(a = 0L; a < nPointCount; a++)
446 : : {
447 [ # # ]: 0 : B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));
448 : :
449 [ # # ][ # # ]: 0 : if(fTools::equalZero(aTexCoor.getY()) || fTools::equal(aTexCoor.getY(), fOne))
[ # # ][ # # ]
[ # # ]
450 : : {
451 : : // get prev, next TexCoor and test for pole
452 [ # # ][ # # ]: 0 : const B2DPoint aPrevTexCoor(aRetval.getTextureCoordinate(a ? a - 1L : nPointCount - 1L));
453 [ # # ]: 0 : const B2DPoint aNextTexCoor(aRetval.getTextureCoordinate((a + 1L) % nPointCount));
454 [ # # ][ # # ]: 0 : const bool bPrevPole(fTools::equalZero(aPrevTexCoor.getY()) || fTools::equal(aPrevTexCoor.getY(), fOne));
[ # # ][ # # ]
455 [ # # ][ # # ]: 0 : const bool bNextPole(fTools::equalZero(aNextTexCoor.getY()) || fTools::equal(aNextTexCoor.getY(), fOne));
[ # # ][ # # ]
456 : :
457 [ # # ][ # # ]: 0 : if(!bPrevPole && !bNextPole)
458 : : {
459 : : // both no poles, mix them
460 : 0 : aTexCoor.setX((aPrevTexCoor.getX() + aNextTexCoor.getX()) / 2.0);
461 : : }
462 [ # # ]: 0 : else if(!bNextPole)
463 : : {
464 : : // copy next
465 : 0 : aTexCoor.setX(aNextTexCoor.getX());
466 : : }
467 : : else
468 : : {
469 : : // copy prev, even if it's a pole, hopefully it is already corrected
470 : 0 : aTexCoor.setX(aPrevTexCoor.getX());
471 : : }
472 : :
473 [ # # ]: 0 : aRetval.setTextureCoordinate(a, aTexCoor);
474 : : }
475 : 0 : }
476 : 0 : }
477 : : }
478 : :
479 : 0 : return aRetval;
480 : : }
481 : :
482 : 0 : bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder)
483 : : {
484 [ # # ][ # # ]: 0 : if(bWithBorder && isPointOnPolygon(rCandidate, rPoint, true))
[ # # ]
485 : : {
486 : 0 : return true;
487 : : }
488 : : else
489 : : {
490 : 0 : bool bRetval(false);
491 [ # # ]: 0 : const B3DVector aPlaneNormal(rCandidate.getNormal());
492 : :
493 [ # # ][ # # ]: 0 : if(!aPlaneNormal.equalZero())
494 : : {
495 [ # # ]: 0 : const sal_uInt32 nPointCount(rCandidate.count());
496 : :
497 [ # # ]: 0 : if(nPointCount)
498 : : {
499 [ # # ]: 0 : B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nPointCount - 1));
500 : 0 : const double fAbsX(fabs(aPlaneNormal.getX()));
501 : 0 : const double fAbsY(fabs(aPlaneNormal.getY()));
502 : 0 : const double fAbsZ(fabs(aPlaneNormal.getZ()));
503 : :
504 [ # # ][ # # ]: 0 : if(fAbsX > fAbsY && fAbsX > fAbsZ)
505 : : {
506 : : // normal points mostly in X-Direction, use YZ-Polygon projection for check
507 : : // x -> y, y -> z
508 [ # # ]: 0 : for(sal_uInt32 a(0); a < nPointCount; a++)
509 : : {
510 : 0 : const B3DPoint aPreviousPoint(aCurrentPoint);
511 [ # # ][ # # ]: 0 : aCurrentPoint = rCandidate.getB3DPoint(a);
512 : :
513 : : // cross-over in Z?
514 : 0 : const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
515 : 0 : const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
516 : :
517 [ # # ]: 0 : if(bCompZA != bCompZB)
518 : : {
519 : : // cross-over in Y?
520 : 0 : const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
521 : 0 : const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
522 : :
523 [ # # ]: 0 : if(bCompYA == bCompYB)
524 : : {
525 [ # # ]: 0 : if(bCompYA)
526 : : {
527 : 0 : bRetval = !bRetval;
528 : : }
529 : : }
530 : : else
531 : : {
532 : : const double fCompare(
533 : 0 : aCurrentPoint.getY() - (aCurrentPoint.getZ() - rPoint.getZ()) *
534 : 0 : (aPreviousPoint.getY() - aCurrentPoint.getY()) /
535 : 0 : (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
536 : :
537 [ # # ]: 0 : if(fTools::more(fCompare, rPoint.getY()))
538 : : {
539 : 0 : bRetval = !bRetval;
540 : : }
541 : : }
542 : : }
543 : 0 : }
544 : : }
545 [ # # ][ # # ]: 0 : else if(fAbsY > fAbsX && fAbsY > fAbsZ)
546 : : {
547 : : // normal points mostly in Y-Direction, use XZ-Polygon projection for check
548 : : // x -> x, y -> z
549 [ # # ]: 0 : for(sal_uInt32 a(0); a < nPointCount; a++)
550 : : {
551 : 0 : const B3DPoint aPreviousPoint(aCurrentPoint);
552 [ # # ][ # # ]: 0 : aCurrentPoint = rCandidate.getB3DPoint(a);
553 : :
554 : : // cross-over in Z?
555 : 0 : const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
556 : 0 : const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
557 : :
558 [ # # ]: 0 : if(bCompZA != bCompZB)
559 : : {
560 : : // cross-over in X?
561 : 0 : const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
562 : 0 : const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
563 : :
564 [ # # ]: 0 : if(bCompXA == bCompXB)
565 : : {
566 [ # # ]: 0 : if(bCompXA)
567 : : {
568 : 0 : bRetval = !bRetval;
569 : : }
570 : : }
571 : : else
572 : : {
573 : : const double fCompare(
574 : 0 : aCurrentPoint.getX() - (aCurrentPoint.getZ() - rPoint.getZ()) *
575 : 0 : (aPreviousPoint.getX() - aCurrentPoint.getX()) /
576 : 0 : (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
577 : :
578 [ # # ]: 0 : if(fTools::more(fCompare, rPoint.getX()))
579 : : {
580 : 0 : bRetval = !bRetval;
581 : : }
582 : : }
583 : : }
584 : 0 : }
585 : : }
586 : : else
587 : : {
588 : : // normal points mostly in Z-Direction, use XY-Polygon projection for check
589 : : // x -> x, y -> y
590 [ # # ]: 0 : for(sal_uInt32 a(0); a < nPointCount; a++)
591 : : {
592 : 0 : const B3DPoint aPreviousPoint(aCurrentPoint);
593 [ # # ][ # # ]: 0 : aCurrentPoint = rCandidate.getB3DPoint(a);
594 : :
595 : : // cross-over in Y?
596 : 0 : const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
597 : 0 : const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
598 : :
599 [ # # ]: 0 : if(bCompYA != bCompYB)
600 : : {
601 : : // cross-over in X?
602 : 0 : const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
603 : 0 : const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
604 : :
605 [ # # ]: 0 : if(bCompXA == bCompXB)
606 : : {
607 [ # # ]: 0 : if(bCompXA)
608 : : {
609 : 0 : bRetval = !bRetval;
610 : : }
611 : : }
612 : : else
613 : : {
614 : : const double fCompare(
615 : 0 : aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) *
616 : 0 : (aPreviousPoint.getX() - aCurrentPoint.getX()) /
617 : 0 : (aPreviousPoint.getY() - aCurrentPoint.getY()));
618 : :
619 [ # # ]: 0 : if(fTools::more(fCompare, rPoint.getX()))
620 : : {
621 : 0 : bRetval = !bRetval;
622 : : }
623 : : }
624 : : }
625 : 0 : }
626 : 0 : }
627 : : }
628 : : }
629 : :
630 : 0 : return bRetval;
631 : : }
632 : : }
633 : :
634 : 0 : bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint& rCandidate, bool bWithPoints)
635 : : {
636 [ # # ][ # # ]: 0 : if(rCandidate.equal(rStart) || rCandidate.equal(rEnd))
[ # # ]
637 : : {
638 : : // candidate is in epsilon around start or end -> inside
639 : 0 : return bWithPoints;
640 : : }
641 [ # # ]: 0 : else if(rStart.equal(rEnd))
642 : : {
643 : : // start and end are equal, but candidate is outside their epsilon -> outside
644 : 0 : return false;
645 : : }
646 : : else
647 : : {
648 : 0 : const B3DVector aEdgeVector(rEnd - rStart);
649 : 0 : const B3DVector aTestVector(rCandidate - rStart);
650 : :
651 [ # # ][ # # ]: 0 : if(areParallel(aEdgeVector, aTestVector))
652 : : {
653 : 0 : const double fZero(0.0);
654 : 0 : const double fOne(1.0);
655 : 0 : double fParamTestOnCurr(0.0);
656 : :
657 [ # # ]: 0 : if(aEdgeVector.getX() > aEdgeVector.getY())
658 : : {
659 [ # # ]: 0 : if(aEdgeVector.getX() > aEdgeVector.getZ())
660 : : {
661 : : // X is biggest
662 : 0 : fParamTestOnCurr = aTestVector.getX() / aEdgeVector.getX();
663 : : }
664 : : else
665 : : {
666 : : // Z is biggest
667 : 0 : fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
668 : : }
669 : : }
670 : : else
671 : : {
672 [ # # ]: 0 : if(aEdgeVector.getY() > aEdgeVector.getZ())
673 : : {
674 : : // Y is biggest
675 : 0 : fParamTestOnCurr = aTestVector.getY() / aEdgeVector.getY();
676 : : }
677 : : else
678 : : {
679 : : // Z is biggest
680 : 0 : fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
681 : : }
682 : : }
683 : :
684 [ # # ][ # # ]: 0 : if(fTools::more(fParamTestOnCurr, fZero) && fTools::less(fParamTestOnCurr, fOne))
[ # # ]
685 : : {
686 : 0 : return true;
687 : : }
688 : : }
689 : :
690 : 0 : return false;
691 : : }
692 : : }
693 : :
694 : 0 : bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithPoints)
695 : : {
696 : 0 : const sal_uInt32 nPointCount(rCandidate.count());
697 : :
698 [ # # ]: 0 : if(nPointCount > 1L)
699 : : {
700 [ # # ][ # # ]: 0 : const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1L);
701 [ # # ]: 0 : B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
702 : :
703 [ # # ]: 0 : for(sal_uInt32 a(0); a < nLoopCount; a++)
704 : : {
705 [ # # ]: 0 : const B3DPoint aNextPoint(rCandidate.getB3DPoint((a + 1) % nPointCount));
706 : :
707 [ # # ][ # # ]: 0 : if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, bWithPoints))
708 : : {
709 : 0 : return true;
710 : : }
711 : :
712 [ # # ][ # # ]: 0 : aCurrentPoint = aNextPoint;
713 [ # # ]: 0 : }
714 : : }
715 [ # # ][ # # ]: 0 : else if(nPointCount && bWithPoints)
716 : : {
717 : 0 : return rPoint.equal(rCandidate.getB3DPoint(0));
718 : : }
719 : :
720 : 0 : return false;
721 : : }
722 : :
723 : 0 : bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut)
724 : : {
725 [ # # ][ # # ]: 0 : if(!rPlaneNormal.equalZero() && !rEdgeStart.equal(rEdgeEnd))
[ # # ]
726 : : {
727 : 0 : const B3DVector aTestEdge(rEdgeEnd - rEdgeStart);
728 : 0 : const double fScalarEdge(rPlaneNormal.scalar(aTestEdge));
729 : :
730 [ # # ]: 0 : if(!fTools::equalZero(fScalarEdge))
731 : : {
732 : 0 : const B3DVector aCompareEdge(rPlanePoint - rEdgeStart);
733 : 0 : const double fScalarCompare(rPlaneNormal.scalar(aCompareEdge));
734 : :
735 : 0 : fCut = fScalarCompare / fScalarEdge;
736 : 0 : return true;
737 [ # # ]: 0 : }
738 : : }
739 : :
740 : 0 : return false;
741 : : }
742 : :
743 : : // snap points of horizontal or vertical edges to discrete values
744 : 0 : B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate)
745 : : {
746 : 0 : const sal_uInt32 nPointCount(rCandidate.count());
747 : :
748 [ # # ]: 0 : if(nPointCount > 1)
749 : : {
750 : : // Start by copying the source polygon to get a writeable copy. The closed state is
751 : : // copied by aRetval's initialisation, too, so no need to copy it in this method
752 [ # # ]: 0 : B3DPolygon aRetval(rCandidate);
753 : :
754 : : // prepare geometry data. Get rounded from original
755 [ # # ][ # # ]: 0 : B3ITuple aPrevTuple(basegfx::fround(rCandidate.getB3DPoint(nPointCount - 1)));
756 [ # # ]: 0 : B3DPoint aCurrPoint(rCandidate.getB3DPoint(0));
757 [ # # ]: 0 : B3ITuple aCurrTuple(basegfx::fround(aCurrPoint));
758 : :
759 : : // loop over all points. This will also snap the implicit closing edge
760 : : // even when not closed, but that's no problem here
761 [ # # ]: 0 : for(sal_uInt32 a(0); a < nPointCount; a++)
762 : : {
763 : : // get next point. Get rounded from original
764 : 0 : const bool bLastRun(a + 1 == nPointCount);
765 [ # # ]: 0 : const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1);
766 [ # # ]: 0 : const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
767 [ # # ]: 0 : const B3ITuple aNextTuple(basegfx::fround(aNextPoint));
768 : :
769 : : // get the states
770 : 0 : const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
771 : 0 : const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
772 : 0 : const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
773 : 0 : const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
774 [ # # ][ # # ]: 0 : const bool bSnapX(bPrevVertical || bNextVertical);
775 [ # # ][ # # ]: 0 : const bool bSnapY(bPrevHorizontal || bNextHorizontal);
776 : :
777 [ # # ][ # # ]: 0 : if(bSnapX || bSnapY)
778 : : {
779 : : const B3DPoint aSnappedPoint(
780 : 0 : bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
781 : 0 : bSnapY ? aCurrTuple.getY() : aCurrPoint.getY(),
782 [ # # ][ # # ]: 0 : aCurrPoint.getZ());
783 : :
784 [ # # ]: 0 : aRetval.setB3DPoint(a, aSnappedPoint);
785 : : }
786 : :
787 : : // prepare next point
788 [ # # ]: 0 : if(!bLastRun)
789 : : {
790 : 0 : aPrevTuple = aCurrTuple;
791 [ # # ]: 0 : aCurrPoint = aNextPoint;
792 : 0 : aCurrTuple = aNextTuple;
793 : : }
794 : 0 : }
795 : :
796 [ # # ][ # # ]: 0 : return aRetval;
797 : : }
798 : : else
799 : : {
800 : 0 : return rCandidate;
801 : : }
802 : : }
803 : :
804 : : } // end of namespace tools
805 : : } // end of namespace basegfx
806 : :
807 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|