Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / basegfx / source / polygon / b3dpolypolygontools.cxx
blob83241d8bfa872f1c576e34de2b102df9bba124e6
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 <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 <numeric>
27 #include <basegfx/matrix/b3dhommatrix.hxx>
28 #include <basegfx/numeric/ftools.hxx>
29 #include <com/sun/star/drawing/DoubleSequence.hpp>
31 //////////////////////////////////////////////////////////////////////////////
32 // predefines
33 #define nMinSegments sal_uInt32(1)
34 #define nMaxSegments sal_uInt32(512)
36 //////////////////////////////////////////////////////////////////////////////
38 namespace basegfx
40 namespace tools
42 // B3DPolyPolygon tools
43 B3DRange getRange(const B3DPolyPolygon& rCandidate)
45 B3DRange aRetval;
46 const sal_uInt32 nPolygonCount(rCandidate.count());
48 for(sal_uInt32 a(0L); a < nPolygonCount; a++)
50 B3DPolygon aCandidate = rCandidate.getB3DPolygon(a);
51 aRetval.expand(getRange(aCandidate));
54 return aRetval;
57 namespace
59 struct theUnitCubePolyPolygon : public rtl::StaticWithInit<B3DPolyPolygon,
60 theUnitCubePolyPolygon>
62 B3DPolyPolygon operator()()
64 B3DPolyPolygon aRetval;
65 B3DPolygon aTemp;
66 aTemp.append(B3DPoint(0.0, 0.0, 1.0));
67 aTemp.append(B3DPoint(0.0, 1.0, 1.0));
68 aTemp.append(B3DPoint(1.0, 1.0, 1.0));
69 aTemp.append(B3DPoint(1.0, 0.0, 1.0));
70 aTemp.setClosed(true);
71 aRetval.append(aTemp);
73 aTemp.clear();
74 aTemp.append(B3DPoint(0.0, 0.0, 0.0));
75 aTemp.append(B3DPoint(0.0, 1.0, 0.0));
76 aTemp.append(B3DPoint(1.0, 1.0, 0.0));
77 aTemp.append(B3DPoint(1.0, 0.0, 0.0));
78 aTemp.setClosed(true);
79 aRetval.append(aTemp);
81 aTemp.clear();
82 aTemp.append(B3DPoint(0.0, 0.0, 0.0));
83 aTemp.append(B3DPoint(0.0, 0.0, 1.0));
84 aRetval.append(aTemp);
86 aTemp.clear();
87 aTemp.append(B3DPoint(0.0, 1.0, 0.0));
88 aTemp.append(B3DPoint(0.0, 1.0, 1.0));
89 aRetval.append(aTemp);
91 aTemp.clear();
92 aTemp.append(B3DPoint(1.0, 1.0, 0.0));
93 aTemp.append(B3DPoint(1.0, 1.0, 1.0));
94 aRetval.append(aTemp);
96 aTemp.clear();
97 aTemp.append(B3DPoint(1.0, 0.0, 0.0));
98 aTemp.append(B3DPoint(1.0, 0.0, 1.0));
99 aRetval.append(aTemp);
100 return aRetval;
105 B3DPolyPolygon createUnitCubePolyPolygon()
107 return theUnitCubePolyPolygon::get();
110 namespace
112 struct theUnitCubeFillPolyPolygon : public rtl::StaticWithInit<B3DPolyPolygon,
113 theUnitCubeFillPolyPolygon>
115 B3DPolyPolygon operator()()
117 B3DPolyPolygon aRetval;
118 B3DPolygon aTemp;
120 // all points
121 const B3DPoint A(0.0, 0.0, 0.0);
122 const B3DPoint B(0.0, 1.0, 0.0);
123 const B3DPoint C(1.0, 1.0, 0.0);
124 const B3DPoint D(1.0, 0.0, 0.0);
125 const B3DPoint E(0.0, 0.0, 1.0);
126 const B3DPoint F(0.0, 1.0, 1.0);
127 const B3DPoint G(1.0, 1.0, 1.0);
128 const B3DPoint H(1.0, 0.0, 1.0);
130 // create bottom
131 aTemp.append(D);
132 aTemp.append(A);
133 aTemp.append(E);
134 aTemp.append(H);
135 aTemp.setClosed(true);
136 aRetval.append(aTemp);
138 // create front
139 aTemp.clear();
140 aTemp.append(B);
141 aTemp.append(A);
142 aTemp.append(D);
143 aTemp.append(C);
144 aTemp.setClosed(true);
145 aRetval.append(aTemp);
147 // create left
148 aTemp.clear();
149 aTemp.append(E);
150 aTemp.append(A);
151 aTemp.append(B);
152 aTemp.append(F);
153 aTemp.setClosed(true);
154 aRetval.append(aTemp);
156 // create top
157 aTemp.clear();
158 aTemp.append(C);
159 aTemp.append(G);
160 aTemp.append(F);
161 aTemp.append(B);
162 aTemp.setClosed(true);
163 aRetval.append(aTemp);
165 // create right
166 aTemp.clear();
167 aTemp.append(H);
168 aTemp.append(G);
169 aTemp.append(C);
170 aTemp.append(D);
171 aTemp.setClosed(true);
172 aRetval.append(aTemp);
174 // create back
175 aTemp.clear();
176 aTemp.append(F);
177 aTemp.append(G);
178 aTemp.append(H);
179 aTemp.append(E);
180 aTemp.setClosed(true);
181 aRetval.append(aTemp);
182 return aRetval;
187 B3DPolyPolygon createUnitCubeFillPolyPolygon()
189 return theUnitCubeFillPolyPolygon::get();
192 B3DPolyPolygon createCubePolyPolygonFromB3DRange( const B3DRange& rRange)
194 B3DPolyPolygon aRetval;
196 if(!rRange.isEmpty())
198 aRetval = createUnitCubePolyPolygon();
199 B3DHomMatrix aTrans;
200 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
201 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
202 aRetval.transform(aTrans);
203 aRetval.removeDoublePoints();
206 return aRetval;
209 B3DPolyPolygon createCubeFillPolyPolygonFromB3DRange( const B3DRange& rRange)
211 B3DPolyPolygon aRetval;
213 if(!rRange.isEmpty())
215 aRetval = createUnitCubeFillPolyPolygon();
216 B3DHomMatrix aTrans;
217 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
218 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
219 aRetval.transform(aTrans);
220 aRetval.removeDoublePoints();
223 return aRetval;
226 // helper for getting the 3D Point from given cartesian coordiantes. fVer is defined from
227 // [F_PI2 .. -F_PI2], fHor from [0.0 .. F_2PI]
228 inline B3DPoint getPointFromCartesian(double fVer, double fHor)
230 const double fCosHor(cos(fHor));
231 return B3DPoint(fCosHor * cos(fVer), sin(fHor), fCosHor * -sin(fVer));
234 B3DPolyPolygon createUnitSpherePolyPolygon(
235 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
236 double fVerStart, double fVerStop,
237 double fHorStart, double fHorStop)
239 B3DPolyPolygon aRetval;
240 sal_uInt32 a, b;
242 if(!nHorSeg)
244 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
247 // min/max limitations
248 nHorSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nHorSeg));
250 if(!nVerSeg)
252 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
255 // min/max limitations
256 nVerSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nVerSeg));
258 // create constants
259 const double fVerDiffPerStep((fVerStop - fVerStart) / (double)nVerSeg);
260 const double fHorDiffPerStep((fHorStop - fHorStart) / (double)nHorSeg);
261 bool bHorClosed(fTools::equal(fHorStop - fHorStart, F_2PI));
262 bool bVerFromTop(fTools::equal(fVerStart, F_PI2));
263 bool bVerToBottom(fTools::equal(fVerStop, -F_PI2));
265 // create horizontal rings
266 const sal_uInt32 nLoopVerInit(bVerFromTop ? 1L : 0L);
267 const sal_uInt32 nLoopVerLimit(bVerToBottom ? nVerSeg : nVerSeg + 1L);
268 const sal_uInt32 nLoopHorLimit(bHorClosed ? nHorSeg : nHorSeg + 1L);
270 for(a = nLoopVerInit; a < nLoopVerLimit; a++)
272 const double fVer(fVerStart + ((double)(a) * fVerDiffPerStep));
273 B3DPolygon aNew;
275 for(b = 0L; b < nLoopHorLimit; b++)
277 const double fHor(fHorStart + ((double)(b) * fHorDiffPerStep));
278 aNew.append(getPointFromCartesian(fHor, fVer));
281 aNew.setClosed(bHorClosed);
282 aRetval.append(aNew);
285 // create vertical half-rings
286 for(a = 0L; a < nLoopHorLimit; a++)
288 const double fHor(fHorStart + ((double)(a) * fHorDiffPerStep));
289 B3DPolygon aNew;
291 if(bVerFromTop)
293 aNew.append(B3DPoint(0.0, 1.0, 0.0));
296 for(b = nLoopVerInit; b < nLoopVerLimit; b++)
298 const double fVer(fVerStart + ((double)(b) * fVerDiffPerStep));
299 aNew.append(getPointFromCartesian(fHor, fVer));
302 if(bVerToBottom)
304 aNew.append(B3DPoint(0.0, -1.0, 0.0));
307 aRetval.append(aNew);
310 return aRetval;
313 B3DPolyPolygon createSpherePolyPolygonFromB3DRange( const B3DRange& rRange,
314 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
315 double fVerStart, double fVerStop,
316 double fHorStart, double fHorStop)
318 B3DPolyPolygon aRetval(createUnitSpherePolyPolygon(nHorSeg, nVerSeg, fVerStart, fVerStop, fHorStart, fHorStop));
320 if(aRetval.count())
322 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
323 B3DHomMatrix aTrans;
324 aTrans.translate(1.0, 1.0, 1.0);
325 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
326 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
327 aRetval.transform(aTrans);
330 return aRetval;
333 B3DPolyPolygon createUnitSphereFillPolyPolygon(
334 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
335 bool bNormals,
336 double fVerStart, double fVerStop,
337 double fHorStart, double fHorStop)
339 B3DPolyPolygon aRetval;
341 if(!nHorSeg)
343 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
346 // min/max limitations
347 nHorSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nHorSeg));
349 if(!nVerSeg)
351 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
354 // min/max limitations
355 nVerSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nVerSeg));
357 // vertical loop
358 for(sal_uInt32 a(0L); a < nVerSeg; a++)
360 const double fVer(fVerStart + (((fVerStop - fVerStart) * a) / nVerSeg));
361 const double fVer2(fVerStart + (((fVerStop - fVerStart) * (a + 1)) / nVerSeg));
363 // horizontal loop
364 for(sal_uInt32 b(0L); b < nHorSeg; b++)
366 const double fHor(fHorStart + (((fHorStop - fHorStart) * b) / nHorSeg));
367 const double fHor2(fHorStart + (((fHorStop - fHorStart) * (b + 1)) / nHorSeg));
368 B3DPolygon aNew;
370 aNew.append(getPointFromCartesian(fHor, fVer));
371 aNew.append(getPointFromCartesian(fHor2, fVer));
372 aNew.append(getPointFromCartesian(fHor2, fVer2));
373 aNew.append(getPointFromCartesian(fHor, fVer2));
375 if(bNormals)
377 for(sal_uInt32 c(0L); c < aNew.count(); c++)
379 aNew.setNormal(c, ::basegfx::B3DVector(aNew.getB3DPoint(c)));
383 aNew.setClosed(true);
384 aRetval.append(aNew);
388 return aRetval;
391 B3DPolyPolygon createSphereFillPolyPolygonFromB3DRange( const B3DRange& rRange,
392 sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
393 bool bNormals,
394 double fVerStart, double fVerStop,
395 double fHorStart, double fHorStop)
397 B3DPolyPolygon aRetval(createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, bNormals, fVerStart, fVerStop, fHorStart, fHorStop));
399 if(aRetval.count())
401 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
402 B3DHomMatrix aTrans;
403 aTrans.translate(1.0, 1.0, 1.0);
404 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
405 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
406 aRetval.transform(aTrans);
409 return aRetval;
412 B3DPolyPolygon applyDefaultNormalsSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter)
414 B3DPolyPolygon aRetval;
416 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
418 aRetval.append(applyDefaultNormalsSphere(rCandidate.getB3DPolygon(a), rCenter));
421 return aRetval;
424 B3DPolyPolygon invertNormals( const B3DPolyPolygon& rCandidate)
426 B3DPolyPolygon aRetval;
428 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
430 aRetval.append(invertNormals(rCandidate.getB3DPolygon(a)));
433 return aRetval;
436 B3DPolyPolygon applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
438 B3DPolyPolygon aRetval;
440 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
442 aRetval.append(applyDefaultTextureCoordinatesParallel(rCandidate.getB3DPolygon(a), rRange, bChangeX, bChangeY));
445 return aRetval;
448 B3DPolyPolygon applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
450 B3DPolyPolygon aRetval;
452 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
454 aRetval.append(applyDefaultTextureCoordinatesSphere(rCandidate.getB3DPolygon(a), rCenter, bChangeX, bChangeY));
457 return aRetval;
460 bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder)
462 const sal_uInt32 nPolygonCount(rCandidate.count());
464 if(1L == nPolygonCount)
466 return isInside(rCandidate.getB3DPolygon(0), rPoint, bWithBorder);
468 else
470 sal_Int32 nInsideCount(0);
472 for(sal_uInt32 a(0); a < nPolygonCount; a++)
474 const B3DPolygon aPolygon(rCandidate.getB3DPolygon(a));
475 const bool bInside(isInside(aPolygon, rPoint, bWithBorder));
477 if(bInside)
479 nInsideCount++;
483 return (nInsideCount % 2L);
487 //////////////////////////////////////////////////////////////////////
488 // comparators with tolerance for 3D PolyPolygons
490 bool equal(const B3DPolyPolygon& rCandidateA, const B3DPolyPolygon& rCandidateB, const double& rfSmallValue)
492 const sal_uInt32 nPolygonCount(rCandidateA.count());
494 if(nPolygonCount != rCandidateB.count())
495 return false;
497 for(sal_uInt32 a(0); a < nPolygonCount; a++)
499 const B3DPolygon aCandidate(rCandidateA.getB3DPolygon(a));
501 if(!equal(aCandidate, rCandidateB.getB3DPolygon(a), rfSmallValue))
502 return false;
505 return true;
508 bool equal(const B3DPolyPolygon& rCandidateA, const B3DPolyPolygon& rCandidateB)
510 const double fSmallValue(fTools::getSmallValue());
512 return equal(rCandidateA, rCandidateB, fSmallValue);
515 /// converters for com::sun::star::drawing::PolyPolygonShape3D
516 B3DPolyPolygon UnoPolyPolygonShape3DToB3DPolyPolygon(
517 const com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygonShape3DSource,
518 bool bCheckClosed)
520 B3DPolyPolygon aRetval;
521 const sal_Int32 nOuterSequenceCount(rPolyPolygonShape3DSource.SequenceX.getLength());
523 if(nOuterSequenceCount)
525 OSL_ENSURE(nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceY.getLength()
526 && nOuterSequenceCount == rPolyPolygonShape3DSource.SequenceZ.getLength(),
527 "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)");
529 const com::sun::star::drawing::DoubleSequence* pInnerSequenceX = rPolyPolygonShape3DSource.SequenceX.getConstArray();
530 const com::sun::star::drawing::DoubleSequence* pInnerSequenceY = rPolyPolygonShape3DSource.SequenceY.getConstArray();
531 const com::sun::star::drawing::DoubleSequence* pInnerSequenceZ = rPolyPolygonShape3DSource.SequenceZ.getConstArray();
533 for(sal_Int32 a(0); a < nOuterSequenceCount; a++)
535 basegfx::B3DPolygon aNewPolygon;
536 const sal_Int32 nInnerSequenceCount(pInnerSequenceX->getLength());
537 OSL_ENSURE(nInnerSequenceCount == pInnerSequenceY->getLength()
538 && nInnerSequenceCount == pInnerSequenceZ->getLength(),
539 "UnoPolyPolygonShape3DToB3DPolygon: Not all double sequences have the same length (!)");
541 const double* pArrayX = pInnerSequenceX->getConstArray();
542 const double* pArrayY = pInnerSequenceY->getConstArray();
543 const double* pArrayZ = pInnerSequenceZ->getConstArray();
545 for(sal_Int32 b(0); b < nInnerSequenceCount; b++)
547 aNewPolygon.append(basegfx::B3DPoint(*pArrayX++,*pArrayY++,*pArrayZ++));
550 pInnerSequenceX++;
551 pInnerSequenceY++;
552 pInnerSequenceZ++;
554 // #i101520# correction is needed for imported polygons of old format,
555 // see callers
556 if(bCheckClosed)
558 basegfx::tools::checkClosed(aNewPolygon);
561 aRetval.append(aNewPolygon);
565 return aRetval;
568 void B3DPolyPolygonToUnoPolyPolygonShape3D(
569 const B3DPolyPolygon& rPolyPolygonSource,
570 com::sun::star::drawing::PolyPolygonShape3D& rPolyPolygonShape3DRetval)
572 const sal_uInt32 nPolygonCount(rPolyPolygonSource.count());
574 if(nPolygonCount)
576 rPolyPolygonShape3DRetval.SequenceX.realloc(nPolygonCount);
577 rPolyPolygonShape3DRetval.SequenceY.realloc(nPolygonCount);
578 rPolyPolygonShape3DRetval.SequenceZ.realloc(nPolygonCount);
580 com::sun::star::drawing::DoubleSequence* pOuterSequenceX = rPolyPolygonShape3DRetval.SequenceX.getArray();
581 com::sun::star::drawing::DoubleSequence* pOuterSequenceY = rPolyPolygonShape3DRetval.SequenceY.getArray();
582 com::sun::star::drawing::DoubleSequence* pOuterSequenceZ = rPolyPolygonShape3DRetval.SequenceZ.getArray();
584 for(sal_uInt32 a(0); a < nPolygonCount; a++)
586 const basegfx::B3DPolygon aPoly(rPolyPolygonSource.getB3DPolygon(a));
587 const sal_uInt32 nPointCount(aPoly.count());
589 if(nPointCount)
591 const bool bIsClosed(aPoly.isClosed());
592 const sal_uInt32 nTargetCount(bIsClosed ? nPointCount + 1 : nPointCount);
593 pOuterSequenceX->realloc(nTargetCount);
594 pOuterSequenceY->realloc(nTargetCount);
595 pOuterSequenceZ->realloc(nTargetCount);
597 double* pInnerSequenceX = pOuterSequenceX->getArray();
598 double* pInnerSequenceY = pOuterSequenceY->getArray();
599 double* pInnerSequenceZ = pOuterSequenceZ->getArray();
601 for(sal_uInt32 b(0); b < nPointCount; b++)
603 const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(b));
605 *pInnerSequenceX++ = aPoint.getX();
606 *pInnerSequenceY++ = aPoint.getY();
607 *pInnerSequenceZ++ = aPoint.getZ();
610 if(bIsClosed)
612 const basegfx::B3DPoint aPoint(aPoly.getB3DPoint(0));
614 *pInnerSequenceX++ = aPoint.getX();
615 *pInnerSequenceY++ = aPoint.getY();
616 *pInnerSequenceZ++ = aPoint.getZ();
619 else
621 pOuterSequenceX->realloc(0);
622 pOuterSequenceY->realloc(0);
623 pOuterSequenceZ->realloc(0);
626 pOuterSequenceX++;
627 pOuterSequenceY++;
628 pOuterSequenceZ++;
631 else
633 rPolyPolygonShape3DRetval.SequenceX.realloc(0);
634 rPolyPolygonShape3DRetval.SequenceY.realloc(0);
635 rPolyPolygonShape3DRetval.SequenceZ.realloc(0);
639 } // end of namespace tools
640 } // end of namespace basegfx
642 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */