Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / basegfx / source / polygon / b3dpolypolygontools.cxx
blob083678726a4d78ef5ab676600b005f12f6b25593
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 <osl/diagnose.h>
21 #include <basegfx/polygon/b3dpolypolygontools.hxx>
22 #include <basegfx/range/b3drange.hxx>
23 #include <basegfx/polygon/b3dpolypolygon.hxx>
24 #include <basegfx/polygon/b3dpolygon.hxx>
25 #include <basegfx/polygon/b3dpolygontools.hxx>
26 #include <basegfx/matrix/b3dhommatrix.hxx>
27 #include <basegfx/numeric/ftools.hxx>
28 #include <com/sun/star/drawing/DoubleSequence.hpp>
29 #include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
31 // predefines
32 #define nMinSegments sal_uInt32(1)
33 #define nMaxSegments sal_uInt32(512)
35 namespace basegfx
37 namespace utils
39 // B3DPolyPolygon tools
40 B3DRange getRange(const B3DPolyPolygon& rCandidate)
42 B3DRange aRetval;
43 const sal_uInt32 nPolygonCount(rCandidate.count());
45 for(sal_uInt32 a(0); a < nPolygonCount; a++)
47 const B3DPolygon& aCandidate = rCandidate.getB3DPolygon(a);
48 aRetval.expand(getRange(aCandidate));
51 return aRetval;
54 B3DPolyPolygon const & createUnitCubePolyPolygon()
56 static auto const singleton = [] {
57 B3DPolyPolygon aRetval;
58 B3DPolygon aTemp;
59 aTemp.append(B3DPoint(0.0, 0.0, 1.0));
60 aTemp.append(B3DPoint(0.0, 1.0, 1.0));
61 aTemp.append(B3DPoint(1.0, 1.0, 1.0));
62 aTemp.append(B3DPoint(1.0, 0.0, 1.0));
63 aTemp.setClosed(true);
64 aRetval.append(aTemp);
66 aTemp.clear();
67 aTemp.append(B3DPoint(0.0, 0.0, 0.0));
68 aTemp.append(B3DPoint(0.0, 1.0, 0.0));
69 aTemp.append(B3DPoint(1.0, 1.0, 0.0));
70 aTemp.append(B3DPoint(1.0, 0.0, 0.0));
71 aTemp.setClosed(true);
72 aRetval.append(aTemp);
74 aTemp.clear();
75 aTemp.append(B3DPoint(0.0, 0.0, 0.0));
76 aTemp.append(B3DPoint(0.0, 0.0, 1.0));
77 aRetval.append(aTemp);
79 aTemp.clear();
80 aTemp.append(B3DPoint(0.0, 1.0, 0.0));
81 aTemp.append(B3DPoint(0.0, 1.0, 1.0));
82 aRetval.append(aTemp);
84 aTemp.clear();
85 aTemp.append(B3DPoint(1.0, 1.0, 0.0));
86 aTemp.append(B3DPoint(1.0, 1.0, 1.0));
87 aRetval.append(aTemp);
89 aTemp.clear();
90 aTemp.append(B3DPoint(1.0, 0.0, 0.0));
91 aTemp.append(B3DPoint(1.0, 0.0, 1.0));
92 aRetval.append(aTemp);
93 return aRetval;
94 }();
95 return singleton;
98 B3DPolyPolygon const & createUnitCubeFillPolyPolygon()
100 static auto const singleton = [] {
101 B3DPolyPolygon aRetval;
102 B3DPolygon aTemp;
104 // all points
105 const B3DPoint A(0.0, 0.0, 0.0);
106 const B3DPoint B(0.0, 1.0, 0.0);
107 const B3DPoint C(1.0, 1.0, 0.0);
108 const B3DPoint D(1.0, 0.0, 0.0);
109 const B3DPoint E(0.0, 0.0, 1.0);
110 const B3DPoint F(0.0, 1.0, 1.0);
111 const B3DPoint G(1.0, 1.0, 1.0);
112 const B3DPoint H(1.0, 0.0, 1.0);
114 // create bottom
115 aTemp.append(D);
116 aTemp.append(A);
117 aTemp.append(E);
118 aTemp.append(H);
119 aTemp.setClosed(true);
120 aRetval.append(aTemp);
122 // create front
123 aTemp.clear();
124 aTemp.append(B);
125 aTemp.append(A);
126 aTemp.append(D);
127 aTemp.append(C);
128 aTemp.setClosed(true);
129 aRetval.append(aTemp);
131 // create left
132 aTemp.clear();
133 aTemp.append(E);
134 aTemp.append(A);
135 aTemp.append(B);
136 aTemp.append(F);
137 aTemp.setClosed(true);
138 aRetval.append(aTemp);
140 // create top
141 aTemp.clear();
142 aTemp.append(C);
143 aTemp.append(G);
144 aTemp.append(F);
145 aTemp.append(B);
146 aTemp.setClosed(true);
147 aRetval.append(aTemp);
149 // create right
150 aTemp.clear();
151 aTemp.append(H);
152 aTemp.append(G);
153 aTemp.append(C);
154 aTemp.append(D);
155 aTemp.setClosed(true);
156 aRetval.append(aTemp);
158 // create back
159 aTemp.clear();
160 aTemp.append(F);
161 aTemp.append(G);
162 aTemp.append(H);
163 aTemp.append(E);
164 aTemp.setClosed(true);
165 aRetval.append(aTemp);
166 return aRetval;
167 }();
168 return singleton;
171 B3DPolyPolygon createCubePolyPolygonFromB3DRange( const B3DRange& rRange)
173 B3DPolyPolygon aRetval;
175 if(!rRange.isEmpty())
177 aRetval = createUnitCubePolyPolygon();
178 B3DHomMatrix aTrans;
179 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
180 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
181 aRetval.transform(aTrans);
182 aRetval.removeDoublePoints();
185 return aRetval;
188 B3DPolyPolygon createCubeFillPolyPolygonFromB3DRange( const B3DRange& rRange)
190 B3DPolyPolygon aRetval;
192 if(!rRange.isEmpty())
194 aRetval = createUnitCubeFillPolyPolygon();
195 B3DHomMatrix aTrans;
196 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
197 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
198 aRetval.transform(aTrans);
199 aRetval.removeDoublePoints();
202 return aRetval;
205 // helper for getting the 3D Point from given cartesian coordinates. fHor is defined from
206 // [F_PI2 .. -F_PI2], fVer from [0.0 .. F_2PI]
207 static B3DPoint getPointFromCartesian(double fHor, double fVer)
209 const double fCosVer(cos(fVer));
210 return B3DPoint(fCosVer * cos(fHor), sin(fVer), fCosVer * -sin(fHor));
213 B3DPolyPolygon createUnitSpherePolyPolygon(
214 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
215 double fVerStart, double fVerStop,
216 double fHorStart, double fHorStop)
218 B3DPolyPolygon aRetval;
219 sal_uInt32 a, b;
221 if(!nHorSeg)
223 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
226 // min/max limitations
227 nHorSeg = std::min(nMaxSegments, std::max(nMinSegments, nHorSeg));
229 if(!nVerSeg)
231 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
234 // min/max limitations
235 nVerSeg = std::min(nMaxSegments, std::max(nMinSegments, nVerSeg));
237 // create constants
238 const double fVerDiffPerStep((fVerStop - fVerStart) / static_cast<double>(nVerSeg));
239 const double fHorDiffPerStep((fHorStop - fHorStart) / static_cast<double>(nHorSeg));
240 bool bHorClosed(fTools::equal(fHorStop - fHorStart, F_2PI));
241 bool bVerFromTop(fTools::equal(fVerStart, F_PI2));
242 bool bVerToBottom(fTools::equal(fVerStop, -F_PI2));
244 // create horizontal rings
245 const sal_uInt32 nLoopVerInit(bVerFromTop ? 1 : 0);
246 const sal_uInt32 nLoopVerLimit(bVerToBottom ? nVerSeg : nVerSeg + 1);
247 const sal_uInt32 nLoopHorLimit(bHorClosed ? nHorSeg : nHorSeg + 1);
249 for(a = nLoopVerInit; a < nLoopVerLimit; a++)
251 const double fVer(fVerStart + (static_cast<double>(a) * fVerDiffPerStep));
252 B3DPolygon aNew;
254 for(b = 0; b < nLoopHorLimit; b++)
256 const double fHor(fHorStart + (static_cast<double>(b) * fHorDiffPerStep));
257 aNew.append(getPointFromCartesian(fHor, fVer));
260 aNew.setClosed(bHorClosed);
261 aRetval.append(aNew);
264 // create vertical half-rings
265 for(a = 0; a < nLoopHorLimit; a++)
267 const double fHor(fHorStart + (static_cast<double>(a) * fHorDiffPerStep));
268 B3DPolygon aNew;
270 if(bVerFromTop)
272 aNew.append(B3DPoint(0.0, 1.0, 0.0));
275 for(b = nLoopVerInit; b < nLoopVerLimit; b++)
277 const double fVer(fVerStart + (static_cast<double>(b) * fVerDiffPerStep));
278 aNew.append(getPointFromCartesian(fHor, fVer));
281 if(bVerToBottom)
283 aNew.append(B3DPoint(0.0, -1.0, 0.0));
286 aRetval.append(aNew);
289 return aRetval;
292 B3DPolyPolygon createSpherePolyPolygonFromB3DRange( const B3DRange& rRange,
293 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
294 double fVerStart, double fVerStop,
295 double fHorStart, double fHorStop)
297 B3DPolyPolygon aRetval(createUnitSpherePolyPolygon(nHorSeg, nVerSeg, fVerStart, fVerStop, fHorStart, fHorStop));
299 if(aRetval.count())
301 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
302 B3DHomMatrix aTrans;
303 aTrans.translate(1.0, 1.0, 1.0);
304 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
305 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
306 aRetval.transform(aTrans);
309 return aRetval;
312 B3DPolyPolygon createUnitSphereFillPolyPolygon(
313 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
314 bool bNormals,
315 double fVerStart, double fVerStop,
316 double fHorStart, double fHorStop)
318 B3DPolyPolygon aRetval;
320 if(!nHorSeg)
322 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
325 // min/max limitations
326 nHorSeg = std::min(nMaxSegments, std::max(nMinSegments, nHorSeg));
328 if(!nVerSeg)
330 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
333 // min/max limitations
334 nVerSeg = std::min(nMaxSegments, std::max(nMinSegments, nVerSeg));
336 // vertical loop
337 for(sal_uInt32 a(0); a < nVerSeg; a++)
339 const double fVer1(fVerStart + (((fVerStop - fVerStart) * a) / nVerSeg));
340 const double fVer2(fVerStart + (((fVerStop - fVerStart) * (a + 1)) / nVerSeg));
342 // horizontal loop
343 for(sal_uInt32 b(0); b < nHorSeg; b++)
345 const double fHor1(fHorStart + (((fHorStop - fHorStart) * b) / nHorSeg));
346 const double fHor2(fHorStart + (((fHorStop - fHorStart) * (b + 1)) / nHorSeg));
347 B3DPolygon aNew;
349 aNew.append(getPointFromCartesian(fHor1, fVer1));
350 aNew.append(getPointFromCartesian(fHor2, fVer1));
351 aNew.append(getPointFromCartesian(fHor2, fVer2));
352 aNew.append(getPointFromCartesian(fHor1, fVer2));
354 if(bNormals)
356 for(sal_uInt32 c(0); c < aNew.count(); c++)
358 aNew.setNormal(c, ::basegfx::B3DVector(aNew.getB3DPoint(c)));
362 aNew.setClosed(true);
363 aRetval.append(aNew);
367 return aRetval;
370 B3DPolyPolygon createSphereFillPolyPolygonFromB3DRange( const B3DRange& rRange,
371 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
372 bool bNormals,
373 double fVerStart, double fVerStop,
374 double fHorStart, double fHorStop)
376 B3DPolyPolygon aRetval(createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, bNormals, fVerStart, fVerStop, fHorStart, fHorStop));
378 if(aRetval.count())
380 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
381 B3DHomMatrix aTrans;
382 aTrans.translate(1.0, 1.0, 1.0);
383 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
384 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
385 aRetval.transform(aTrans);
388 return aRetval;
391 B3DPolyPolygon applyDefaultNormalsSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter)
393 B3DPolyPolygon aRetval;
395 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
397 aRetval.append(applyDefaultNormalsSphere(rCandidate.getB3DPolygon(a), rCenter));
400 return aRetval;
403 B3DPolyPolygon invertNormals( const B3DPolyPolygon& rCandidate)
405 B3DPolyPolygon aRetval;
407 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
409 aRetval.append(invertNormals(rCandidate.getB3DPolygon(a)));
412 return aRetval;
415 B3DPolyPolygon applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
417 B3DPolyPolygon aRetval;
419 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
421 aRetval.append(applyDefaultTextureCoordinatesParallel(rCandidate.getB3DPolygon(a), rRange, bChangeX, bChangeY));
424 return aRetval;
427 B3DPolyPolygon applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
429 B3DPolyPolygon aRetval;
431 for(sal_uInt32 a(0); a < rCandidate.count(); a++)
433 aRetval.append(applyDefaultTextureCoordinatesSphere(rCandidate.getB3DPolygon(a), rCenter, bChangeX, bChangeY));
436 return aRetval;
439 bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint)
441 const sal_uInt32 nPolygonCount(rCandidate.count());
443 if(nPolygonCount == 1)
445 return isInside(rCandidate.getB3DPolygon(0), rPoint, false/*bWithBorder*/);
447 else
449 sal_Int32 nInsideCount(0);
451 for(sal_uInt32 a(0); a < nPolygonCount; a++)
453 const B3DPolygon& aPolygon(rCandidate.getB3DPolygon(a));
454 const bool bInside(isInside(aPolygon, rPoint, false/*bWithBorder*/));
456 if(bInside)
458 nInsideCount++;
462 return (nInsideCount % 2);
466 /// converters for css::drawing::PolyPolygonShape3D
467 B3DPolyPolygon UnoPolyPolygonShape3DToB3DPolyPolygon(
468 const css::drawing::PolyPolygonShape3D& rPolyPolygonShape3DSource)
470 B3DPolyPolygon aRetval;
471 const sal_Int32 nOuterSequenceCount(rPolyPolygonShape3DSource.SequenceX.getLength());
473 if(nOuterSequenceCount)
475 OSL_ENSURE(nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceY.getLength()
476 && nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceZ.getLength(),
477 "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)");
479 const css::drawing::DoubleSequence* pInnerSequenceX = rPolyPolygonShape3DSource.SequenceX.getConstArray();
480 const css::drawing::DoubleSequence* pInnerSequenceY = rPolyPolygonShape3DSource.SequenceY.getConstArray();
481 const css::drawing::DoubleSequence* pInnerSequenceZ = rPolyPolygonShape3DSource.SequenceZ.getConstArray();
483 for(sal_Int32 a(0); a < nOuterSequenceCount; a++)
485 basegfx::B3DPolygon aNewPolygon;
486 const sal_Int32 nInnerSequenceCount(pInnerSequenceX->getLength());
487 OSL_ENSURE(nInnerSequenceCount == pInnerSequenceY->getLength()
488 && nInnerSequenceCount == pInnerSequenceZ->getLength(),
489 "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)");
491 const double* pArrayX = pInnerSequenceX->getConstArray();
492 const double* pArrayY = pInnerSequenceY->getConstArray();
493 const double* pArrayZ = pInnerSequenceZ->getConstArray();
495 for(sal_Int32 b(0); b < nInnerSequenceCount; b++)
497 aNewPolygon.append(basegfx::B3DPoint(*pArrayX++,*pArrayY++,*pArrayZ++));
500 pInnerSequenceX++;
501 pInnerSequenceY++;
502 pInnerSequenceZ++;
504 // #i101520# correction is needed for imported polygons of old format,
505 // see callers
506 basegfx::utils::checkClosed(aNewPolygon);
508 aRetval.append(aNewPolygon);
512 return aRetval;
515 void B3DPolyPolygonToUnoPolyPolygonShape3D(
516 const B3DPolyPolygon& rPolyPolygonSource,
517 css::drawing::PolyPolygonShape3D& rPolyPolygonShape3DRetval)
519 const sal_uInt32 nPolygonCount(rPolyPolygonSource.count());
521 if(nPolygonCount)
523 rPolyPolygonShape3DRetval.SequenceX.realloc(nPolygonCount);
524 rPolyPolygonShape3DRetval.SequenceY.realloc(nPolygonCount);
525 rPolyPolygonShape3DRetval.SequenceZ.realloc(nPolygonCount);
527 css::drawing::DoubleSequence* pOuterSequenceX = rPolyPolygonShape3DRetval.SequenceX.getArray();
528 css::drawing::DoubleSequence* pOuterSequenceY = rPolyPolygonShape3DRetval.SequenceY.getArray();
529 css::drawing::DoubleSequence* pOuterSequenceZ = rPolyPolygonShape3DRetval.SequenceZ.getArray();
531 for(sal_uInt32 a(0); a < nPolygonCount; a++)
533 const basegfx::B3DPolygon& aPoly(rPolyPolygonSource.getB3DPolygon(a));
534 const sal_uInt32 nPointCount(aPoly.count());
536 if(nPointCount)
538 const bool bIsClosed(aPoly.isClosed());
539 const sal_uInt32 nTargetCount(bIsClosed ? nPointCount + 1 : nPointCount);
540 pOuterSequenceX->realloc(nTargetCount);
541 pOuterSequenceY->realloc(nTargetCount);
542 pOuterSequenceZ->realloc(nTargetCount);
544 double* pInnerSequenceX = pOuterSequenceX->getArray();
545 double* pInnerSequenceY = pOuterSequenceY->getArray();
546 double* pInnerSequenceZ = pOuterSequenceZ->getArray();
548 for(sal_uInt32 b(0); b < nPointCount; b++)
550 const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(b));
552 *pInnerSequenceX++ = aPoint.getX();
553 *pInnerSequenceY++ = aPoint.getY();
554 *pInnerSequenceZ++ = aPoint.getZ();
557 if(bIsClosed)
559 const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(0));
561 *pInnerSequenceX++ = aPoint.getX();
562 *pInnerSequenceY++ = aPoint.getY();
563 *pInnerSequenceZ++ = aPoint.getZ();
566 else
568 pOuterSequenceX->realloc(0);
569 pOuterSequenceY->realloc(0);
570 pOuterSequenceZ->realloc(0);
573 pOuterSequenceX++;
574 pOuterSequenceY++;
575 pOuterSequenceZ++;
578 else
580 rPolyPolygonShape3DRetval.SequenceX.realloc(0);
581 rPolyPolygonShape3DRetval.SequenceY.realloc(0);
582 rPolyPolygonShape3DRetval.SequenceZ.realloc(0);
586 } // end of namespace utils
587 } // end of namespace basegfx
589 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */