1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
27 #include <basegfx/matrix/b3dhommatrix.hxx>
28 #include <basegfx/numeric/ftools.hxx>
29 #include <com/sun/star/drawing/DoubleSequence.hpp>
31 //////////////////////////////////////////////////////////////////////////////
33 #define nMinSegments sal_uInt32(1)
34 #define nMaxSegments sal_uInt32(512)
36 //////////////////////////////////////////////////////////////////////////////
42 // B3DPolyPolygon tools
43 B3DRange
getRange(const B3DPolyPolygon
& rCandidate
)
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
));
59 struct theUnitCubePolyPolygon
: public rtl::StaticWithInit
<B3DPolyPolygon
,
60 theUnitCubePolyPolygon
>
62 B3DPolyPolygon
operator()()
64 B3DPolyPolygon aRetval
;
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
);
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
);
82 aTemp
.append(B3DPoint(0.0, 0.0, 0.0));
83 aTemp
.append(B3DPoint(0.0, 0.0, 1.0));
84 aRetval
.append(aTemp
);
87 aTemp
.append(B3DPoint(0.0, 1.0, 0.0));
88 aTemp
.append(B3DPoint(0.0, 1.0, 1.0));
89 aRetval
.append(aTemp
);
92 aTemp
.append(B3DPoint(1.0, 1.0, 0.0));
93 aTemp
.append(B3DPoint(1.0, 1.0, 1.0));
94 aRetval
.append(aTemp
);
97 aTemp
.append(B3DPoint(1.0, 0.0, 0.0));
98 aTemp
.append(B3DPoint(1.0, 0.0, 1.0));
99 aRetval
.append(aTemp
);
105 B3DPolyPolygon
createUnitCubePolyPolygon()
107 return theUnitCubePolyPolygon::get();
112 struct theUnitCubeFillPolyPolygon
: public rtl::StaticWithInit
<B3DPolyPolygon
,
113 theUnitCubeFillPolyPolygon
>
115 B3DPolyPolygon
operator()()
117 B3DPolyPolygon aRetval
;
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);
135 aTemp
.setClosed(true);
136 aRetval
.append(aTemp
);
144 aTemp
.setClosed(true);
145 aRetval
.append(aTemp
);
153 aTemp
.setClosed(true);
154 aRetval
.append(aTemp
);
162 aTemp
.setClosed(true);
163 aRetval
.append(aTemp
);
171 aTemp
.setClosed(true);
172 aRetval
.append(aTemp
);
180 aTemp
.setClosed(true);
181 aRetval
.append(aTemp
);
187 B3DPolyPolygon
createUnitCubeFillPolyPolygon()
189 return theUnitCubeFillPolyPolygon::get();
192 B3DPolyPolygon
createCubePolyPolygonFromB3DRange( const B3DRange
& rRange
)
194 B3DPolyPolygon aRetval
;
196 if(!rRange
.isEmpty())
198 aRetval
= createUnitCubePolyPolygon();
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();
209 B3DPolyPolygon
createCubeFillPolyPolygonFromB3DRange( const B3DRange
& rRange
)
211 B3DPolyPolygon aRetval
;
213 if(!rRange
.isEmpty())
215 aRetval
= createUnitCubeFillPolyPolygon();
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();
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
;
244 nHorSeg
= fround(fabs(fHorStop
- fHorStart
) / (F_2PI
/ 24.0));
247 // min/max limitations
248 nHorSeg
= ::std::min(nMaxSegments
, ::std::max(nMinSegments
, nHorSeg
));
252 nVerSeg
= fround(fabs(fVerStop
- fVerStart
) / (F_2PI
/ 24.0));
255 // min/max limitations
256 nVerSeg
= ::std::min(nMaxSegments
, ::std::max(nMinSegments
, nVerSeg
));
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
));
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
));
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
));
304 aNew
.append(B3DPoint(0.0, -1.0, 0.0));
307 aRetval
.append(aNew
);
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
));
322 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
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
);
333 B3DPolyPolygon
createUnitSphereFillPolyPolygon(
334 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
336 double fVerStart
, double fVerStop
,
337 double fHorStart
, double fHorStop
)
339 B3DPolyPolygon aRetval
;
343 nHorSeg
= fround(fabs(fHorStop
- fHorStart
) / (F_2PI
/ 24.0));
346 // min/max limitations
347 nHorSeg
= ::std::min(nMaxSegments
, ::std::max(nMinSegments
, nHorSeg
));
351 nVerSeg
= fround(fabs(fVerStop
- fVerStart
) / (F_2PI
/ 24.0));
354 // min/max limitations
355 nVerSeg
= ::std::min(nMaxSegments
, ::std::max(nMinSegments
, nVerSeg
));
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
));
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
));
370 aNew
.append(getPointFromCartesian(fHor
, fVer
));
371 aNew
.append(getPointFromCartesian(fHor2
, fVer
));
372 aNew
.append(getPointFromCartesian(fHor2
, fVer2
));
373 aNew
.append(getPointFromCartesian(fHor
, fVer2
));
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
);
391 B3DPolyPolygon
createSphereFillPolyPolygonFromB3DRange( const B3DRange
& rRange
,
392 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
394 double fVerStart
, double fVerStop
,
395 double fHorStart
, double fHorStop
)
397 B3DPolyPolygon
aRetval(createUnitSphereFillPolyPolygon(nHorSeg
, nVerSeg
, bNormals
, fVerStart
, fVerStop
, fHorStart
, fHorStop
));
401 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
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
);
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
));
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
)));
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
));
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
));
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
);
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
));
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())
497 for(sal_uInt32
a(0); a
< nPolygonCount
; a
++)
499 const B3DPolygon
aCandidate(rCandidateA
.getB3DPolygon(a
));
501 if(!equal(aCandidate
, rCandidateB
.getB3DPolygon(a
), rfSmallValue
))
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
,
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
++));
554 // #i101520# correction is needed for imported polygons of old format,
558 basegfx::tools::checkClosed(aNewPolygon
);
561 aRetval
.append(aNewPolygon
);
568 void B3DPolyPolygonToUnoPolyPolygonShape3D(
569 const B3DPolyPolygon
& rPolyPolygonSource
,
570 com::sun::star::drawing::PolyPolygonShape3D
& rPolyPolygonShape3DRetval
)
572 const sal_uInt32
nPolygonCount(rPolyPolygonSource
.count());
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());
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();
612 const basegfx::B3DPoint
aPoint(aPoly
.getB3DPoint(0));
614 *pInnerSequenceX
++ = aPoint
.getX();
615 *pInnerSequenceY
++ = aPoint
.getY();
616 *pInnerSequenceZ
++ = aPoint
.getZ();
621 pOuterSequenceX
->realloc(0);
622 pOuterSequenceY
->realloc(0);
623 pOuterSequenceZ
->realloc(0);
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: */