Bug Summary

File:home/maarten/src/libreoffice/core/basegfx/source/polygon/b3dpolygontools.cxx
Warning:line 222, column 17
Value stored to 'fDotDashLength' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name b3dpolygontools.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D BASEGFX_DLLIMPLEMENTATION -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/basegfx/source/inc -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/basegfx/source/polygon/b3dpolygontools.cxx
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/polygon/b3dpolypolygon.hxx>
24#include <basegfx/numeric/ftools.hxx>
25#include <basegfx/range/b3drange.hxx>
26#include <basegfx/point/b2dpoint.hxx>
27#include <basegfx/tuple/b3ituple.hxx>
28#include <rtl/math.hxx>
29#include <numeric>
30
31namespace basegfx::utils
32{
33 // B3DPolygon tools
34 void checkClosed(B3DPolygon& rCandidate)
35 {
36 while(rCandidate.count() > 1
37 && rCandidate.getB3DPoint(0).equal(rCandidate.getB3DPoint(rCandidate.count() - 1)))
38 {
39 rCandidate.setClosed(true);
40 rCandidate.remove(rCandidate.count() - 1);
41 }
42 }
43
44 sal_uInt32 getIndexOfSuccessor(sal_uInt32 nIndex, const B3DPolygon& rCandidate)
45 {
46 OSL_ENSURE(nIndex < rCandidate.count(), "getIndexOfPredecessor: Access to polygon out of range (!)")do { if (true && (!(nIndex < rCandidate.count())))
{ sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"
), ("/home/maarten/src/libreoffice/core/basegfx/source/polygon/b3dpolygontools.cxx"
":" "46" ": "), "%s", "getIndexOfPredecessor: Access to polygon out of range (!)"
); } } while (false)
;
47
48 if(nIndex + 1 < rCandidate.count())
49 {
50 return nIndex + 1;
51 }
52 else
53 {
54 return 0;
55 }
56 }
57
58 B3DRange getRange(const B3DPolygon& rCandidate)
59 {
60 B3DRange aRetval;
61 const sal_uInt32 nPointCount(rCandidate.count());
62
63 for(sal_uInt32 a(0); a < nPointCount; a++)
64 {
65 const B3DPoint aTestPoint(rCandidate.getB3DPoint(a));
66 aRetval.expand(aTestPoint);
67 }
68
69 return aRetval;
70 }
71
72 double getLength(const B3DPolygon& rCandidate)
73 {
74 double fRetval(0.0);
75 const sal_uInt32 nPointCount(rCandidate.count());
76
77 if(nPointCount > 1)
78 {
79 const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
80
81 for(sal_uInt32 a(0); a < nLoopCount; a++)
82 {
83 const sal_uInt32 nNextIndex(getIndexOfSuccessor(a, rCandidate));
84 const B3DPoint aCurrentPoint(rCandidate.getB3DPoint(a));
85 const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
86 const B3DVector aVector(aNextPoint - aCurrentPoint);
87 fRetval += aVector.getLength();
88 }
89 }
90
91 return fRetval;
92 }
93
94 void applyLineDashing(
95 const B3DPolygon& rCandidate,
96 const std::vector<double>& rDotDashArray,
97 B3DPolyPolygon* pLineTarget,
98 double fDotDashLength)
99 {
100 // clear targets in any case
101 if(pLineTarget)
102 {
103 pLineTarget->clear();
104 }
105
106 // provide callback as lambda
107 auto aLineCallback(
108 nullptr == pLineTarget
109 ? std::function<void(const basegfx::B3DPolygon&)>()
110 : [&pLineTarget](const basegfx::B3DPolygon& rSnippet){ pLineTarget->append(rSnippet); });
111
112 // call version that uses callbacks
113 applyLineDashing(
114 rCandidate,
115 rDotDashArray,
116 aLineCallback,
117 fDotDashLength);
118 }
119
120 static void implHandleSnippet(
121 const B3DPolygon& rSnippet,
122 const std::function<void(const basegfx::B3DPolygon& rSnippet)>& rTargetCallback,
123 B3DPolygon& rFirst,
124 B3DPolygon& rLast)
125 {
126 if(rSnippet.isClosed())
127 {
128 if(!rFirst.count())
129 {
130 rFirst = rSnippet;
131 }
132 else
133 {
134 if(rLast.count())
135 {
136 rTargetCallback(rLast);
137 }
138
139 rLast = rSnippet;
140 }
141 }
142 else
143 {
144 rTargetCallback(rSnippet);
145 }
146 }
147
148 static void implHandleFirstLast(
149 const std::function<void(const basegfx::B3DPolygon& rSnippet)>& rTargetCallback,
150 B3DPolygon& rFirst,
151 B3DPolygon& rLast)
152 {
153 if(rFirst.count() && rLast.count()
154 && rFirst.getB3DPoint(0).equal(rLast.getB3DPoint(rLast.count() - 1)))
155 {
156 // start of first and end of last are the same -> merge them
157 rLast.append(rFirst);
158 rLast.removeDoublePoints();
159 rFirst.clear();
160 }
161
162 if(rLast.count())
163 {
164 rTargetCallback(rLast);
165 }
166
167 if(rFirst.count())
168 {
169 rTargetCallback(rFirst);
170 }
171 }
172
173 void applyLineDashing(
174 const B3DPolygon& rCandidate,
175 const std::vector<double>& rDotDashArray,
176 std::function<void(const basegfx::B3DPolygon& rSnippet)> aLineTargetCallback,
177 double fDotDashLength)
178 {
179 const sal_uInt32 nPointCount(rCandidate.count());
180 const sal_uInt32 nDotDashCount(rDotDashArray.size());
181
182 if(fTools::lessOrEqual(fDotDashLength, 0.0))
183 {
184 fDotDashLength = std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
185 }
186
187 if(fTools::lessOrEqual(fDotDashLength, 0.0) || !aLineTargetCallback || !nPointCount)
188 {
189 // parameters make no sense, just add source to targets
190 if(aLineTargetCallback)
191 {
192 aLineTargetCallback(rCandidate);
193 }
194
195 return;
196 }
197
198 // precalculate maximal acceptable length of candidate polygon assuming
199 // we want to create a maximum of fNumberOfAllowedSnippets. In 3D
200 // use less for fNumberOfAllowedSnippets, ca. 6553.6, double due to line & gap.
201 // Less in 3D due to potentially blowing up to rounded line segments.
202 static double fNumberOfAllowedSnippets(6553.5 * 2.0);
203 const double fAllowedLength((fNumberOfAllowedSnippets * fDotDashLength) / double(rDotDashArray.size()));
204 const double fCandidateLength(basegfx::utils::getLength(rCandidate));
205 std::vector<double> aDotDashArray(rDotDashArray);
206
207 if(fCandidateLength > fAllowedLength)
208 {
209 // we would produce more than fNumberOfAllowedSnippets, so
210 // adapt aDotDashArray to exactly produce assumed number. Also
211 // assert this to let the caller know about it.
212 // If this asserts: Please think about checking your DotDashArray
213 // before calling this function or evtl. use the callback version
214 // to *not* produce that much of data. Even then, you may still
215 // think about producing too much runtime (!)
216 assert(true && "applyLineDashing: potentially too expensive to do the requested dismantle - please consider stretched LineDash pattern (!)")(static_cast <bool> (true && "applyLineDashing: potentially too expensive to do the requested dismantle - please consider stretched LineDash pattern (!)"
) ? void (0) : __assert_fail ("true && \"applyLineDashing: potentially too expensive to do the requested dismantle - please consider stretched LineDash pattern (!)\""
, "/home/maarten/src/libreoffice/core/basegfx/source/polygon/b3dpolygontools.cxx"
, 216, __extension__ __PRETTY_FUNCTION__))
;
217
218 // calculate correcting factor, apply to aDotDashArray and fDotDashLength
219 // to enlarge these as needed
220 const double fFactor(fCandidateLength / fAllowedLength);
221 std::for_each(aDotDashArray.begin(), aDotDashArray.end(), [&fFactor](double &f){ f *= fFactor; });
222 fDotDashLength *= fFactor;
Value stored to 'fDotDashLength' is never read
223 }
224
225 // prepare current edge's start
226 B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
227 const bool bIsClosed(rCandidate.isClosed());
228 const sal_uInt32 nEdgeCount(bIsClosed ? nPointCount : nPointCount - 1);
229
230 // prepare DotDashArray iteration and the line/gap switching bool
231 sal_uInt32 nDotDashIndex(0);
232 bool bIsLine(true);
233 double fDotDashMovingLength(aDotDashArray[0]);
234 B3DPolygon aSnippet;
235
236 // remember 1st and last snippets to try to merge after execution
237 // is complete and hand to callback
238 B3DPolygon aFirstLine, aLastLine;
239
240 // iterate over all edges
241 for(sal_uInt32 a(0); a < nEdgeCount; a++)
242 {
243 // update current edge
244 const sal_uInt32 nNextIndex((a + 1) % nPointCount);
245 const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
246 const double fEdgeLength(B3DVector(aNextPoint - aCurrentPoint).getLength());
247
248 if(!fTools::equalZero(fEdgeLength))
249 {
250 double fLastDotDashMovingLength(0.0);
251 while(fTools::less(fDotDashMovingLength, fEdgeLength))
252 {
253 // new split is inside edge, create and append snippet [fLastDotDashMovingLength, fDotDashMovingLength]
254 const bool bHandleLine(bIsLine && aLineTargetCallback);
255
256 if(bHandleLine)
257 {
258 if(!aSnippet.count())
259 {
260 aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
261 }
262
263 aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fDotDashMovingLength / fEdgeLength));
264
265 implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
266
267 aSnippet.clear();
268 }
269
270 // prepare next DotDashArray step and flip line/gap flag
271 fLastDotDashMovingLength = fDotDashMovingLength;
272 fDotDashMovingLength += aDotDashArray[(++nDotDashIndex) % nDotDashCount];
273 bIsLine = !bIsLine;
274 }
275
276 // append snippet [fLastDotDashMovingLength, fEdgeLength]
277 const bool bHandleLine(bIsLine && aLineTargetCallback);
278
279 if(bHandleLine)
280 {
281 if(!aSnippet.count())
282 {
283 aSnippet.append(interpolate(aCurrentPoint, aNextPoint, fLastDotDashMovingLength / fEdgeLength));
284 }
285
286 aSnippet.append(aNextPoint);
287 }
288
289 // prepare move to next edge
290 fDotDashMovingLength -= fEdgeLength;
291 }
292
293 // prepare next edge step (end point gets new start point)
294 aCurrentPoint = aNextPoint;
295 }
296
297 // append last intermediate results (if exists)
298 if(aSnippet.count())
299 {
300 const bool bHandleLine(bIsLine && aLineTargetCallback);
301
302 if(bHandleLine)
303 {
304 implHandleSnippet(aSnippet, aLineTargetCallback, aFirstLine, aLastLine);
305 }
306 }
307
308 if(bIsClosed && aLineTargetCallback)
309 {
310 implHandleFirstLast(aLineTargetCallback, aFirstLine, aLastLine);
311 }
312 }
313
314 B3DPolygon applyDefaultNormalsSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter)
315 {
316 B3DPolygon aRetval(rCandidate);
317
318 for(sal_uInt32 a(0); a < aRetval.count(); a++)
319 {
320 B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
321 aVector.normalize();
322 aRetval.setNormal(a, aVector);
323 }
324
325 return aRetval;
326 }
327
328 B3DPolygon invertNormals( const B3DPolygon& rCandidate)
329 {
330 B3DPolygon aRetval(rCandidate);
331
332 if(aRetval.areNormalsUsed())
333 {
334 for(sal_uInt32 a(0); a < aRetval.count(); a++)
335 {
336 aRetval.setNormal(a, -aRetval.getNormal(a));
337 }
338 }
339
340 return aRetval;
341 }
342
343 B3DPolygon applyDefaultTextureCoordinatesParallel( const B3DPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
344 {
345 B3DPolygon aRetval(rCandidate);
346
347 if(bChangeX || bChangeY)
348 {
349 // create projection of standard texture coordinates in (X, Y) onto
350 // the 3d coordinates straight
351 const double fWidth(rRange.getWidth());
352 const double fHeight(rRange.getHeight());
353 const bool bWidthSet(!fTools::equalZero(fWidth));
354 const bool bHeightSet(!fTools::equalZero(fHeight));
355 const double fOne(1.0);
356
357 for(sal_uInt32 a(0); a < aRetval.count(); a++)
358 {
359 const B3DPoint aPoint(aRetval.getB3DPoint(a));
360 B2DPoint aTextureCoordinate(aRetval.getTextureCoordinate(a));
361
362 if(bChangeX)
363 {
364 if(bWidthSet)
365 {
366 aTextureCoordinate.setX((aPoint.getX() - rRange.getMinX()) / fWidth);
367 }
368 else
369 {
370 aTextureCoordinate.setX(0.0);
371 }
372 }
373
374 if(bChangeY)
375 {
376 if(bHeightSet)
377 {
378 aTextureCoordinate.setY(fOne - ((aPoint.getY() - rRange.getMinY()) / fHeight));
379 }
380 else
381 {
382 aTextureCoordinate.setY(fOne);
383 }
384 }
385
386 aRetval.setTextureCoordinate(a, aTextureCoordinate);
387 }
388 }
389
390 return aRetval;
391 }
392
393 B3DPolygon applyDefaultTextureCoordinatesSphere( const B3DPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
394 {
395 B3DPolygon aRetval(rCandidate);
396
397 if(bChangeX || bChangeY)
398 {
399 // create texture coordinates using sphere projection to cartesian coordinates,
400 // use object's center as base
401 const double fOne(1.0);
402 const sal_uInt32 nPointCount(aRetval.count());
403 bool bPolarPoints(false);
404 sal_uInt32 a;
405
406 // create center cartesian coordinates to have a possibility to decide if on boundary
407 // transitions which value to choose
408 const B3DRange aPlaneRange(getRange(rCandidate));
409 const B3DPoint aPlaneCenter(aPlaneRange.getCenter() - rCenter);
410 const double fXCenter(fOne - ((atan2(aPlaneCenter.getZ(), aPlaneCenter.getX()) + F_PI3.14159265358979323846) / F_2PI(2.0*3.14159265358979323846)));
411
412 for(a = 0; a < nPointCount; a++)
413 {
414 const B3DVector aVector(aRetval.getB3DPoint(a) - rCenter);
415 const double fY(fOne - ((atan2(aVector.getY(), aVector.getXZLength()) + F_PI21.57079632679489661923) / F_PI3.14159265358979323846));
416 B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));
417
418 if(fTools::equalZero(fY))
419 {
420 // point is a north polar point, no useful X-coordinate can be created.
421 if(bChangeY)
422 {
423 aTexCoor.setY(0.0);
424
425 if(bChangeX)
426 {
427 bPolarPoints = true;
428 }
429 }
430 }
431 else if(fTools::equal(fY, fOne))
432 {
433 // point is a south polar point, no useful X-coordinate can be created. Set
434 // Y-coordinate, though
435 if(bChangeY)
436 {
437 aTexCoor.setY(fOne);
438
439 if(bChangeX)
440 {
441 bPolarPoints = true;
442 }
443 }
444 }
445 else
446 {
447 double fX(fOne - ((atan2(aVector.getZ(), aVector.getX()) + F_PI3.14159265358979323846) / F_2PI(2.0*3.14159265358979323846)));
448
449 // correct cartesian point coordinate dependent from center value
450 if(fX > fXCenter + 0.5)
451 {
452 fX -= fOne;
453 }
454 else if(fX < fXCenter - 0.5)
455 {
456 fX += fOne;
457 }
458
459 if(bChangeX)
460 {
461 aTexCoor.setX(fX);
462 }
463
464 if(bChangeY)
465 {
466 aTexCoor.setY(fY);
467 }
468 }
469
470 aRetval.setTextureCoordinate(a, aTexCoor);
471 }
472
473 if(bPolarPoints)
474 {
475 // correct X-texture coordinates if polar points are contained. Those
476 // coordinates cannot be correct, so use prev or next X-coordinate
477 for(a = 0; a < nPointCount; a++)
478 {
479 B2DPoint aTexCoor(aRetval.getTextureCoordinate(a));
480
481 if(fTools::equalZero(aTexCoor.getY()) || fTools::equal(aTexCoor.getY(), fOne))
482 {
483 // get prev, next TexCoor and test for pole
484 const B2DPoint aPrevTexCoor(aRetval.getTextureCoordinate(a ? a - 1 : nPointCount - 1));
485 const B2DPoint aNextTexCoor(aRetval.getTextureCoordinate((a + 1) % nPointCount));
486 const bool bPrevPole(fTools::equalZero(aPrevTexCoor.getY()) || fTools::equal(aPrevTexCoor.getY(), fOne));
487 const bool bNextPole(fTools::equalZero(aNextTexCoor.getY()) || fTools::equal(aNextTexCoor.getY(), fOne));
488
489 if(!bPrevPole && !bNextPole)
490 {
491 // both no poles, mix them
492 aTexCoor.setX((aPrevTexCoor.getX() + aNextTexCoor.getX()) / 2.0);
493 }
494 else if(!bNextPole)
495 {
496 // copy next
497 aTexCoor.setX(aNextTexCoor.getX());
498 }
499 else
500 {
501 // copy prev, even if it's a pole, hopefully it is already corrected
502 aTexCoor.setX(aPrevTexCoor.getX());
503 }
504
505 aRetval.setTextureCoordinate(a, aTexCoor);
506 }
507 }
508 }
509 }
510
511 return aRetval;
512 }
513
514 bool isInside(const B3DPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder)
515 {
516 if(bWithBorder && isPointOnPolygon(rCandidate, rPoint))
517 {
518 return true;
519 }
520 else
521 {
522 bool bRetval(false);
523 const B3DVector aPlaneNormal(rCandidate.getNormal());
524
525 if(!aPlaneNormal.equalZero())
526 {
527 const sal_uInt32 nPointCount(rCandidate.count());
528
529 if(nPointCount)
530 {
531 B3DPoint aCurrentPoint(rCandidate.getB3DPoint(nPointCount - 1));
532 const double fAbsX(fabs(aPlaneNormal.getX()));
533 const double fAbsY(fabs(aPlaneNormal.getY()));
534 const double fAbsZ(fabs(aPlaneNormal.getZ()));
535
536 if(fAbsX > fAbsY && fAbsX > fAbsZ)
537 {
538 // normal points mostly in X-Direction, use YZ-Polygon projection for check
539 // x -> y, y -> z
540 for(sal_uInt32 a(0); a < nPointCount; a++)
541 {
542 const B3DPoint aPreviousPoint(aCurrentPoint);
543 aCurrentPoint = rCandidate.getB3DPoint(a);
544
545 // cross-over in Z?
546 const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
547 const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
548
549 if(bCompZA != bCompZB)
550 {
551 // cross-over in Y?
552 const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
553 const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
554
555 if(bCompYA == bCompYB)
556 {
557 if(bCompYA)
558 {
559 bRetval = !bRetval;
560 }
561 }
562 else
563 {
564 const double fCompare(
565 aCurrentPoint.getY() - (aCurrentPoint.getZ() - rPoint.getZ()) *
566 (aPreviousPoint.getY() - aCurrentPoint.getY()) /
567 (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
568
569 if(fTools::more(fCompare, rPoint.getY()))
570 {
571 bRetval = !bRetval;
572 }
573 }
574 }
575 }
576 }
577 else if(fAbsY > fAbsX && fAbsY > fAbsZ)
578 {
579 // normal points mostly in Y-Direction, use XZ-Polygon projection for check
580 // x -> x, y -> z
581 for(sal_uInt32 a(0); a < nPointCount; a++)
582 {
583 const B3DPoint aPreviousPoint(aCurrentPoint);
584 aCurrentPoint = rCandidate.getB3DPoint(a);
585
586 // cross-over in Z?
587 const bool bCompZA(fTools::more(aPreviousPoint.getZ(), rPoint.getZ()));
588 const bool bCompZB(fTools::more(aCurrentPoint.getZ(), rPoint.getZ()));
589
590 if(bCompZA != bCompZB)
591 {
592 // cross-over in X?
593 const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
594 const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
595
596 if(bCompXA == bCompXB)
597 {
598 if(bCompXA)
599 {
600 bRetval = !bRetval;
601 }
602 }
603 else
604 {
605 const double fCompare(
606 aCurrentPoint.getX() - (aCurrentPoint.getZ() - rPoint.getZ()) *
607 (aPreviousPoint.getX() - aCurrentPoint.getX()) /
608 (aPreviousPoint.getZ() - aCurrentPoint.getZ()));
609
610 if(fTools::more(fCompare, rPoint.getX()))
611 {
612 bRetval = !bRetval;
613 }
614 }
615 }
616 }
617 }
618 else
619 {
620 // normal points mostly in Z-Direction, use XY-Polygon projection for check
621 // x -> x, y -> y
622 for(sal_uInt32 a(0); a < nPointCount; a++)
623 {
624 const B3DPoint aPreviousPoint(aCurrentPoint);
625 aCurrentPoint = rCandidate.getB3DPoint(a);
626
627 // cross-over in Y?
628 const bool bCompYA(fTools::more(aPreviousPoint.getY(), rPoint.getY()));
629 const bool bCompYB(fTools::more(aCurrentPoint.getY(), rPoint.getY()));
630
631 if(bCompYA != bCompYB)
632 {
633 // cross-over in X?
634 const bool bCompXA(fTools::more(aPreviousPoint.getX(), rPoint.getX()));
635 const bool bCompXB(fTools::more(aCurrentPoint.getX(), rPoint.getX()));
636
637 if(bCompXA == bCompXB)
638 {
639 if(bCompXA)
640 {
641 bRetval = !bRetval;
642 }
643 }
644 else
645 {
646 const double fCompare(
647 aCurrentPoint.getX() - (aCurrentPoint.getY() - rPoint.getY()) *
648 (aPreviousPoint.getX() - aCurrentPoint.getX()) /
649 (aPreviousPoint.getY() - aCurrentPoint.getY()));
650
651 if(fTools::more(fCompare, rPoint.getX()))
652 {
653 bRetval = !bRetval;
654 }
655 }
656 }
657 }
658 }
659 }
660 }
661
662 return bRetval;
663 }
664 }
665
666 bool isPointOnLine(const B3DPoint& rStart, const B3DPoint& rEnd, const B3DPoint& rCandidate, bool bWithPoints)
667 {
668 if(rCandidate.equal(rStart) || rCandidate.equal(rEnd))
669 {
670 // candidate is in epsilon around start or end -> inside
671 return bWithPoints;
672 }
673 else if(rStart.equal(rEnd))
674 {
675 // start and end are equal, but candidate is outside their epsilon -> outside
676 return false;
677 }
678 else
679 {
680 const B3DVector aEdgeVector(rEnd - rStart);
681 const B3DVector aTestVector(rCandidate - rStart);
682
683 if(areParallel(aEdgeVector, aTestVector))
684 {
685 double fParamTestOnCurr(0.0);
686
687 if(aEdgeVector.getX() > aEdgeVector.getY())
688 {
689 if(aEdgeVector.getX() > aEdgeVector.getZ())
690 {
691 // X is biggest
692 fParamTestOnCurr = aTestVector.getX() / aEdgeVector.getX();
693 }
694 else
695 {
696 // Z is biggest
697 fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
698 }
699 }
700 else
701 {
702 if(aEdgeVector.getY() > aEdgeVector.getZ())
703 {
704 // Y is biggest
705 fParamTestOnCurr = aTestVector.getY() / aEdgeVector.getY();
706 }
707 else
708 {
709 // Z is biggest
710 fParamTestOnCurr = aTestVector.getZ() / aEdgeVector.getZ();
711 }
712 }
713
714 if(fTools::more(fParamTestOnCurr, 0.0) && fTools::less(fParamTestOnCurr, 1.0))
715 {
716 return true;
717 }
718 }
719
720 return false;
721 }
722 }
723
724 bool isPointOnPolygon(const B3DPolygon& rCandidate, const B3DPoint& rPoint)
725 {
726 const sal_uInt32 nPointCount(rCandidate.count());
727
728 if(nPointCount > 1)
729 {
730 const sal_uInt32 nLoopCount(rCandidate.isClosed() ? nPointCount : nPointCount - 1);
731 B3DPoint aCurrentPoint(rCandidate.getB3DPoint(0));
732
733 for(sal_uInt32 a(0); a < nLoopCount; a++)
734 {
735 const B3DPoint aNextPoint(rCandidate.getB3DPoint((a + 1) % nPointCount));
736
737 if(isPointOnLine(aCurrentPoint, aNextPoint, rPoint, true/*bWithPoints*/))
738 {
739 return true;
740 }
741
742 aCurrentPoint = aNextPoint;
743 }
744 }
745 else if(nPointCount)
746 {
747 return rPoint.equal(rCandidate.getB3DPoint(0));
748 }
749
750 return false;
751 }
752
753 bool getCutBetweenLineAndPlane(const B3DVector& rPlaneNormal, const B3DPoint& rPlanePoint, const B3DPoint& rEdgeStart, const B3DPoint& rEdgeEnd, double& fCut)
754 {
755 if(!rPlaneNormal.equalZero() && !rEdgeStart.equal(rEdgeEnd))
756 {
757 const B3DVector aTestEdge(rEdgeEnd - rEdgeStart);
758 const double fScalarEdge(rPlaneNormal.scalar(aTestEdge));
759
760 if(!fTools::equalZero(fScalarEdge))
761 {
762 const B3DVector aCompareEdge(rPlanePoint - rEdgeStart);
763 const double fScalarCompare(rPlaneNormal.scalar(aCompareEdge));
764
765 fCut = fScalarCompare / fScalarEdge;
766 return true;
767 }
768 }
769
770 return false;
771 }
772
773 // snap points of horizontal or vertical edges to discrete values
774 B3DPolygon snapPointsOfHorizontalOrVerticalEdges(const B3DPolygon& rCandidate)
775 {
776 const sal_uInt32 nPointCount(rCandidate.count());
777
778 if(nPointCount > 1)
779 {
780 // Start by copying the source polygon to get a writeable copy. The closed state is
781 // copied by aRetval's initialisation, too, so no need to copy it in this method
782 B3DPolygon aRetval(rCandidate);
783
784 // prepare geometry data. Get rounded from original
785 B3ITuple aPrevTuple(basegfx::fround(rCandidate.getB3DPoint(nPointCount - 1)));
786 B3DPoint aCurrPoint(rCandidate.getB3DPoint(0));
787 B3ITuple aCurrTuple(basegfx::fround(aCurrPoint));
788
789 // loop over all points. This will also snap the implicit closing edge
790 // even when not closed, but that's no problem here
791 for(sal_uInt32 a(0); a < nPointCount; a++)
792 {
793 // get next point. Get rounded from original
794 const bool bLastRun(a + 1 == nPointCount);
795 const sal_uInt32 nNextIndex(bLastRun ? 0 : a + 1);
796 const B3DPoint aNextPoint(rCandidate.getB3DPoint(nNextIndex));
797 const B3ITuple aNextTuple(basegfx::fround(aNextPoint));
798
799 // get the states
800 const bool bPrevVertical(aPrevTuple.getX() == aCurrTuple.getX());
801 const bool bNextVertical(aNextTuple.getX() == aCurrTuple.getX());
802 const bool bPrevHorizontal(aPrevTuple.getY() == aCurrTuple.getY());
803 const bool bNextHorizontal(aNextTuple.getY() == aCurrTuple.getY());
804 const bool bSnapX(bPrevVertical || bNextVertical);
805 const bool bSnapY(bPrevHorizontal || bNextHorizontal);
806
807 if(bSnapX || bSnapY)
808 {
809 const B3DPoint aSnappedPoint(
810 bSnapX ? aCurrTuple.getX() : aCurrPoint.getX(),
811 bSnapY ? aCurrTuple.getY() : aCurrPoint.getY(),
812 aCurrPoint.getZ());
813
814 aRetval.setB3DPoint(a, aSnappedPoint);
815 }
816
817 // prepare next point
818 if(!bLastRun)
819 {
820 aPrevTuple = aCurrTuple;
821 aCurrPoint = aNextPoint;
822 aCurrTuple = aNextTuple;
823 }
824 }
825
826 return aRetval;
827 }
828 else
829 {
830 return rCandidate;
831 }
832 }
833
834} // end of namespace
835
836/* vim:set shiftwidth=4 softtabstop=4 expandtab: */