Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / basegfx / source / polygon / b3dpolypolygontools.cxx
blob0130dd5d7081fd5c13581bb6d2d1449bcedec41b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <rtl/instance.hxx>
21 #include <osl/diagnose.h>
22 #include <basegfx/polygon/b3dpolypolygontools.hxx>
23 #include <basegfx/range/b3drange.hxx>
24 #include <basegfx/polygon/b3dpolypolygon.hxx>
25 #include <basegfx/polygon/b3dpolygon.hxx>
26 #include <basegfx/polygon/b3dpolygontools.hxx>
27 #include <numeric>
28 #include <basegfx/matrix/b3dhommatrix.hxx>
29 #include <basegfx/numeric/ftools.hxx>
30 #include <com/sun/star/drawing/DoubleSequence.hpp>
32 // predefines
33 #define nMinSegments sal_uInt32(1)
34 #define nMaxSegments sal_uInt32(512)
36 namespace basegfx
38 namespace utils
40 // B3DPolyPolygon tools
41 B3DRange getRange(const B3DPolyPolygon& rCandidate)
43 B3DRange aRetval;
44 const sal_uInt32 nPolygonCount(rCandidate.count());
46 for(sal_uInt32 a(0); a < nPolygonCount; a++)
48 B3DPolygon aCandidate = rCandidate.getB3DPolygon(a);
49 aRetval.expand(getRange(aCandidate));
52 return aRetval;
55 namespace
57 struct theUnitCubePolyPolygon : public rtl::StaticWithInit<B3DPolyPolygon,
58 theUnitCubePolyPolygon>
60 B3DPolyPolygon operator()()
62 B3DPolyPolygon aRetval;
63 B3DPolygon aTemp;
64 aTemp.append(B3DPoint(0.0, 0.0, 1.0));
65 aTemp.append(B3DPoint(0.0, 1.0, 1.0));
66 aTemp.append(B3DPoint(1.0, 1.0, 1.0));
67 aTemp.append(B3DPoint(1.0, 0.0, 1.0));
68 aTemp.setClosed(true);
69 aRetval.append(aTemp);
71 aTemp.clear();
72 aTemp.append(B3DPoint(0.0, 0.0, 0.0));
73 aTemp.append(B3DPoint(0.0, 1.0, 0.0));
74 aTemp.append(B3DPoint(1.0, 1.0, 0.0));
75 aTemp.append(B3DPoint(1.0, 0.0, 0.0));
76 aTemp.setClosed(true);
77 aRetval.append(aTemp);
79 aTemp.clear();
80 aTemp.append(B3DPoint(0.0, 0.0, 0.0));
81 aTemp.append(B3DPoint(0.0, 0.0, 1.0));
82 aRetval.append(aTemp);
84 aTemp.clear();
85 aTemp.append(B3DPoint(0.0, 1.0, 0.0));
86 aTemp.append(B3DPoint(0.0, 1.0, 1.0));
87 aRetval.append(aTemp);
89 aTemp.clear();
90 aTemp.append(B3DPoint(1.0, 1.0, 0.0));
91 aTemp.append(B3DPoint(1.0, 1.0, 1.0));
92 aRetval.append(aTemp);
94 aTemp.clear();
95 aTemp.append(B3DPoint(1.0, 0.0, 0.0));
96 aTemp.append(B3DPoint(1.0, 0.0, 1.0));
97 aRetval.append(aTemp);
98 return aRetval;
103 B3DPolyPolygon const & createUnitCubePolyPolygon()
105 return theUnitCubePolyPolygon::get();
108 namespace
110 struct theUnitCubeFillPolyPolygon : public rtl::StaticWithInit<B3DPolyPolygon,
111 theUnitCubeFillPolyPolygon>
113 B3DPolyPolygon operator()()
115 B3DPolyPolygon aRetval;
116 B3DPolygon aTemp;
118 // all points
119 const B3DPoint A(0.0, 0.0, 0.0);
120 const B3DPoint B(0.0, 1.0, 0.0);
121 const B3DPoint C(1.0, 1.0, 0.0);
122 const B3DPoint D(1.0, 0.0, 0.0);
123 const B3DPoint E(0.0, 0.0, 1.0);
124 const B3DPoint F(0.0, 1.0, 1.0);
125 const B3DPoint G(1.0, 1.0, 1.0);
126 const B3DPoint H(1.0, 0.0, 1.0);
128 // create bottom
129 aTemp.append(D);
130 aTemp.append(A);
131 aTemp.append(E);
132 aTemp.append(H);
133 aTemp.setClosed(true);
134 aRetval.append(aTemp);
136 // create front
137 aTemp.clear();
138 aTemp.append(B);
139 aTemp.append(A);
140 aTemp.append(D);
141 aTemp.append(C);
142 aTemp.setClosed(true);
143 aRetval.append(aTemp);
145 // create left
146 aTemp.clear();
147 aTemp.append(E);
148 aTemp.append(A);
149 aTemp.append(B);
150 aTemp.append(F);
151 aTemp.setClosed(true);
152 aRetval.append(aTemp);
154 // create top
155 aTemp.clear();
156 aTemp.append(C);
157 aTemp.append(G);
158 aTemp.append(F);
159 aTemp.append(B);
160 aTemp.setClosed(true);
161 aRetval.append(aTemp);
163 // create right
164 aTemp.clear();
165 aTemp.append(H);
166 aTemp.append(G);
167 aTemp.append(C);
168 aTemp.append(D);
169 aTemp.setClosed(true);
170 aRetval.append(aTemp);
172 // create back
173 aTemp.clear();
174 aTemp.append(F);
175 aTemp.append(G);
176 aTemp.append(H);
177 aTemp.append(E);
178 aTemp.setClosed(true);
179 aRetval.append(aTemp);
180 return aRetval;
185 B3DPolyPolygon const & createUnitCubeFillPolyPolygon()
187 return theUnitCubeFillPolyPolygon::get();
190 B3DPolyPolygon createCubePolyPolygonFromB3DRange( const B3DRange& rRange)
192 B3DPolyPolygon aRetval;
194 if(!rRange.isEmpty())
196 aRetval = createUnitCubePolyPolygon();
197 B3DHomMatrix aTrans;
198 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
199 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
200 aRetval.transform(aTrans);
201 aRetval.removeDoublePoints();
204 return aRetval;
207 B3DPolyPolygon createCubeFillPolyPolygonFromB3DRange( const B3DRange& rRange)
209 B3DPolyPolygon aRetval;
211 if(!rRange.isEmpty())
213 aRetval = createUnitCubeFillPolyPolygon();
214 B3DHomMatrix aTrans;
215 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
216 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
217 aRetval.transform(aTrans);
218 aRetval.removeDoublePoints();
221 return aRetval;
224 // helper for getting the 3D Point from given cartesian coordinates. fHor is defined from
225 // [F_PI2 .. -F_PI2], fVer from [0.0 .. F_2PI]
226 inline B3DPoint getPointFromCartesian(double fHor, double fVer)
228 const double fCosVer(cos(fVer));
229 return B3DPoint(fCosVer * cos(fHor), sin(fVer), fCosVer * -sin(fHor));
232 B3DPolyPolygon createUnitSpherePolyPolygon(
233 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
234 double fVerStart, double fVerStop,
235 double fHorStart, double fHorStop)
237 B3DPolyPolygon aRetval;
238 sal_uInt32 a, b;
240 if(!nHorSeg)
242 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
245 // min/max limitations
246 nHorSeg = std::min(nMaxSegments, std::max(nMinSegments, nHorSeg));
248 if(!nVerSeg)
250 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
253 // min/max limitations
254 nVerSeg = std::min(nMaxSegments, std::max(nMinSegments, nVerSeg));
256 // create constants
257 const double fVerDiffPerStep((fVerStop - fVerStart) / static_cast<double>(nVerSeg));
258 const double fHorDiffPerStep((fHorStop - fHorStart) / static_cast<double>(nHorSeg));
259 bool bHorClosed(fTools::equal(fHorStop - fHorStart, F_2PI));
260 bool bVerFromTop(fTools::equal(fVerStart, F_PI2));
261 bool bVerToBottom(fTools::equal(fVerStop, -F_PI2));
263 // create horizontal rings
264 const sal_uInt32 nLoopVerInit(bVerFromTop ? 1 : 0);
265 const sal_uInt32 nLoopVerLimit(bVerToBottom ? nVerSeg : nVerSeg + 1);
266 const sal_uInt32 nLoopHorLimit(bHorClosed ? nHorSeg : nHorSeg + 1);
268 for(a = nLoopVerInit; a < nLoopVerLimit; a++)
270 const double fVer(fVerStart + (static_cast<double>(a) * fVerDiffPerStep));
271 B3DPolygon aNew;
273 for(b = 0; b < nLoopHorLimit; b++)
275 const double fHor(fHorStart + (static_cast<double>(b) * fHorDiffPerStep));
276 aNew.append(getPointFromCartesian(fHor, fVer));
279 aNew.setClosed(bHorClosed);
280 aRetval.append(aNew);
283 // create vertical half-rings
284 for(a = 0; a < nLoopHorLimit; a++)
286 const double fHor(fHorStart + (static_cast<double>(a) * fHorDiffPerStep));
287 B3DPolygon aNew;
289 if(bVerFromTop)
291 aNew.append(B3DPoint(0.0, 1.0, 0.0));
294 for(b = nLoopVerInit; b < nLoopVerLimit; b++)
296 const double fVer(fVerStart + (static_cast<double>(b) * fVerDiffPerStep));
297 aNew.append(getPointFromCartesian(fHor, fVer));
300 if(bVerToBottom)
302 aNew.append(B3DPoint(0.0, -1.0, 0.0));
305 aRetval.append(aNew);
308 return aRetval;
311 B3DPolyPolygon createSpherePolyPolygonFromB3DRange( const B3DRange& rRange,
312 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
313 double fVerStart, double fVerStop,
314 double fHorStart, double fHorStop)
316 B3DPolyPolygon aRetval(createUnitSpherePolyPolygon(nHorSeg, nVerSeg, fVerStart, fVerStop, fHorStart, fHorStop));
318 if(aRetval.count())
320 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
321 B3DHomMatrix aTrans;
322 aTrans.translate(1.0, 1.0, 1.0);
323 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
324 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
325 aRetval.transform(aTrans);
328 return aRetval;
331 B3DPolyPolygon createUnitSphereFillPolyPolygon(
332 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
333 bool bNormals,
334 double fVerStart, double fVerStop,
335 double fHorStart, double fHorStop)
337 B3DPolyPolygon aRetval;
339 if(!nHorSeg)
341 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
344 // min/max limitations
345 nHorSeg = std::min(nMaxSegments, std::max(nMinSegments, nHorSeg));
347 if(!nVerSeg)
349 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
352 // min/max limitations
353 nVerSeg = std::min(nMaxSegments, std::max(nMinSegments, nVerSeg));
355 // vertical loop
356 for(sal_uInt32 a(0); a < nVerSeg; a++)
358 const double fVer1(fVerStart + (((fVerStop - fVerStart) * a) / nVerSeg));
359 const double fVer2(fVerStart + (((fVerStop - fVerStart) * (a + 1)) / nVerSeg));
361 // horizontal loop
362 for(sal_uInt32 b(0); b < nHorSeg; b++)
364 const double fHor1(fHorStart + (((fHorStop - fHorStart) * b) / nHorSeg));
365 const double fHor2(fHorStart + (((fHorStop - fHorStart) * (b + 1)) / nHorSeg));
366 B3DPolygon aNew;
368 aNew.append(getPointFromCartesian(fHor1, fVer1));
369 aNew.append(getPointFromCartesian(fHor2, fVer1));
370 aNew.append(getPointFromCartesian(fHor2, fVer2));
371 aNew.append(getPointFromCartesian(fHor1, fVer2));
373 if(bNormals)
375 for(sal_uInt32 c(0); c < aNew.count(); c++)
377 aNew.setNormal(c, ::basegfx::B3DVector(aNew.getB3DPoint(c)));
381 aNew.setClosed(true);
382 aRetval.append(aNew);
386 return aRetval;
389 B3DPolyPolygon createSphereFillPolyPolygonFromB3DRange( const B3DRange& rRange,
390 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
391 bool bNormals,
392 double fVerStart, double fVerStop,
393 double fHorStart, double fHorStop)
395 B3DPolyPolygon aRetval(createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, bNormals, fVerStart, fVerStop, fHorStart, fHorStop));
397 if(aRetval.count())
399 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
400 B3DHomMatrix aTrans;
401 aTrans.translate(1.0, 1.0, 1.0);
402 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
403 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
404 aRetval.transform(aTrans);
407 return aRetval;
410 B3DPolyPolygon applyDefaultNormalsSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter)
412 B3DPolyPolygon aRetval;
414 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
416 aRetval.append(applyDefaultNormalsSphere(rCandidate.getB3DPolygon(a), rCenter));
419 return aRetval;
422 B3DPolyPolygon invertNormals( const B3DPolyPolygon& rCandidate)
424 B3DPolyPolygon aRetval;
426 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
428 aRetval.append(invertNormals(rCandidate.getB3DPolygon(a)));
431 return aRetval;
434 B3DPolyPolygon applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
436 B3DPolyPolygon aRetval;
438 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
440 aRetval.append(applyDefaultTextureCoordinatesParallel(rCandidate.getB3DPolygon(a), rRange, bChangeX, bChangeY));
443 return aRetval;
446 B3DPolyPolygon applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
448 B3DPolyPolygon aRetval;
450 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
452 aRetval.append(applyDefaultTextureCoordinatesSphere(rCandidate.getB3DPolygon(a), rCenter, bChangeX, bChangeY));
455 return aRetval;
458 bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint)
460 const sal_uInt32 nPolygonCount(rCandidate.count());
462 if(nPolygonCount == 1)
464 return isInside(rCandidate.getB3DPolygon(0), rPoint, false/*bWithBorder*/);
466 else
468 sal_Int32 nInsideCount(0);
470 for(sal_uInt32 a(0); a < nPolygonCount; a++)
472 const B3DPolygon aPolygon(rCandidate.getB3DPolygon(a));
473 const bool bInside(isInside(aPolygon, rPoint, false/*bWithBorder*/));
475 if(bInside)
477 nInsideCount++;
481 return (nInsideCount % 2);
485 /// converters for css::drawing::PolyPolygonShape3D
486 B3DPolyPolygon UnoPolyPolygonShape3DToB3DPolyPolygon(
487 const css::drawing::PolyPolygonShape3D& rPolyPolygonShape3DSource)
489 B3DPolyPolygon aRetval;
490 const sal_Int32 nOuterSequenceCount(rPolyPolygonShape3DSource.SequenceX.getLength());
492 if(nOuterSequenceCount)
494 OSL_ENSURE(nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceY.getLength()
495 && nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceZ.getLength(),
496 "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)");
498 const css::drawing::DoubleSequence* pInnerSequenceX = rPolyPolygonShape3DSource.SequenceX.getConstArray();
499 const css::drawing::DoubleSequence* pInnerSequenceY = rPolyPolygonShape3DSource.SequenceY.getConstArray();
500 const css::drawing::DoubleSequence* pInnerSequenceZ = rPolyPolygonShape3DSource.SequenceZ.getConstArray();
502 for(sal_Int32 a(0); a < nOuterSequenceCount; a++)
504 basegfx::B3DPolygon aNewPolygon;
505 const sal_Int32 nInnerSequenceCount(pInnerSequenceX->getLength());
506 OSL_ENSURE(nInnerSequenceCount == pInnerSequenceY->getLength()
507 && nInnerSequenceCount == pInnerSequenceZ->getLength(),
508 "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)");
510 const double* pArrayX = pInnerSequenceX->getConstArray();
511 const double* pArrayY = pInnerSequenceY->getConstArray();
512 const double* pArrayZ = pInnerSequenceZ->getConstArray();
514 for(sal_Int32 b(0); b < nInnerSequenceCount; b++)
516 aNewPolygon.append(basegfx::B3DPoint(*pArrayX++,*pArrayY++,*pArrayZ++));
519 pInnerSequenceX++;
520 pInnerSequenceY++;
521 pInnerSequenceZ++;
523 // #i101520# correction is needed for imported polygons of old format,
524 // see callers
525 basegfx::utils::checkClosed(aNewPolygon);
527 aRetval.append(aNewPolygon);
531 return aRetval;
534 void B3DPolyPolygonToUnoPolyPolygonShape3D(
535 const B3DPolyPolygon& rPolyPolygonSource,
536 css::drawing::PolyPolygonShape3D& rPolyPolygonShape3DRetval)
538 const sal_uInt32 nPolygonCount(rPolyPolygonSource.count());
540 if(nPolygonCount)
542 rPolyPolygonShape3DRetval.SequenceX.realloc(nPolygonCount);
543 rPolyPolygonShape3DRetval.SequenceY.realloc(nPolygonCount);
544 rPolyPolygonShape3DRetval.SequenceZ.realloc(nPolygonCount);
546 css::drawing::DoubleSequence* pOuterSequenceX = rPolyPolygonShape3DRetval.SequenceX.getArray();
547 css::drawing::DoubleSequence* pOuterSequenceY = rPolyPolygonShape3DRetval.SequenceY.getArray();
548 css::drawing::DoubleSequence* pOuterSequenceZ = rPolyPolygonShape3DRetval.SequenceZ.getArray();
550 for(sal_uInt32 a(0); a < nPolygonCount; a++)
552 const basegfx::B3DPolygon aPoly(rPolyPolygonSource.getB3DPolygon(a));
553 const sal_uInt32 nPointCount(aPoly.count());
555 if(nPointCount)
557 const bool bIsClosed(aPoly.isClosed());
558 const sal_uInt32 nTargetCount(bIsClosed ? nPointCount + 1 : nPointCount);
559 pOuterSequenceX->realloc(nTargetCount);
560 pOuterSequenceY->realloc(nTargetCount);
561 pOuterSequenceZ->realloc(nTargetCount);
563 double* pInnerSequenceX = pOuterSequenceX->getArray();
564 double* pInnerSequenceY = pOuterSequenceY->getArray();
565 double* pInnerSequenceZ = pOuterSequenceZ->getArray();
567 for(sal_uInt32 b(0); b < nPointCount; b++)
569 const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(b));
571 *pInnerSequenceX++ = aPoint.getX();
572 *pInnerSequenceY++ = aPoint.getY();
573 *pInnerSequenceZ++ = aPoint.getZ();
576 if(bIsClosed)
578 const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(0));
580 *pInnerSequenceX++ = aPoint.getX();
581 *pInnerSequenceY++ = aPoint.getY();
582 *pInnerSequenceZ++ = aPoint.getZ();
585 else
587 pOuterSequenceX->realloc(0);
588 pOuterSequenceY->realloc(0);
589 pOuterSequenceZ->realloc(0);
592 pOuterSequenceX++;
593 pOuterSequenceY++;
594 pOuterSequenceZ++;
597 else
599 rPolyPolygonShape3DRetval.SequenceX.realloc(0);
600 rPolyPolygonShape3DRetval.SequenceY.realloc(0);
601 rPolyPolygonShape3DRetval.SequenceZ.realloc(0);
605 } // end of namespace utils
606 } // end of namespace basegfx
608 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */