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>
30 //////////////////////////////////////////////////////////////////////////////
32 #define nMinSegments sal_uInt32(1)
33 #define nMaxSegments sal_uInt32(512)
35 //////////////////////////////////////////////////////////////////////////////
41 // B3DPolyPolygon tools
42 B3DRange
getRange(const B3DPolyPolygon
& rCandidate
)
45 const sal_uInt32
nPolygonCount(rCandidate
.count());
47 for(sal_uInt32
a(0L); a
< nPolygonCount
; a
++)
49 B3DPolygon aCandidate
= rCandidate
.getB3DPolygon(a
);
50 aRetval
.expand(getRange(aCandidate
));
58 struct theUnitCubePolyPolygon
: public rtl::StaticWithInit
<B3DPolyPolygon
,
59 theUnitCubePolyPolygon
>
61 B3DPolyPolygon
operator()()
63 B3DPolyPolygon aRetval
;
65 aTemp
.append(B3DPoint(0.0, 0.0, 1.0));
66 aTemp
.append(B3DPoint(0.0, 1.0, 1.0));
67 aTemp
.append(B3DPoint(1.0, 1.0, 1.0));
68 aTemp
.append(B3DPoint(1.0, 0.0, 1.0));
69 aTemp
.setClosed(true);
70 aRetval
.append(aTemp
);
73 aTemp
.append(B3DPoint(0.0, 0.0, 0.0));
74 aTemp
.append(B3DPoint(0.0, 1.0, 0.0));
75 aTemp
.append(B3DPoint(1.0, 1.0, 0.0));
76 aTemp
.append(B3DPoint(1.0, 0.0, 0.0));
77 aTemp
.setClosed(true);
78 aRetval
.append(aTemp
);
81 aTemp
.append(B3DPoint(0.0, 0.0, 0.0));
82 aTemp
.append(B3DPoint(0.0, 0.0, 1.0));
83 aRetval
.append(aTemp
);
86 aTemp
.append(B3DPoint(0.0, 1.0, 0.0));
87 aTemp
.append(B3DPoint(0.0, 1.0, 1.0));
88 aRetval
.append(aTemp
);
91 aTemp
.append(B3DPoint(1.0, 1.0, 0.0));
92 aTemp
.append(B3DPoint(1.0, 1.0, 1.0));
93 aRetval
.append(aTemp
);
96 aTemp
.append(B3DPoint(1.0, 0.0, 0.0));
97 aTemp
.append(B3DPoint(1.0, 0.0, 1.0));
98 aRetval
.append(aTemp
);
104 B3DPolyPolygon
createUnitCubePolyPolygon()
106 return theUnitCubePolyPolygon::get();
111 struct theUnitCubeFillPolyPolygon
: public rtl::StaticWithInit
<B3DPolyPolygon
,
112 theUnitCubeFillPolyPolygon
>
114 B3DPolyPolygon
operator()()
116 B3DPolyPolygon aRetval
;
120 const B3DPoint
A(0.0, 0.0, 0.0);
121 const B3DPoint
B(0.0, 1.0, 0.0);
122 const B3DPoint
C(1.0, 1.0, 0.0);
123 const B3DPoint
D(1.0, 0.0, 0.0);
124 const B3DPoint
E(0.0, 0.0, 1.0);
125 const B3DPoint
F(0.0, 1.0, 1.0);
126 const B3DPoint
G(1.0, 1.0, 1.0);
127 const B3DPoint
H(1.0, 0.0, 1.0);
134 aTemp
.setClosed(true);
135 aRetval
.append(aTemp
);
143 aTemp
.setClosed(true);
144 aRetval
.append(aTemp
);
152 aTemp
.setClosed(true);
153 aRetval
.append(aTemp
);
161 aTemp
.setClosed(true);
162 aRetval
.append(aTemp
);
170 aTemp
.setClosed(true);
171 aRetval
.append(aTemp
);
179 aTemp
.setClosed(true);
180 aRetval
.append(aTemp
);
186 B3DPolyPolygon
createUnitCubeFillPolyPolygon()
188 return theUnitCubeFillPolyPolygon::get();
191 B3DPolyPolygon
createCubePolyPolygonFromB3DRange( const B3DRange
& rRange
)
193 B3DPolyPolygon aRetval
;
195 if(!rRange
.isEmpty())
197 aRetval
= createUnitCubePolyPolygon();
199 aTrans
.scale(rRange
.getWidth(), rRange
.getHeight(), rRange
.getDepth());
200 aTrans
.translate(rRange
.getMinX(), rRange
.getMinY(), rRange
.getMinZ());
201 aRetval
.transform(aTrans
);
202 aRetval
.removeDoublePoints();
208 B3DPolyPolygon
createCubeFillPolyPolygonFromB3DRange( const B3DRange
& rRange
)
210 B3DPolyPolygon aRetval
;
212 if(!rRange
.isEmpty())
214 aRetval
= createUnitCubeFillPolyPolygon();
216 aTrans
.scale(rRange
.getWidth(), rRange
.getHeight(), rRange
.getDepth());
217 aTrans
.translate(rRange
.getMinX(), rRange
.getMinY(), rRange
.getMinZ());
218 aRetval
.transform(aTrans
);
219 aRetval
.removeDoublePoints();
225 // helper for getting the 3D Point from given cartesian coordiantes. fVer is defined from
226 // [F_PI2 .. -F_PI2], fHor from [0.0 .. F_2PI]
227 inline B3DPoint
getPointFromCartesian(double fVer
, double fHor
)
229 const double fCosHor(cos(fHor
));
230 return B3DPoint(fCosHor
* cos(fVer
), sin(fHor
), fCosHor
* -sin(fVer
));
233 B3DPolyPolygon
createUnitSpherePolyPolygon(
234 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
235 double fVerStart
, double fVerStop
,
236 double fHorStart
, double fHorStop
)
238 B3DPolyPolygon aRetval
;
243 nHorSeg
= fround(fabs(fHorStop
- fHorStart
) / (F_2PI
/ 24.0));
246 // min/max limitations
247 nHorSeg
= ::std::min(nMaxSegments
, ::std::max(nMinSegments
, nHorSeg
));
251 nVerSeg
= fround(fabs(fVerStop
- fVerStart
) / (F_2PI
/ 24.0));
254 // min/max limitations
255 nVerSeg
= ::std::min(nMaxSegments
, ::std::max(nMinSegments
, nVerSeg
));
258 const double fVerDiffPerStep((fVerStop
- fVerStart
) / (double)nVerSeg
);
259 const double fHorDiffPerStep((fHorStop
- fHorStart
) / (double)nHorSeg
);
260 bool bHorClosed(fTools::equal(fHorStop
- fHorStart
, F_2PI
));
261 bool bVerFromTop(fTools::equal(fVerStart
, F_PI2
));
262 bool bVerToBottom(fTools::equal(fVerStop
, -F_PI2
));
264 // create horizontal rings
265 const sal_uInt32
nLoopVerInit(bVerFromTop
? 1L : 0L);
266 const sal_uInt32
nLoopVerLimit(bVerToBottom
? nVerSeg
: nVerSeg
+ 1L);
267 const sal_uInt32
nLoopHorLimit(bHorClosed
? nHorSeg
: nHorSeg
+ 1L);
269 for(a
= nLoopVerInit
; a
< nLoopVerLimit
; a
++)
271 const double fVer(fVerStart
+ ((double)(a
) * fVerDiffPerStep
));
274 for(b
= 0L; b
< nLoopHorLimit
; b
++)
276 const double fHor(fHorStart
+ ((double)(b
) * fHorDiffPerStep
));
277 aNew
.append(getPointFromCartesian(fHor
, fVer
));
280 aNew
.setClosed(bHorClosed
);
281 aRetval
.append(aNew
);
284 // create vertical half-rings
285 for(a
= 0L; a
< nLoopHorLimit
; a
++)
287 const double fHor(fHorStart
+ ((double)(a
) * fHorDiffPerStep
));
292 aNew
.append(B3DPoint(0.0, 1.0, 0.0));
295 for(b
= nLoopVerInit
; b
< nLoopVerLimit
; b
++)
297 const double fVer(fVerStart
+ ((double)(b
) * fVerDiffPerStep
));
298 aNew
.append(getPointFromCartesian(fHor
, fVer
));
303 aNew
.append(B3DPoint(0.0, -1.0, 0.0));
306 aRetval
.append(aNew
);
312 B3DPolyPolygon
createSpherePolyPolygonFromB3DRange( const B3DRange
& rRange
,
313 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
314 double fVerStart
, double fVerStop
,
315 double fHorStart
, double fHorStop
)
317 B3DPolyPolygon
aRetval(createUnitSpherePolyPolygon(nHorSeg
, nVerSeg
, fVerStart
, fVerStop
, fHorStart
, fHorStop
));
321 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
323 aTrans
.translate(1.0, 1.0, 1.0);
324 aTrans
.scale(rRange
.getWidth() / 2.0, rRange
.getHeight() / 2.0, rRange
.getDepth() / 2.0);
325 aTrans
.translate(rRange
.getMinX(), rRange
.getMinY(), rRange
.getMinZ());
326 aRetval
.transform(aTrans
);
332 B3DPolyPolygon
createUnitSphereFillPolyPolygon(
333 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
335 double fVerStart
, double fVerStop
,
336 double fHorStart
, double fHorStop
)
338 B3DPolyPolygon aRetval
;
342 nHorSeg
= fround(fabs(fHorStop
- fHorStart
) / (F_2PI
/ 24.0));
345 // min/max limitations
346 nHorSeg
= ::std::min(nMaxSegments
, ::std::max(nMinSegments
, nHorSeg
));
350 nVerSeg
= fround(fabs(fVerStop
- fVerStart
) / (F_2PI
/ 24.0));
353 // min/max limitations
354 nVerSeg
= ::std::min(nMaxSegments
, ::std::max(nMinSegments
, nVerSeg
));
357 for(sal_uInt32
a(0L); a
< nVerSeg
; a
++)
359 const double fVer(fVerStart
+ (((fVerStop
- fVerStart
) * a
) / nVerSeg
));
360 const double fVer2(fVerStart
+ (((fVerStop
- fVerStart
) * (a
+ 1)) / nVerSeg
));
363 for(sal_uInt32
b(0L); b
< nHorSeg
; b
++)
365 const double fHor(fHorStart
+ (((fHorStop
- fHorStart
) * b
) / nHorSeg
));
366 const double fHor2(fHorStart
+ (((fHorStop
- fHorStart
) * (b
+ 1)) / nHorSeg
));
369 aNew
.append(getPointFromCartesian(fHor
, fVer
));
370 aNew
.append(getPointFromCartesian(fHor2
, fVer
));
371 aNew
.append(getPointFromCartesian(fHor2
, fVer2
));
372 aNew
.append(getPointFromCartesian(fHor
, fVer2
));
376 for(sal_uInt32
c(0L); c
< aNew
.count(); c
++)
378 aNew
.setNormal(c
, ::basegfx::B3DVector(aNew
.getB3DPoint(c
)));
382 aNew
.setClosed(true);
383 aRetval
.append(aNew
);
390 B3DPolyPolygon
createSphereFillPolyPolygonFromB3DRange( const B3DRange
& rRange
,
391 sal_uInt32 nHorSeg
, sal_uInt32 nVerSeg
,
393 double fVerStart
, double fVerStop
,
394 double fHorStart
, double fHorStop
)
396 B3DPolyPolygon
aRetval(createUnitSphereFillPolyPolygon(nHorSeg
, nVerSeg
, bNormals
, fVerStart
, fVerStop
, fHorStart
, fHorStop
));
400 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
402 aTrans
.translate(1.0, 1.0, 1.0);
403 aTrans
.scale(rRange
.getWidth() / 2.0, rRange
.getHeight() / 2.0, rRange
.getDepth() / 2.0);
404 aTrans
.translate(rRange
.getMinX(), rRange
.getMinY(), rRange
.getMinZ());
405 aRetval
.transform(aTrans
);
411 B3DPolyPolygon
applyDefaultNormalsSphere( const B3DPolyPolygon
& rCandidate
, const B3DPoint
& rCenter
)
413 B3DPolyPolygon aRetval
;
415 for(sal_uInt32
a(0L); a
< rCandidate
.count(); a
++)
417 aRetval
.append(applyDefaultNormalsSphere(rCandidate
.getB3DPolygon(a
), rCenter
));
423 B3DPolyPolygon
invertNormals( const B3DPolyPolygon
& rCandidate
)
425 B3DPolyPolygon aRetval
;
427 for(sal_uInt32
a(0L); a
< rCandidate
.count(); a
++)
429 aRetval
.append(invertNormals(rCandidate
.getB3DPolygon(a
)));
435 B3DPolyPolygon
applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon
& rCandidate
, const B3DRange
& rRange
, bool bChangeX
, bool bChangeY
)
437 B3DPolyPolygon aRetval
;
439 for(sal_uInt32
a(0L); a
< rCandidate
.count(); a
++)
441 aRetval
.append(applyDefaultTextureCoordinatesParallel(rCandidate
.getB3DPolygon(a
), rRange
, bChangeX
, bChangeY
));
447 B3DPolyPolygon
applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon
& rCandidate
, const B3DPoint
& rCenter
, bool bChangeX
, bool bChangeY
)
449 B3DPolyPolygon aRetval
;
451 for(sal_uInt32
a(0L); a
< rCandidate
.count(); a
++)
453 aRetval
.append(applyDefaultTextureCoordinatesSphere(rCandidate
.getB3DPolygon(a
), rCenter
, bChangeX
, bChangeY
));
459 bool isInside(const B3DPolyPolygon
& rCandidate
, const B3DPoint
& rPoint
, bool bWithBorder
)
461 const sal_uInt32
nPolygonCount(rCandidate
.count());
463 if(1L == nPolygonCount
)
465 return isInside(rCandidate
.getB3DPolygon(0), rPoint
, bWithBorder
);
469 sal_Int32
nInsideCount(0);
471 for(sal_uInt32
a(0); a
< nPolygonCount
; a
++)
473 const B3DPolygon
aPolygon(rCandidate
.getB3DPolygon(a
));
474 const bool bInside(isInside(aPolygon
, rPoint
, bWithBorder
));
482 return (nInsideCount
% 2L);
486 } // end of namespace tools
487 } // end of namespace basegfx
489 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */