xref: /AOO41X/main/basegfx/source/polygon/b3dpolypolygontools.cxx (revision b2937f997bda0a05141a2d862a64f7be893955b7)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basegfx.hxx"
26 #include <basegfx/polygon/b3dpolypolygontools.hxx>
27 #include <basegfx/range/b3drange.hxx>
28 #include <basegfx/polygon/b3dpolypolygon.hxx>
29 #include <basegfx/polygon/b3dpolygon.hxx>
30 #include <basegfx/polygon/b3dpolygontools.hxx>
31 #include <numeric>
32 #include <basegfx/matrix/b3dhommatrix.hxx>
33 #include <basegfx/numeric/ftools.hxx>
34 #include <osl/mutex.hxx>
35 
36 //////////////////////////////////////////////////////////////////////////////
37 
38 namespace basegfx
39 {
40     namespace tools
41     {
42         // B3DPolyPolygon tools
43         B3DRange getRange(const B3DPolyPolygon& rCandidate)
44         {
45             B3DRange aRetval;
46             const sal_uInt32 nPolygonCount(rCandidate.count());
47 
48             for(sal_uInt32 a(0L); a < nPolygonCount; a++)
49             {
50                 B3DPolygon aCandidate = rCandidate.getB3DPolygon(a);
51                 aRetval.expand(getRange(aCandidate));
52             }
53 
54             return aRetval;
55         }
56 
57         void applyLineDashing(const B3DPolyPolygon& rCandidate, const ::std::vector<double>& rDotDashArray, B3DPolyPolygon* pLineTarget, B3DPolyPolygon* pGapTarget, double fFullDashDotLen)
58         {
59             if(0.0 == fFullDashDotLen && rDotDashArray.size())
60             {
61                 // calculate fFullDashDotLen from rDotDashArray
62                 fFullDashDotLen = ::std::accumulate(rDotDashArray.begin(), rDotDashArray.end(), 0.0);
63             }
64 
65             if(rCandidate.count() && fFullDashDotLen > 0.0)
66             {
67                 B3DPolyPolygon aLineTarget, aGapTarget;
68 
69                 for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
70                 {
71                     const B3DPolygon aCandidate(rCandidate.getB3DPolygon(a));
72 
73                     applyLineDashing(
74                         aCandidate,
75                         rDotDashArray,
76                         pLineTarget ? &aLineTarget : 0,
77                         pGapTarget ? &aGapTarget : 0,
78                         fFullDashDotLen);
79 
80                     if(pLineTarget)
81                     {
82                         pLineTarget->append(aLineTarget);
83                     }
84 
85                     if(pGapTarget)
86                     {
87                         pGapTarget->append(aGapTarget);
88                     }
89                 }
90             }
91         }
92 
93         B3DPolyPolygon createUnitCubePolyPolygon()
94         {
95             static B3DPolyPolygon aRetval;
96             ::osl::Mutex m_mutex;
97 
98             if(!aRetval.count())
99             {
100                 B3DPolygon aTemp;
101                 aTemp.append(B3DPoint(0.0, 0.0, 1.0));
102                 aTemp.append(B3DPoint(0.0, 1.0, 1.0));
103                 aTemp.append(B3DPoint(1.0, 1.0, 1.0));
104                 aTemp.append(B3DPoint(1.0, 0.0, 1.0));
105                 aTemp.setClosed(true);
106                 aRetval.append(aTemp);
107 
108                 aTemp.clear();
109                 aTemp.append(B3DPoint(0.0, 0.0, 0.0));
110                 aTemp.append(B3DPoint(0.0, 1.0, 0.0));
111                 aTemp.append(B3DPoint(1.0, 1.0, 0.0));
112                 aTemp.append(B3DPoint(1.0, 0.0, 0.0));
113                 aTemp.setClosed(true);
114                 aRetval.append(aTemp);
115 
116                 aTemp.clear();
117                 aTemp.append(B3DPoint(0.0, 0.0, 0.0));
118                 aTemp.append(B3DPoint(0.0, 0.0, 1.0));
119                 aRetval.append(aTemp);
120 
121                 aTemp.clear();
122                 aTemp.append(B3DPoint(0.0, 1.0, 0.0));
123                 aTemp.append(B3DPoint(0.0, 1.0, 1.0));
124                 aRetval.append(aTemp);
125 
126                 aTemp.clear();
127                 aTemp.append(B3DPoint(1.0, 1.0, 0.0));
128                 aTemp.append(B3DPoint(1.0, 1.0, 1.0));
129                 aRetval.append(aTemp);
130 
131                 aTemp.clear();
132                 aTemp.append(B3DPoint(1.0, 0.0, 0.0));
133                 aTemp.append(B3DPoint(1.0, 0.0, 1.0));
134                 aRetval.append(aTemp);
135             }
136 
137             return aRetval;
138         }
139 
140         B3DPolyPolygon createUnitCubeFillPolyPolygon()
141         {
142             static B3DPolyPolygon aRetval;
143             ::osl::Mutex m_mutex;
144 
145             if(!aRetval.count())
146             {
147                 B3DPolygon aTemp;
148 
149                 // all points
150                 const B3DPoint A(0.0, 0.0, 0.0);
151                 const B3DPoint B(0.0, 1.0, 0.0);
152                 const B3DPoint C(1.0, 1.0, 0.0);
153                 const B3DPoint D(1.0, 0.0, 0.0);
154                 const B3DPoint E(0.0, 0.0, 1.0);
155                 const B3DPoint F(0.0, 1.0, 1.0);
156                 const B3DPoint G(1.0, 1.0, 1.0);
157                 const B3DPoint H(1.0, 0.0, 1.0);
158 
159                 // create bottom
160                 aTemp.append(D);
161                 aTemp.append(A);
162                 aTemp.append(E);
163                 aTemp.append(H);
164                 aTemp.setClosed(true);
165                 aRetval.append(aTemp);
166 
167                 // create front
168                 aTemp.clear();
169                 aTemp.append(B);
170                 aTemp.append(A);
171                 aTemp.append(D);
172                 aTemp.append(C);
173                 aTemp.setClosed(true);
174                 aRetval.append(aTemp);
175 
176                 // create left
177                 aTemp.clear();
178                 aTemp.append(E);
179                 aTemp.append(A);
180                 aTemp.append(B);
181                 aTemp.append(F);
182                 aTemp.setClosed(true);
183                 aRetval.append(aTemp);
184 
185                 // create top
186                 aTemp.clear();
187                 aTemp.append(C);
188                 aTemp.append(G);
189                 aTemp.append(F);
190                 aTemp.append(B);
191                 aTemp.setClosed(true);
192                 aRetval.append(aTemp);
193 
194                 // create right
195                 aTemp.clear();
196                 aTemp.append(H);
197                 aTemp.append(G);
198                 aTemp.append(C);
199                 aTemp.append(D);
200                 aTemp.setClosed(true);
201                 aRetval.append(aTemp);
202 
203                 // create back
204                 aTemp.clear();
205                 aTemp.append(F);
206                 aTemp.append(G);
207                 aTemp.append(H);
208                 aTemp.append(E);
209                 aTemp.setClosed(true);
210                 aRetval.append(aTemp);
211             }
212 
213             return aRetval;
214         }
215 
216         B3DPolyPolygon createCubePolyPolygonFromB3DRange( const B3DRange& rRange)
217         {
218             B3DPolyPolygon aRetval;
219 
220             if(!rRange.isEmpty())
221             {
222                 aRetval = createUnitCubePolyPolygon();
223                 B3DHomMatrix aTrans;
224                 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
225                 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
226                 aRetval.transform(aTrans);
227                 aRetval.removeDoublePoints();
228             }
229 
230             return aRetval;
231         }
232 
233         B3DPolyPolygon createCubeFillPolyPolygonFromB3DRange( const B3DRange& rRange)
234         {
235             B3DPolyPolygon aRetval;
236 
237             if(!rRange.isEmpty())
238             {
239                 aRetval = createUnitCubeFillPolyPolygon();
240                 B3DHomMatrix aTrans;
241                 aTrans.scale(rRange.getWidth(), rRange.getHeight(), rRange.getDepth());
242                 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
243                 aRetval.transform(aTrans);
244                 aRetval.removeDoublePoints();
245             }
246 
247             return aRetval;
248         }
249 
250         // helper for getting the 3D Point from given cartesian coordiantes. fVer is defined from
251         // [F_PI2 .. -F_PI2], fHor from [0.0 .. F_2PI]
252         inline B3DPoint getPointFromCartesian(double fVer, double fHor)
253         {
254             const double fCosHor(cos(fHor));
255             return B3DPoint(fCosHor * cos(fVer), sin(fHor), fCosHor * -sin(fVer));
256         }
257 
258         B3DPolyPolygon createUnitSpherePolyPolygon(
259             sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
260             double fVerStart, double fVerStop,
261             double fHorStart, double fHorStop)
262         {
263             B3DPolyPolygon aRetval;
264             sal_uInt32 a, b;
265 
266             if(!nHorSeg)
267             {
268                 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
269             }
270 
271             if(!nHorSeg)
272             {
273                 nHorSeg = 1L;
274             }
275 
276             if(!nVerSeg)
277             {
278                 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
279             }
280 
281             if(!nVerSeg)
282             {
283                 nVerSeg = 1L;
284             }
285 
286             // create constants
287             const double fVerDiffPerStep((fVerStop - fVerStart) / (double)nVerSeg);
288             const double fHorDiffPerStep((fHorStop - fHorStart) / (double)nHorSeg);
289             bool bHorClosed(fTools::equal(fHorStop - fHorStart, F_2PI));
290             bool bVerFromTop(fTools::equal(fVerStart, F_PI2));
291             bool bVerToBottom(fTools::equal(fVerStop, -F_PI2));
292 
293             // create horizontal rings
294             const sal_uInt32 nLoopVerInit(bVerFromTop ? 1L : 0L);
295             const sal_uInt32 nLoopVerLimit(bVerToBottom ? nVerSeg : nVerSeg + 1L);
296             const sal_uInt32 nLoopHorLimit(bHorClosed ? nHorSeg : nHorSeg + 1L);
297 
298             for(a = nLoopVerInit; a < nLoopVerLimit; a++)
299             {
300                 const double fVer(fVerStart + ((double)(a) * fVerDiffPerStep));
301                 B3DPolygon aNew;
302 
303                 for(b = 0L; b < nLoopHorLimit; b++)
304                 {
305                     const double fHor(fHorStart + ((double)(b) * fHorDiffPerStep));
306                     aNew.append(getPointFromCartesian(fHor, fVer));
307                 }
308 
309                 aNew.setClosed(bHorClosed);
310                 aRetval.append(aNew);
311             }
312 
313             // create vertical half-rings
314             for(a = 0L; a < nLoopHorLimit; a++)
315             {
316                 const double fHor(fHorStart + ((double)(a) * fHorDiffPerStep));
317                 B3DPolygon aNew;
318 
319                 if(bVerFromTop)
320                 {
321                     aNew.append(B3DPoint(0.0, 1.0, 0.0));
322                 }
323 
324                 for(b = nLoopVerInit; b < nLoopVerLimit; b++)
325                 {
326                     const double fVer(fVerStart + ((double)(b) * fVerDiffPerStep));
327                     aNew.append(getPointFromCartesian(fHor, fVer));
328                 }
329 
330                 if(bVerToBottom)
331                 {
332                     aNew.append(B3DPoint(0.0, -1.0, 0.0));
333                 }
334 
335                 aRetval.append(aNew);
336             }
337 
338             return aRetval;
339         }
340 
341         B3DPolyPolygon createSpherePolyPolygonFromB3DRange( const B3DRange& rRange,
342             sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
343             double fVerStart, double fVerStop,
344             double fHorStart, double fHorStop)
345         {
346             B3DPolyPolygon aRetval(createUnitSpherePolyPolygon(nHorSeg, nVerSeg, fVerStart, fVerStop, fHorStart, fHorStop));
347 
348             if(aRetval.count())
349             {
350                 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
351                 B3DHomMatrix aTrans;
352                 aTrans.translate(1.0, 1.0, 1.0);
353                 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
354                 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
355                 aRetval.transform(aTrans);
356             }
357 
358             return aRetval;
359         }
360 
361         B3DPolyPolygon createUnitSphereFillPolyPolygon(
362             sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
363             bool bNormals,
364             double fVerStart, double fVerStop,
365             double fHorStart, double fHorStop)
366         {
367             B3DPolyPolygon aRetval;
368 
369             if(!nHorSeg)
370             {
371                 nHorSeg = fround(fabs(fHorStop - fHorStart) / (F_2PI / 24.0));
372             }
373 
374             if(!nHorSeg)
375             {
376                 nHorSeg = 1L;
377             }
378 
379             if(!nVerSeg)
380             {
381                 nVerSeg = fround(fabs(fVerStop - fVerStart) / (F_2PI / 24.0));
382             }
383 
384             if(!nVerSeg)
385             {
386                 nVerSeg = 1L;
387             }
388 
389             // vertical loop
390             for(sal_uInt32 a(0L); a < nVerSeg; a++)
391             {
392                 const double fVer(fVerStart + (((fVerStop - fVerStart) * a) / nVerSeg));
393                 const double fVer2(fVerStart + (((fVerStop - fVerStart) * (a + 1)) / nVerSeg));
394 
395                 // horizontal loop
396                 for(sal_uInt32 b(0L); b < nHorSeg; b++)
397                 {
398                     const double fHor(fHorStart + (((fHorStop - fHorStart) * b) / nHorSeg));
399                     const double fHor2(fHorStart + (((fHorStop - fHorStart) * (b + 1)) / nHorSeg));
400                     B3DPolygon aNew;
401 
402                     aNew.append(getPointFromCartesian(fHor, fVer));
403                     aNew.append(getPointFromCartesian(fHor2, fVer));
404                     aNew.append(getPointFromCartesian(fHor2, fVer2));
405                     aNew.append(getPointFromCartesian(fHor, fVer2));
406 
407                     if(bNormals)
408                     {
409                         for(sal_uInt32 c(0L); c < aNew.count(); c++)
410                         {
411                             aNew.setNormal(c, ::basegfx::B3DVector(aNew.getB3DPoint(c)));
412                         }
413                     }
414 
415                     aNew.setClosed(true);
416                     aRetval.append(aNew);
417                 }
418             }
419 
420             return aRetval;
421         }
422 
423         B3DPolyPolygon createSphereFillPolyPolygonFromB3DRange( const B3DRange& rRange,
424             sal_uInt32 nHorSeg, sal_uInt32 nVerSeg,
425             bool bNormals,
426             double fVerStart, double fVerStop,
427             double fHorStart, double fHorStop)
428         {
429             B3DPolyPolygon aRetval(createUnitSphereFillPolyPolygon(nHorSeg, nVerSeg, bNormals, fVerStart, fVerStop, fHorStart, fHorStop));
430 
431             if(aRetval.count())
432             {
433                 // move and scale whole construct which is now in [-1.0 .. 1.0] in all directions
434                 B3DHomMatrix aTrans;
435                 aTrans.translate(1.0, 1.0, 1.0);
436                 aTrans.scale(rRange.getWidth() / 2.0, rRange.getHeight() / 2.0, rRange.getDepth() / 2.0);
437                 aTrans.translate(rRange.getMinX(), rRange.getMinY(), rRange.getMinZ());
438                 aRetval.transform(aTrans);
439             }
440 
441             return aRetval;
442         }
443 
444         B3DPolyPolygon applyDefaultNormalsSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter)
445         {
446             B3DPolyPolygon aRetval;
447 
448             for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
449             {
450                 aRetval.append(applyDefaultNormalsSphere(rCandidate.getB3DPolygon(a), rCenter));
451             }
452 
453             return aRetval;
454         }
455 
456         B3DPolyPolygon invertNormals( const B3DPolyPolygon& rCandidate)
457         {
458             B3DPolyPolygon aRetval;
459 
460             for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
461             {
462                 aRetval.append(invertNormals(rCandidate.getB3DPolygon(a)));
463             }
464 
465             return aRetval;
466         }
467 
468         B3DPolyPolygon applyDefaultTextureCoordinatesParallel( const B3DPolyPolygon& rCandidate, const B3DRange& rRange, bool bChangeX, bool bChangeY)
469         {
470             B3DPolyPolygon aRetval;
471 
472             for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
473             {
474                 aRetval.append(applyDefaultTextureCoordinatesParallel(rCandidate.getB3DPolygon(a), rRange, bChangeX, bChangeY));
475             }
476 
477             return aRetval;
478         }
479 
480         B3DPolyPolygon applyDefaultTextureCoordinatesSphere( const B3DPolyPolygon& rCandidate, const B3DPoint& rCenter, bool bChangeX, bool bChangeY)
481         {
482             B3DPolyPolygon aRetval;
483 
484             for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
485             {
486                 aRetval.append(applyDefaultTextureCoordinatesSphere(rCandidate.getB3DPolygon(a), rCenter, bChangeX, bChangeY));
487             }
488 
489             return aRetval;
490         }
491 
492         bool isInside(const B3DPolyPolygon& rCandidate, const B3DPoint& rPoint, bool bWithBorder)
493         {
494             const sal_uInt32 nPolygonCount(rCandidate.count());
495 
496             if(1L == nPolygonCount)
497             {
498                 return isInside(rCandidate.getB3DPolygon(0), rPoint, bWithBorder);
499             }
500             else
501             {
502                 sal_Int32 nInsideCount(0);
503 
504                 for(sal_uInt32 a(0); a < nPolygonCount; a++)
505                 {
506                     const B3DPolygon aPolygon(rCandidate.getB3DPolygon(a));
507                     const bool bInside(isInside(aPolygon, rPoint, bWithBorder));
508 
509                     if(bInside)
510                     {
511                         nInsideCount++;
512                     }
513                 }
514 
515                 return (nInsideCount % 2L);
516             }
517         }
518 
519         //////////////////////////////////////////////////////////////////////
520         // comparators with tolerance for 3D PolyPolygons
521 
522         bool equal(const B3DPolyPolygon& rCandidateA, const B3DPolyPolygon& rCandidateB, const double& rfSmallValue)
523         {
524             const sal_uInt32 nPolygonCount(rCandidateA.count());
525 
526             if(nPolygonCount != rCandidateB.count())
527                 return false;
528 
529             for(sal_uInt32 a(0); a < nPolygonCount; a++)
530             {
531                 const B3DPolygon aCandidate(rCandidateA.getB3DPolygon(a));
532 
533                 if(!equal(aCandidate, rCandidateB.getB3DPolygon(a), rfSmallValue))
534                     return false;
535             }
536 
537             return true;
538         }
539 
540         bool equal(const B3DPolyPolygon& rCandidateA, const B3DPolyPolygon& rCandidateB)
541         {
542             const double fSmallValue(fTools::getSmallValue());
543 
544             return equal(rCandidateA, rCandidateB, fSmallValue);
545         }
546 
547     } // end of namespace tools
548 } // end of namespace basegfx
549 
550 //////////////////////////////////////////////////////////////////////////////
551 
552 // eof
553