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