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