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 <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>
32 #define nMinSegments sal_uInt32(1)
33 #define nMaxSegments sal_uInt32(512)
39 // B3DPolyPolygon tools
40 B3DRange
getRange(const B3DPolyPolygon
& rCandidate
)
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
));
54 B3DPolyPolygon
const & createUnitCubePolyPolygon()
56 static auto const singleton
= [] {
57 B3DPolyPolygon aRetval
;
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
);
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
);
75 aTemp
.append(B3DPoint(0.0, 0.0, 0.0));
76 aTemp
.append(B3DPoint(0.0, 0.0, 1.0));
77 aRetval
.append(aTemp
);
80 aTemp
.append(B3DPoint(0.0, 1.0, 0.0));
81 aTemp
.append(B3DPoint(0.0, 1.0, 1.0));
82 aRetval
.append(aTemp
);
85 aTemp
.append(B3DPoint(1.0, 1.0, 0.0));
86 aTemp
.append(B3DPoint(1.0, 1.0, 1.0));
87 aRetval
.append(aTemp
);
90 aTemp
.append(B3DPoint(1.0, 0.0, 0.0));
91 aTemp
.append(B3DPoint(1.0, 0.0, 1.0));
92 aRetval
.append(aTemp
);
98 B3DPolyPolygon
const & createUnitCubeFillPolyPolygon()
100 static auto const singleton
= [] {
101 B3DPolyPolygon aRetval
;
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);
119 aTemp
.setClosed(true);
120 aRetval
.append(aTemp
);
128 aTemp
.setClosed(true);
129 aRetval
.append(aTemp
);
137 aTemp
.setClosed(true);
138 aRetval
.append(aTemp
);
146 aTemp
.setClosed(true);
147 aRetval
.append(aTemp
);
155 aTemp
.setClosed(true);
156 aRetval
.append(aTemp
);
164 aTemp
.setClosed(true);
165 aRetval
.append(aTemp
);
171 B3DPolyPolygon
createCubePolyPolygonFromB3DRange( const B3DRange
& rRange
)
173 B3DPolyPolygon aRetval
;
175 if(!rRange
.isEmpty())
177 aRetval
= createUnitCubePolyPolygon();
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();
188 B3DPolyPolygon
createCubeFillPolyPolygonFromB3DRange( const B3DRange
& rRange
)
190 B3DPolyPolygon aRetval
;
192 if(!rRange
.isEmpty())
194 aRetval
= createUnitCubeFillPolyPolygon();
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();
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
;
223 nHorSeg
= fround(fabs(fHorStop
- fHorStart
) / (F_2PI
/ 24.0));
226 // min/max limitations
227 nHorSeg
= std::min(nMaxSegments
, std::max(nMinSegments
, nHorSeg
));
231 nVerSeg
= fround(fabs(fVerStop
- fVerStart
) / (F_2PI
/ 24.0));
234 // min/max limitations
235 nVerSeg
= std::min(nMaxSegments
, std::max(nMinSegments
, nVerSeg
));
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
));
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
));
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
));
283 aNew
.append(B3DPoint(0.0, -1.0, 0.0));
286 aRetval
.append(aNew
);
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
));
301 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
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
);
312 B3DPolyPolygon
createUnitSphereFillPolyPolygon(
313 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
315 double fVerStart
, double fVerStop
,
316 double fHorStart
, double fHorStop
)
318 B3DPolyPolygon aRetval
;
322 nHorSeg
= fround(fabs(fHorStop
- fHorStart
) / (F_2PI
/ 24.0));
325 // min/max limitations
326 nHorSeg
= std::min(nMaxSegments
, std::max(nMinSegments
, nHorSeg
));
330 nVerSeg
= fround(fabs(fVerStop
- fVerStart
) / (F_2PI
/ 24.0));
333 // min/max limitations
334 nVerSeg
= std::min(nMaxSegments
, std::max(nMinSegments
, nVerSeg
));
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
));
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
));
349 aNew
.append(getPointFromCartesian(fHor1
, fVer1
));
350 aNew
.append(getPointFromCartesian(fHor2
, fVer1
));
351 aNew
.append(getPointFromCartesian(fHor2
, fVer2
));
352 aNew
.append(getPointFromCartesian(fHor1
, fVer2
));
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
);
370 B3DPolyPolygon
createSphereFillPolyPolygonFromB3DRange( const B3DRange
& rRange
,
371 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
373 double fVerStart
, double fVerStop
,
374 double fHorStart
, double fHorStop
)
376 B3DPolyPolygon
aRetval(createUnitSphereFillPolyPolygon(nHorSeg
, nVerSeg
, bNormals
, fVerStart
, fVerStop
, fHorStart
, fHorStop
));
380 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
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
);
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
));
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
)));
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
));
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
));
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*/);
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*/));
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
++));
504 // #i101520# correction is needed for imported polygons of old format,
506 basegfx::utils::checkClosed(aNewPolygon
);
508 aRetval
.append(aNewPolygon
);
515 void B3DPolyPolygonToUnoPolyPolygonShape3D(
516 const B3DPolyPolygon
& rPolyPolygonSource
,
517 css::drawing::PolyPolygonShape3D
& rPolyPolygonShape3DRetval
)
519 const sal_uInt32
nPolygonCount(rPolyPolygonSource
.count());
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());
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();
559 const basegfx::B3DPoint
aPoint(aPoly
.getB3DPoint(0));
561 *pInnerSequenceX
++ = aPoint
.getX();
562 *pInnerSequenceY
++ = aPoint
.getY();
563 *pInnerSequenceZ
++ = aPoint
.getZ();
568 pOuterSequenceX
->realloc(0);
569 pOuterSequenceY
->realloc(0);
570 pOuterSequenceZ
->realloc(0);
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: */