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 <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>
28 #include <basegfx/matrix/b3dhommatrix.hxx>
29 #include <basegfx/numeric/ftools.hxx>
30 #include <com/sun/star/drawing/DoubleSequence.hpp>
33 #define nMinSegments sal_uInt32(1)
34 #define nMaxSegments sal_uInt32(512)
40 // B3DPolyPolygon tools
41 B3DRange
getRange(const B3DPolyPolygon
& rCandidate
)
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
));
57 struct theUnitCubePolyPolygon
: public rtl::StaticWithInit
<B3DPolyPolygon
,
58 theUnitCubePolyPolygon
>
60 B3DPolyPolygon
operator()()
62 B3DPolyPolygon aRetval
;
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
);
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
);
80 aTemp
.append(B3DPoint(0.0, 0.0, 0.0));
81 aTemp
.append(B3DPoint(0.0, 0.0, 1.0));
82 aRetval
.append(aTemp
);
85 aTemp
.append(B3DPoint(0.0, 1.0, 0.0));
86 aTemp
.append(B3DPoint(0.0, 1.0, 1.0));
87 aRetval
.append(aTemp
);
90 aTemp
.append(B3DPoint(1.0, 1.0, 0.0));
91 aTemp
.append(B3DPoint(1.0, 1.0, 1.0));
92 aRetval
.append(aTemp
);
95 aTemp
.append(B3DPoint(1.0, 0.0, 0.0));
96 aTemp
.append(B3DPoint(1.0, 0.0, 1.0));
97 aRetval
.append(aTemp
);
103 B3DPolyPolygon
const & createUnitCubePolyPolygon()
105 return theUnitCubePolyPolygon::get();
110 struct theUnitCubeFillPolyPolygon
: public rtl::StaticWithInit
<B3DPolyPolygon
,
111 theUnitCubeFillPolyPolygon
>
113 B3DPolyPolygon
operator()()
115 B3DPolyPolygon aRetval
;
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);
133 aTemp
.setClosed(true);
134 aRetval
.append(aTemp
);
142 aTemp
.setClosed(true);
143 aRetval
.append(aTemp
);
151 aTemp
.setClosed(true);
152 aRetval
.append(aTemp
);
160 aTemp
.setClosed(true);
161 aRetval
.append(aTemp
);
169 aTemp
.setClosed(true);
170 aRetval
.append(aTemp
);
178 aTemp
.setClosed(true);
179 aRetval
.append(aTemp
);
185 B3DPolyPolygon
const & createUnitCubeFillPolyPolygon()
187 return theUnitCubeFillPolyPolygon::get();
190 B3DPolyPolygon
createCubePolyPolygonFromB3DRange( const B3DRange
& rRange
)
192 B3DPolyPolygon aRetval
;
194 if(!rRange
.isEmpty())
196 aRetval
= createUnitCubePolyPolygon();
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();
207 B3DPolyPolygon
createCubeFillPolyPolygonFromB3DRange( const B3DRange
& rRange
)
209 B3DPolyPolygon aRetval
;
211 if(!rRange
.isEmpty())
213 aRetval
= createUnitCubeFillPolyPolygon();
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();
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
;
242 nHorSeg
= fround(fabs(fHorStop
- fHorStart
) / (F_2PI
/ 24.0));
245 // min/max limitations
246 nHorSeg
= std::min(nMaxSegments
, std::max(nMinSegments
, nHorSeg
));
250 nVerSeg
= fround(fabs(fVerStop
- fVerStart
) / (F_2PI
/ 24.0));
253 // min/max limitations
254 nVerSeg
= std::min(nMaxSegments
, std::max(nMinSegments
, nVerSeg
));
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
));
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
));
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
));
302 aNew
.append(B3DPoint(0.0, -1.0, 0.0));
305 aRetval
.append(aNew
);
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
));
320 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
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
);
331 B3DPolyPolygon
createUnitSphereFillPolyPolygon(
332 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
334 double fVerStart
, double fVerStop
,
335 double fHorStart
, double fHorStop
)
337 B3DPolyPolygon aRetval
;
341 nHorSeg
= fround(fabs(fHorStop
- fHorStart
) / (F_2PI
/ 24.0));
344 // min/max limitations
345 nHorSeg
= std::min(nMaxSegments
, std::max(nMinSegments
, nHorSeg
));
349 nVerSeg
= fround(fabs(fVerStop
- fVerStart
) / (F_2PI
/ 24.0));
352 // min/max limitations
353 nVerSeg
= std::min(nMaxSegments
, std::max(nMinSegments
, nVerSeg
));
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
));
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
));
368 aNew
.append(getPointFromCartesian(fHor1
, fVer1
));
369 aNew
.append(getPointFromCartesian(fHor2
, fVer1
));
370 aNew
.append(getPointFromCartesian(fHor2
, fVer2
));
371 aNew
.append(getPointFromCartesian(fHor1
, fVer2
));
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
);
389 B3DPolyPolygon
createSphereFillPolyPolygonFromB3DRange( const B3DRange
& rRange
,
390 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
392 double fVerStart
, double fVerStop
,
393 double fHorStart
, double fHorStop
)
395 B3DPolyPolygon
aRetval(createUnitSphereFillPolyPolygon(nHorSeg
, nVerSeg
, bNormals
, fVerStart
, fVerStop
, fHorStart
, fHorStop
));
399 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
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
);
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
));
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
)));
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
));
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
));
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*/);
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*/));
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
++));
523 // #i101520# correction is needed for imported polygons of old format,
525 basegfx::utils::checkClosed(aNewPolygon
);
527 aRetval
.append(aNewPolygon
);
534 void B3DPolyPolygonToUnoPolyPolygonShape3D(
535 const B3DPolyPolygon
& rPolyPolygonSource
,
536 css::drawing::PolyPolygonShape3D
& rPolyPolygonShape3DRetval
)
538 const sal_uInt32
nPolygonCount(rPolyPolygonSource
.count());
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());
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();
578 const basegfx::B3DPoint
aPoint(aPoly
.getB3DPoint(0));
580 *pInnerSequenceX
++ = aPoint
.getX();
581 *pInnerSequenceY
++ = aPoint
.getY();
582 *pInnerSequenceZ
++ = aPoint
.getZ();
587 pOuterSequenceX
->realloc(0);
588 pOuterSequenceY
->realloc(0);
589 pOuterSequenceZ
->realloc(0);
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: */