Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
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 :
30 : //////////////////////////////////////////////////////////////////////////////
31 : // predefines
32 : #define nMinSegments sal_uInt32(1)
33 : #define nMaxSegments sal_uInt32(512)
34 :
35 : //////////////////////////////////////////////////////////////////////////////
36 :
37 : namespace basegfx
38 : {
39 : namespace tools
40 : {
41 : // B3DPolyPolygon tools
42 18605 : B3DRange getRange(const B3DPolyPolygon& rCandidate)
43 : {
44 18605 : B3DRange aRetval;
45 18605 : const sal_uInt32 nPolygonCount(rCandidate.count());
46 :
47 37210 : for(sal_uInt32 a(0L); a < nPolygonCount; a++)
48 : {
49 18605 : B3DPolygon aCandidate = rCandidate.getB3DPolygon(a);
50 18605 : aRetval.expand(getRange(aCandidate));
51 18605 : }
52 :
53 18605 : return aRetval;
54 : }
55 :
56 : namespace
57 : {
58 : struct theUnitCubePolyPolygon : public rtl::StaticWithInit<B3DPolyPolygon,
59 : theUnitCubePolyPolygon>
60 : {
61 0 : B3DPolyPolygon operator()()
62 : {
63 0 : B3DPolyPolygon aRetval;
64 0 : B3DPolygon aTemp;
65 0 : aTemp.append(B3DPoint(0.0, 0.0, 1.0));
66 0 : aTemp.append(B3DPoint(0.0, 1.0, 1.0));
67 0 : aTemp.append(B3DPoint(1.0, 1.0, 1.0));
68 0 : aTemp.append(B3DPoint(1.0, 0.0, 1.0));
69 0 : aTemp.setClosed(true);
70 0 : aRetval.append(aTemp);
71 :
72 0 : aTemp.clear();
73 0 : aTemp.append(B3DPoint(0.0, 0.0, 0.0));
74 0 : aTemp.append(B3DPoint(0.0, 1.0, 0.0));
75 0 : aTemp.append(B3DPoint(1.0, 1.0, 0.0));
76 0 : aTemp.append(B3DPoint(1.0, 0.0, 0.0));
77 0 : aTemp.setClosed(true);
78 0 : aRetval.append(aTemp);
79 :
80 0 : aTemp.clear();
81 0 : aTemp.append(B3DPoint(0.0, 0.0, 0.0));
82 0 : aTemp.append(B3DPoint(0.0, 0.0, 1.0));
83 0 : aRetval.append(aTemp);
84 :
85 0 : aTemp.clear();
86 0 : aTemp.append(B3DPoint(0.0, 1.0, 0.0));
87 0 : aTemp.append(B3DPoint(0.0, 1.0, 1.0));
88 0 : aRetval.append(aTemp);
89 :
90 0 : aTemp.clear();
91 0 : aTemp.append(B3DPoint(1.0, 1.0, 0.0));
92 0 : aTemp.append(B3DPoint(1.0, 1.0, 1.0));
93 0 : aRetval.append(aTemp);
94 :
95 0 : aTemp.clear();
96 0 : aTemp.append(B3DPoint(1.0, 0.0, 0.0));
97 0 : aTemp.append(B3DPoint(1.0, 0.0, 1.0));
98 0 : aRetval.append(aTemp);
99 0 : return aRetval;
100 : }
101 : };
102 : }
103 :
104 0 : B3DPolyPolygon createUnitCubePolyPolygon()
105 : {
106 0 : return theUnitCubePolyPolygon::get();
107 : }
108 :
109 : namespace
110 : {
111 : struct theUnitCubeFillPolyPolygon : public rtl::StaticWithInit<B3DPolyPolygon,
112 : theUnitCubeFillPolyPolygon>
113 : {
114 0 : B3DPolyPolygon operator()()
115 : {
116 0 : B3DPolyPolygon aRetval;
117 0 : B3DPolygon aTemp;
118 :
119 : // all points
120 0 : const B3DPoint A(0.0, 0.0, 0.0);
121 0 : const B3DPoint B(0.0, 1.0, 0.0);
122 0 : const B3DPoint C(1.0, 1.0, 0.0);
123 0 : const B3DPoint D(1.0, 0.0, 0.0);
124 0 : const B3DPoint E(0.0, 0.0, 1.0);
125 0 : const B3DPoint F(0.0, 1.0, 1.0);
126 0 : const B3DPoint G(1.0, 1.0, 1.0);
127 0 : const B3DPoint H(1.0, 0.0, 1.0);
128 :
129 : // create bottom
130 0 : aTemp.append(D);
131 0 : aTemp.append(A);
132 0 : aTemp.append(E);
133 0 : aTemp.append(H);
134 0 : aTemp.setClosed(true);
135 0 : aRetval.append(aTemp);
136 :
137 : // create front
138 0 : aTemp.clear();
139 0 : aTemp.append(B);
140 0 : aTemp.append(A);
141 0 : aTemp.append(D);
142 0 : aTemp.append(C);
143 0 : aTemp.setClosed(true);
144 0 : aRetval.append(aTemp);
145 :
146 : // create left
147 0 : aTemp.clear();
148 0 : aTemp.append(E);
149 0 : aTemp.append(A);
150 0 : aTemp.append(B);
151 0 : aTemp.append(F);
152 0 : aTemp.setClosed(true);
153 0 : aRetval.append(aTemp);
154 :
155 : // create top
156 0 : aTemp.clear();
157 0 : aTemp.append(C);
158 0 : aTemp.append(G);
159 0 : aTemp.append(F);
160 0 : aTemp.append(B);
161 0 : aTemp.setClosed(true);
162 0 : aRetval.append(aTemp);
163 :
164 : // create right
165 0 : aTemp.clear();
166 0 : aTemp.append(H);
167 0 : aTemp.append(G);
168 0 : aTemp.append(C);
169 0 : aTemp.append(D);
170 0 : aTemp.setClosed(true);
171 0 : aRetval.append(aTemp);
172 :
173 : // create back
174 0 : aTemp.clear();
175 0 : aTemp.append(F);
176 0 : aTemp.append(G);
177 0 : aTemp.append(H);
178 0 : aTemp.append(E);
179 0 : aTemp.setClosed(true);
180 0 : aRetval.append(aTemp);
181 0 : return aRetval;
182 : }
183 : };
184 : }
185 :
186 0 : B3DPolyPolygon createUnitCubeFillPolyPolygon()
187 : {
188 0 : return theUnitCubeFillPolyPolygon::get();
189 : }
190 :
191 0 : B3DPolyPolygon createCubePolyPolygonFromB3DRange( const B3DRange& rRange)
192 : {
193 0 : B3DPolyPolygon aRetval;
194 :
195 0 : if(!rRange.isEmpty())
196 : {
197 0 : aRetval = createUnitCubePolyPolygon();
198 0 : B3DHomMatrix aTrans;
199 0 : aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
200 0 : aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
201 0 : aRetval.transform(aTrans);
202 0 : aRetval.removeDoublePoints();
203 : }
204 :
205 0 : return aRetval;
206 : }
207 :
208 0 : B3DPolyPolygon createCubeFillPolyPolygonFromB3DRange( const B3DRange& rRange)
209 : {
210 0 : B3DPolyPolygon aRetval;
211 :
212 0 : if(!rRange.isEmpty())
213 : {
214 0 : aRetval = createUnitCubeFillPolyPolygon();
215 0 : B3DHomMatrix aTrans;
216 0 : aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
217 0 : aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
218 0 : aRetval.transform(aTrans);
219 0 : aRetval.removeDoublePoints();
220 : }
221 :
222 0 : return aRetval;
223 : }
224 :
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 0 : inline B3DPoint getPointFromCartesian(double fVer, double fHor)
228 : {
229 0 : const double fCosHor(cos(fHor));
230 0 : return B3DPoint(fCosHor * cos(fVer), sin(fHor), fCosHor * -sin(fVer));
231 : }
232 :
233 0 : B3DPolyPolygon createUnitSpherePolyPolygon(
234 : sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
235 : double fVerStart, double fVerStop,
236 : double fHorStart, double fHorStop)
237 : {
238 0 : B3DPolyPolygon aRetval;
239 : sal_uInt32 a, b;
240 :
241 0 : if(!nHorSeg)
242 : {
243 0 : nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
244 : }
245 :
246 : // min/max limitations
247 0 : nHorSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nHorSeg));
248 :
249 0 : if(!nVerSeg)
250 : {
251 0 : nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
252 : }
253 :
254 : // min/max limitations
255 0 : nVerSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nVerSeg));
256 :
257 : // create constants
258 0 : const double fVerDiffPerStep((fVerStop - fVerStart) / (double)nVerSeg);
259 0 : const double fHorDiffPerStep((fHorStop - fHorStart) / (double)nHorSeg);
260 0 : bool bHorClosed(fTools::equal(fHorStop - fHorStart, F_2PI));
261 0 : bool bVerFromTop(fTools::equal(fVerStart, F_PI2));
262 0 : bool bVerToBottom(fTools::equal(fVerStop, -F_PI2));
263 :
264 : // create horizontal rings
265 0 : const sal_uInt32 nLoopVerInit(bVerFromTop ? 1L : 0L);
266 0 : const sal_uInt32 nLoopVerLimit(bVerToBottom ? nVerSeg : nVerSeg + 1L);
267 0 : const sal_uInt32 nLoopHorLimit(bHorClosed ? nHorSeg : nHorSeg + 1L);
268 :
269 0 : for(a = nLoopVerInit; a < nLoopVerLimit; a++)
270 : {
271 0 : const double fVer(fVerStart + ((double)(a) * fVerDiffPerStep));
272 0 : B3DPolygon aNew;
273 :
274 0 : for(b = 0L; b < nLoopHorLimit; b++)
275 : {
276 0 : const double fHor(fHorStart + ((double)(b) * fHorDiffPerStep));
277 0 : aNew.append(getPointFromCartesian(fHor, fVer));
278 : }
279 :
280 0 : aNew.setClosed(bHorClosed);
281 0 : aRetval.append(aNew);
282 0 : }
283 :
284 : // create vertical half-rings
285 0 : for(a = 0L; a < nLoopHorLimit; a++)
286 : {
287 0 : const double fHor(fHorStart + ((double)(a) * fHorDiffPerStep));
288 0 : B3DPolygon aNew;
289 :
290 0 : if(bVerFromTop)
291 : {
292 0 : aNew.append(B3DPoint(0.0, 1.0, 0.0));
293 : }
294 :
295 0 : for(b = nLoopVerInit; b < nLoopVerLimit; b++)
296 : {
297 0 : const double fVer(fVerStart + ((double)(b) * fVerDiffPerStep));
298 0 : aNew.append(getPointFromCartesian(fHor, fVer));
299 : }
300 :
301 0 : if(bVerToBottom)
302 : {
303 0 : aNew.append(B3DPoint(0.0, -1.0, 0.0));
304 : }
305 :
306 0 : aRetval.append(aNew);
307 0 : }
308 :
309 0 : return aRetval;
310 : }
311 :
312 0 : B3DPolyPolygon createSpherePolyPolygonFromB3DRange( const B3DRange& rRange,
313 : sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
314 : double fVerStart, double fVerStop,
315 : double fHorStart, double fHorStop)
316 : {
317 0 : B3DPolyPolygon aRetval(createUnitSpherePolyPolygon(nHorSeg, nVerSeg, fVerStart, fVerStop, fHorStart, fHorStop));
318 :
319 0 : if(aRetval.count())
320 : {
321 : // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
322 0 : B3DHomMatrix aTrans;
323 0 : aTrans.translate(1.0, 1.0, 1.0);
324 0 : aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
325 0 : aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
326 0 : aRetval.transform(aTrans);
327 : }
328 :
329 0 : return aRetval;
330 : }
331 :
332 0 : B3DPolyPolygon createUnitSphereFillPolyPolygon(
333 : sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
334 : bool bNormals,
335 : double fVerStart, double fVerStop,
336 : double fHorStart, double fHorStop)
337 : {
338 0 : B3DPolyPolygon aRetval;
339 :
340 0 : if(!nHorSeg)
341 : {
342 0 : nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
343 : }
344 :
345 : // min/max limitations
346 0 : nHorSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nHorSeg));
347 :
348 0 : if(!nVerSeg)
349 : {
350 0 : nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
351 : }
352 :
353 : // min/max limitations
354 0 : nVerSeg = ::std::min(nMaxSegments, ::std::max(nMinSegments, nVerSeg));
355 :
356 : // vertical loop
357 0 : for(sal_uInt32 a(0L); a < nVerSeg; a++)
358 : {
359 0 : const double fVer(fVerStart + (((fVerStop - fVerStart) * a) / nVerSeg));
360 0 : const double fVer2(fVerStart + (((fVerStop - fVerStart) * (a + 1)) / nVerSeg));
361 :
362 : // horizontal loop
363 0 : for(sal_uInt32 b(0L); b < nHorSeg; b++)
364 : {
365 0 : const double fHor(fHorStart + (((fHorStop - fHorStart) * b) / nHorSeg));
366 0 : const double fHor2(fHorStart + (((fHorStop - fHorStart) * (b + 1)) / nHorSeg));
367 0 : B3DPolygon aNew;
368 :
369 0 : aNew.append(getPointFromCartesian(fHor, fVer));
370 0 : aNew.append(getPointFromCartesian(fHor2, fVer));
371 0 : aNew.append(getPointFromCartesian(fHor2, fVer2));
372 0 : aNew.append(getPointFromCartesian(fHor, fVer2));
373 :
374 0 : if(bNormals)
375 : {
376 0 : for(sal_uInt32 c(0L); c < aNew.count(); c++)
377 : {
378 0 : aNew.setNormal(c, ::basegfx::B3DVector(aNew.getB3DPoint(c)));
379 : }
380 : }
381 :
382 0 : aNew.setClosed(true);
383 0 : aRetval.append(aNew);
384 0 : }
385 : }
386 :
387 0 : return aRetval;
388 : }
389 :
390 0 : B3DPolyPolygon createSphereFillPolyPolygonFromB3DRange( const B3DRange& rRange,
391 : sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
392 : bool bNormals,
393 : double fVerStart, double fVerStop,
394 : double fHorStart, double fHorStop)
395 : {
396 0 : B3DPolyPolygon aRetval(createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, bNormals, fVerStart, fVerStop, fHorStart, fHorStop));
397 :
398 0 : if(aRetval.count())
399 : {
400 : // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
401 0 : B3DHomMatrix aTrans;
402 0 : aTrans.translate(1.0, 1.0, 1.0);
403 0 : aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
404 0 : aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
405 0 : aRetval.transform(aTrans);
406 : }
407 :
408 0 : return aRetval;
409 : }
410 :
411 0 : B3DPolyPolygon applyDefaultNormalsSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter)
412 : {
413 0 : B3DPolyPolygon aRetval;
414 :
415 0 : for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
416 : {
417 0 : aRetval.append(applyDefaultNormalsSphere(rCandidate.getB3DPolygon(a), rCenter));
418 : }
419 :
420 0 : return aRetval;
421 : }
422 :
423 0 : B3DPolyPolygon invertNormals( const B3DPolyPolygon& rCandidate)
424 : {
425 0 : B3DPolyPolygon aRetval;
426 :
427 0 : for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
428 : {
429 0 : aRetval.append(invertNormals(rCandidate.getB3DPolygon(a)));
430 : }
431 :
432 0 : return aRetval;
433 : }
434 :
435 144 : B3DPolyPolygon applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
436 : {
437 144 : B3DPolyPolygon aRetval;
438 :
439 288 : for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
440 : {
441 144 : aRetval.append(applyDefaultTextureCoordinatesParallel(rCandidate.getB3DPolygon(a), rRange, bChangeX, bChangeY));
442 : }
443 :
444 144 : return aRetval;
445 : }
446 :
447 0 : B3DPolyPolygon applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
448 : {
449 0 : B3DPolyPolygon aRetval;
450 :
451 0 : for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
452 : {
453 0 : aRetval.append(applyDefaultTextureCoordinatesSphere(rCandidate.getB3DPolygon(a), rCenter, bChangeX, bChangeY));
454 : }
455 :
456 0 : return aRetval;
457 : }
458 :
459 0 : bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder)
460 : {
461 0 : const sal_uInt32 nPolygonCount(rCandidate.count());
462 :
463 0 : if(1L == nPolygonCount)
464 : {
465 0 : return isInside(rCandidate.getB3DPolygon(0), rPoint, bWithBorder);
466 : }
467 : else
468 : {
469 0 : sal_Int32 nInsideCount(0);
470 :
471 0 : for(sal_uInt32 a(0); a < nPolygonCount; a++)
472 : {
473 0 : const B3DPolygon aPolygon(rCandidate.getB3DPolygon(a));
474 0 : const bool bInside(isInside(aPolygon, rPoint, bWithBorder));
475 :
476 0 : if(bInside)
477 : {
478 0 : nInsideCount++;
479 : }
480 0 : }
481 :
482 0 : return (nInsideCount % 2L);
483 : }
484 : }
485 :
486 : } // end of namespace tools
487 : } // end of namespace basegfx
488 :
489 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|