bump product version to 5.0.4.1
[LibreOffice.git] / basegfx / source / polygon / b3dpolypolygontools.cxx
blob0f74f6e588296bdd8108a843a37bdc318b46bd71
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 tools
40 // B3DPolyPolygon tools
41 B3DRange getRange(const B3DPolyPolygon& rCandidate)
43 B3DRange aRetval;
44 const sal_uInt32 nPolygonCount(rCandidate.count());
46 for(sal_uInt32 a(0L); 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 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 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 coordiantes. 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) / (double)nVerSeg);
258 const double fHorDiffPerStep((fHorStop - fHorStart) / (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 ? 1L : 0L);
265 const sal_uInt32 nLoopVerLimit(bVerToBottom ? nVerSeg : nVerSeg + 1L);
266 const sal_uInt32 nLoopHorLimit(bHorClosed ? nHorSeg : nHorSeg + 1L);
268 for(a = nLoopVerInit; a < nLoopVerLimit; a++)
270 const double fVer(fVerStart + ((double)(a) * fVerDiffPerStep));
271 B3DPolygon aNew;
273 for(b = 0L; b < nLoopHorLimit; b++)
275 const double fHor(fHorStart + ((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 = 0L; a < nLoopHorLimit; a++)
286 const double fHor(fHorStart + ((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 + ((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(0L); 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(0L); 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(0L); 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(0L); 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(0L); 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(0L); 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(0L); 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, bool bWithBorder)
460 const sal_uInt32 nPolygonCount(rCandidate.count());
462 if(1L == nPolygonCount)
464 return isInside(rCandidate.getB3DPolygon(0), rPoint, 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, bWithBorder));
475 if(bInside)
477 nInsideCount++;
481 return (nInsideCount % 2L);
485 /// converters for com::sun::star::drawing::PolyPolygonShape3D
486 B3DPolyPolygon UnoPolyPolygonShape3DToB3DPolyPolygon(
487 const com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygonShape3DSource,
488 bool bCheckClosed)
490 B3DPolyPolygon aRetval;
491 const sal_Int32 nOuterSequenceCount(rPolyPolygonShape3DSource.SequenceX.getLength());
493 if(nOuterSequenceCount)
495 OSL_ENSURE(nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceY.getLength()
496 && nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceZ.getLength(),
497 "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)");
499 const com::sun::star::drawing::DoubleSequence* pInnerSequenceX = rPolyPolygonShape3DSource.SequenceX.getConstArray();
500 const com::sun::star::drawing::DoubleSequence* pInnerSequenceY = rPolyPolygonShape3DSource.SequenceY.getConstArray();
501 const com::sun::star::drawing::DoubleSequence* pInnerSequenceZ = rPolyPolygonShape3DSource.SequenceZ.getConstArray();
503 for(sal_Int32 a(0); a < nOuterSequenceCount; a++)
505 basegfx::B3DPolygon aNewPolygon;
506 const sal_Int32 nInnerSequenceCount(pInnerSequenceX->getLength());
507 OSL_ENSURE(nInnerSequenceCount == pInnerSequenceY->getLength()
508 && nInnerSequenceCount == pInnerSequenceZ->getLength(),
509 "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)");
511 const double* pArrayX = pInnerSequenceX->getConstArray();
512 const double* pArrayY = pInnerSequenceY->getConstArray();
513 const double* pArrayZ = pInnerSequenceZ->getConstArray();
515 for(sal_Int32 b(0); b < nInnerSequenceCount; b++)
517 aNewPolygon.append(basegfx::B3DPoint(*pArrayX++,*pArrayY++,*pArrayZ++));
520 pInnerSequenceX++;
521 pInnerSequenceY++;
522 pInnerSequenceZ++;
524 // #i101520# correction is needed for imported polygons of old format,
525 // see callers
526 if(bCheckClosed)
528 basegfx::tools::checkClosed(aNewPolygon);
531 aRetval.append(aNewPolygon);
535 return aRetval;
538 void B3DPolyPolygonToUnoPolyPolygonShape3D(
539 const B3DPolyPolygon& rPolyPolygonSource,
540 com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygonShape3DRetval)
542 const sal_uInt32 nPolygonCount(rPolyPolygonSource.count());
544 if(nPolygonCount)
546 rPolyPolygonShape3DRetval.SequenceX.realloc(nPolygonCount);
547 rPolyPolygonShape3DRetval.SequenceY.realloc(nPolygonCount);
548 rPolyPolygonShape3DRetval.SequenceZ.realloc(nPolygonCount);
550 com::sun::star::drawing::DoubleSequence* pOuterSequenceX = rPolyPolygonShape3DRetval.SequenceX.getArray();
551 com::sun::star::drawing::DoubleSequence* pOuterSequenceY = rPolyPolygonShape3DRetval.SequenceY.getArray();
552 com::sun::star::drawing::DoubleSequence* pOuterSequenceZ = rPolyPolygonShape3DRetval.SequenceZ.getArray();
554 for(sal_uInt32 a(0); a < nPolygonCount; a++)
556 const basegfx::B3DPolygon aPoly(rPolyPolygonSource.getB3DPolygon(a));
557 const sal_uInt32 nPointCount(aPoly.count());
559 if(nPointCount)
561 const bool bIsClosed(aPoly.isClosed());
562 const sal_uInt32 nTargetCount(bIsClosed ? nPointCount + 1 : nPointCount);
563 pOuterSequenceX->realloc(nTargetCount);
564 pOuterSequenceY->realloc(nTargetCount);
565 pOuterSequenceZ->realloc(nTargetCount);
567 double* pInnerSequenceX = pOuterSequenceX->getArray();
568 double* pInnerSequenceY = pOuterSequenceY->getArray();
569 double* pInnerSequenceZ = pOuterSequenceZ->getArray();
571 for(sal_uInt32 b(0); b < nPointCount; b++)
573 const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(b));
575 *pInnerSequenceX++ = aPoint.getX();
576 *pInnerSequenceY++ = aPoint.getY();
577 *pInnerSequenceZ++ = aPoint.getZ();
580 if(bIsClosed)
582 const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(0));
584 *pInnerSequenceX++ = aPoint.getX();
585 *pInnerSequenceY++ = aPoint.getY();
586 *pInnerSequenceZ++ = aPoint.getZ();
589 else
591 pOuterSequenceX->realloc(0);
592 pOuterSequenceY->realloc(0);
593 pOuterSequenceZ->realloc(0);
596 pOuterSequenceX++;
597 pOuterSequenceY++;
598 pOuterSequenceZ++;
601 else
603 rPolyPolygonShape3DRetval.SequenceX.realloc(0);
604 rPolyPolygonShape3DRetval.SequenceY.realloc(0);
605 rPolyPolygonShape3DRetval.SequenceZ.realloc(0);
609 } // end of namespace tools
610 } // end of namespace basegfx
612 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */