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 <drawinglayer/primitive3d/sdrextrudelathetools3d.hxx>
21 :
22 : #include <osl/diagnose.h>
23 : #include <basegfx/polygon/b2dpolypolygon.hxx>
24 : #include <basegfx/range/b2drange.hxx>
25 : #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 : #include <basegfx/matrix/b2dhommatrix.hxx>
27 : #include <basegfx/point/b3dpoint.hxx>
28 : #include <basegfx/polygon/b3dpolygon.hxx>
29 : #include <basegfx/polygon/b3dpolygontools.hxx>
30 : #include <basegfx/polygon/b3dpolypolygontools.hxx>
31 : #include <basegfx/range/b3drange.hxx>
32 : #include <basegfx/matrix/b3dhommatrix.hxx>
33 : #include <basegfx/polygon/b2dpolygontools.hxx>
34 : #include <drawinglayer/geometry/viewinformation3d.hxx>
35 : #include <numeric>
36 :
37 :
38 : // decompositon helpers for extrude/lathe (rotation) objects
39 :
40 : namespace
41 : {
42 :
43 : // common helpers
44 :
45 0 : basegfx::B2DPolyPolygon impScalePolyPolygonOnCenter(
46 : const basegfx::B2DPolyPolygon& rSource,
47 : double fScale)
48 : {
49 0 : basegfx::B2DPolyPolygon aRetval(rSource);
50 :
51 0 : if(!basegfx::fTools::equalZero(fScale))
52 : {
53 0 : const basegfx::B2DRange aRange(basegfx::tools::getRange(rSource));
54 0 : const basegfx::B2DPoint aCenter(aRange.getCenter());
55 0 : basegfx::B2DHomMatrix aTrans;
56 :
57 0 : aTrans.translate(-aCenter.getX(), -aCenter.getY());
58 0 : aTrans.scale(fScale, fScale);
59 0 : aTrans.translate(aCenter.getX(), aCenter.getY());
60 0 : aRetval.transform(aTrans);
61 : }
62 :
63 0 : return aRetval;
64 : }
65 :
66 8290 : void impGetOuterPolyPolygon(
67 : basegfx::B2DPolyPolygon& rPolygon,
68 : basegfx::B2DPolyPolygon& rOuterPolyPolygon,
69 : double fOffset,
70 : bool bCharacterMode)
71 : {
72 8290 : rOuterPolyPolygon = rPolygon;
73 :
74 8290 : if(basegfx::fTools::more(fOffset, 0.0))
75 : {
76 234 : if(bCharacterMode)
77 : {
78 : // grow the outside polygon and scale all polygons to original size. This is done
79 : // to avoid a shrink which potentially would lead to self-intersections, but changes
80 : // the original polygon -> not a precision step, so e.g. not usable for charts
81 234 : const basegfx::B2DRange aRange(basegfx::tools::getRange(rPolygon));
82 234 : rPolygon = basegfx::tools::growInNormalDirection(rPolygon, fOffset);
83 234 : const basegfx::B2DRange aGrownRange(basegfx::tools::getRange(rPolygon));
84 234 : const double fScaleX(basegfx::fTools::equalZero(aGrownRange.getWidth()) ? 1.0 : aRange.getWidth() / aGrownRange.getWidth());
85 234 : const double fScaleY(basegfx::fTools::equalZero(aGrownRange.getHeight())? 1.0 : aRange.getHeight() / aGrownRange.getHeight());
86 234 : basegfx::B2DHomMatrix aScaleTrans;
87 :
88 234 : aScaleTrans.translate(-aGrownRange.getMinX(), -aGrownRange.getMinY());
89 234 : aScaleTrans.scale(fScaleX, fScaleY);
90 234 : aScaleTrans.translate(aRange.getMinX(), aRange.getMinY());
91 234 : rPolygon.transform(aScaleTrans);
92 234 : rOuterPolyPolygon.transform(aScaleTrans);
93 : }
94 : else
95 : {
96 : // use more precision, shrink the outer polygons. Since this may lead to self-intersections,
97 : // some kind of correction should be applied here after that step
98 0 : rOuterPolyPolygon = basegfx::tools::growInNormalDirection(rPolygon, -fOffset);
99 0 : basegfx::tools::correctGrowShrinkPolygonPair(rPolygon, rOuterPolyPolygon);
100 : }
101 : }
102 8290 : }
103 :
104 3149 : void impAddInBetweenFill(
105 : basegfx::B3DPolyPolygon& rTarget,
106 : const basegfx::B3DPolyPolygon& rPolA,
107 : const basegfx::B3DPolyPolygon& rPolB,
108 : double fTexVerStart,
109 : double fTexVerStop,
110 : bool bCreateNormals,
111 : bool bCreateTextureCoordinates)
112 : {
113 : OSL_ENSURE(rPolA.count() == rPolB.count(), "impAddInBetweenFill: unequally sized polygons (!)");
114 3149 : const sal_uInt32 nPolygonCount(::std::min(rPolA.count(), rPolB.count()));
115 :
116 10906 : for(sal_uInt32 a(0L); a < nPolygonCount; a++)
117 : {
118 7757 : const basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a));
119 15514 : const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a));
120 : OSL_ENSURE(aSubA.count() == aSubB.count(), "impAddInBetweenFill: unequally sized polygons (!)");
121 7757 : const sal_uInt32 nPointCount(::std::min(aSubA.count(), aSubB.count()));
122 :
123 7757 : if(nPointCount)
124 : {
125 7757 : const sal_uInt32 nEdgeCount(aSubA.isClosed() ? nPointCount : nPointCount - 1L);
126 7757 : double fTexHorMultiplicatorA(0.0), fTexHorMultiplicatorB(0.0);
127 7757 : double fPolygonPosA(0.0), fPolygonPosB(0.0);
128 :
129 7757 : if(bCreateTextureCoordinates)
130 : {
131 7680 : const double fPolygonLengthA(basegfx::tools::getLength(aSubA));
132 7680 : fTexHorMultiplicatorA = basegfx::fTools::equalZero(fPolygonLengthA) ? 1.0 : 1.0 / fPolygonLengthA;
133 :
134 7680 : const double fPolygonLengthB(basegfx::tools::getLength(aSubB));
135 7680 : fTexHorMultiplicatorB = basegfx::fTools::equalZero(fPolygonLengthB) ? 1.0 : 1.0 / fPolygonLengthB;
136 : }
137 :
138 15745 : for(sal_uInt32 b(0L); b < nEdgeCount; b++)
139 : {
140 7988 : const sal_uInt32 nIndexA(b);
141 7988 : const sal_uInt32 nIndexB((b + 1L) % nPointCount);
142 :
143 7988 : const basegfx::B3DPoint aStartA(aSubA.getB3DPoint(nIndexA));
144 15976 : const basegfx::B3DPoint aEndA(aSubA.getB3DPoint(nIndexB));
145 15976 : const basegfx::B3DPoint aStartB(aSubB.getB3DPoint(nIndexA));
146 15976 : const basegfx::B3DPoint aEndB(aSubB.getB3DPoint(nIndexB));
147 :
148 15976 : basegfx::B3DPolygon aNew;
149 7988 : aNew.setClosed(true);
150 :
151 7988 : aNew.append(aStartA);
152 7988 : aNew.append(aStartB);
153 7988 : aNew.append(aEndB);
154 7988 : aNew.append(aEndA);
155 :
156 7988 : if(bCreateNormals)
157 : {
158 7988 : aNew.setNormal(0L, aSubA.getNormal(nIndexA));
159 7988 : aNew.setNormal(1L, aSubB.getNormal(nIndexA));
160 7988 : aNew.setNormal(2L, aSubB.getNormal(nIndexB));
161 7988 : aNew.setNormal(3L, aSubA.getNormal(nIndexB));
162 : }
163 :
164 7988 : if(bCreateTextureCoordinates)
165 : {
166 7680 : const double fRelTexAL(fPolygonPosA * fTexHorMultiplicatorA);
167 7680 : const double fEdgeLengthA(basegfx::B3DVector(aEndA - aStartA).getLength());
168 7680 : fPolygonPosA += fEdgeLengthA;
169 7680 : const double fRelTexAR(fPolygonPosA * fTexHorMultiplicatorA);
170 :
171 7680 : const double fRelTexBL(fPolygonPosB * fTexHorMultiplicatorB);
172 7680 : const double fEdgeLengthB(basegfx::B3DVector(aEndB - aStartB).getLength());
173 7680 : fPolygonPosB += fEdgeLengthB;
174 7680 : const double fRelTexBR(fPolygonPosB * fTexHorMultiplicatorB);
175 :
176 7680 : aNew.setTextureCoordinate(0L, basegfx::B2DPoint(fRelTexAL, fTexVerStart));
177 7680 : aNew.setTextureCoordinate(1L, basegfx::B2DPoint(fRelTexBL, fTexVerStop));
178 7680 : aNew.setTextureCoordinate(2L, basegfx::B2DPoint(fRelTexBR, fTexVerStop));
179 7680 : aNew.setTextureCoordinate(3L, basegfx::B2DPoint(fRelTexAR, fTexVerStart));
180 : }
181 :
182 7988 : rTarget.append(aNew);
183 7988 : }
184 : }
185 7757 : }
186 3149 : }
187 :
188 154 : void impSetNormal(
189 : basegfx::B3DPolyPolygon& rCandidate,
190 : const basegfx::B3DVector& rNormal)
191 : {
192 308 : for(sal_uInt32 a(0L); a < rCandidate.count(); a++)
193 : {
194 154 : basegfx::B3DPolygon aSub(rCandidate.getB3DPolygon(a));
195 :
196 770 : for(sal_uInt32 b(0L); b < aSub.count(); b++)
197 : {
198 616 : aSub.setNormal(b, rNormal);
199 : }
200 :
201 154 : rCandidate.setB3DPolygon(a, aSub);
202 154 : }
203 154 : }
204 :
205 9293 : void impCreateInBetweenNormals(
206 : basegfx::B3DPolyPolygon& rPolA,
207 : basegfx::B3DPolyPolygon& rPolB,
208 : bool bSmoothHorizontalNormals)
209 : {
210 : OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
211 9293 : const sal_uInt32 nPolygonCount(::std::min(rPolA.count(), rPolB.count()));
212 :
213 32410 : for(sal_uInt32 a(0L); a < nPolygonCount; a++)
214 : {
215 23117 : basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a));
216 46234 : basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a));
217 : OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
218 23117 : const sal_uInt32 nPointCount(::std::min(aSubA.count(), aSubB.count()));
219 :
220 23117 : if(nPointCount)
221 : {
222 23117 : basegfx::B3DPoint aPrevA(aSubA.getB3DPoint(nPointCount - 1L));
223 46234 : basegfx::B3DPoint aCurrA(aSubA.getB3DPoint(0L));
224 23117 : const bool bClosed(aSubA.isClosed());
225 :
226 69505 : for(sal_uInt32 b(0L); b < nPointCount; b++)
227 : {
228 46388 : const sal_uInt32 nIndNext((b + 1L) % nPointCount);
229 46388 : const basegfx::B3DPoint aNextA(aSubA.getB3DPoint(nIndNext));
230 92776 : const basegfx::B3DPoint aCurrB(aSubB.getB3DPoint(b));
231 :
232 : // vector to back
233 92776 : basegfx::B3DVector aDepth(aCurrB - aCurrA);
234 46388 : aDepth.normalize();
235 :
236 46388 : if(aDepth.equalZero())
237 : {
238 : // no difference, try to get depth from next point
239 16896 : const basegfx::B3DPoint aNextB(aSubB.getB3DPoint(nIndNext));
240 16896 : aDepth = aNextB - aNextA;
241 16896 : aDepth.normalize();
242 : }
243 :
244 : // vector to left (correct for non-closed lines)
245 46388 : const bool bFirstAndNotClosed(!bClosed && 0L == b);
246 92776 : basegfx::B3DVector aLeft(bFirstAndNotClosed ? aCurrA - aNextA : aPrevA - aCurrA);
247 46388 : aLeft.normalize();
248 :
249 : // create left normal
250 92776 : const basegfx::B3DVector aNormalLeft(aDepth.getPerpendicular(aLeft));
251 :
252 46388 : if(bSmoothHorizontalNormals)
253 : {
254 : // vector to right (correct for non-closed lines)
255 46388 : const bool bLastAndNotClosed(!bClosed && b + 1L == nPointCount);
256 46388 : basegfx::B3DVector aRight(bLastAndNotClosed ? aCurrA - aPrevA : aNextA - aCurrA);
257 46388 : aRight.normalize();
258 :
259 : // create right normal
260 92776 : const basegfx::B3DVector aNormalRight(aRight.getPerpendicular(aDepth));
261 :
262 : // create smoothed in-between normal
263 92776 : basegfx::B3DVector aNewNormal(aNormalLeft + aNormalRight);
264 46388 : aNewNormal.normalize();
265 :
266 : // set as new normal at polygons
267 46388 : aSubA.setNormal(b, aNewNormal);
268 92776 : aSubB.setNormal(b, aNewNormal);
269 : }
270 : else
271 : {
272 : // set aNormalLeft as new normal at polygons
273 0 : aSubA.setNormal(b, aNormalLeft);
274 0 : aSubB.setNormal(b, aNormalLeft);
275 : }
276 :
277 : // prepare next step
278 46388 : aPrevA = aCurrA;
279 46388 : aCurrA = aNextA;
280 46388 : }
281 :
282 23117 : rPolA.setB3DPolygon(a, aSubA);
283 46234 : rPolB.setB3DPolygon(a, aSubB);
284 : }
285 23117 : }
286 9293 : }
287 :
288 6298 : void impMixNormals(
289 : basegfx::B3DPolyPolygon& rPolA,
290 : const basegfx::B3DPolyPolygon& rPolB,
291 : double fWeightA)
292 : {
293 6298 : const double fWeightB(1.0 - fWeightA);
294 : OSL_ENSURE(rPolA.count() == rPolB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
295 6298 : const sal_uInt32 nPolygonCount(::std::min(rPolA.count(), rPolB.count()));
296 :
297 21812 : for(sal_uInt32 a(0L); a < nPolygonCount; a++)
298 : {
299 15514 : basegfx::B3DPolygon aSubA(rPolA.getB3DPolygon(a));
300 31028 : const basegfx::B3DPolygon aSubB(rPolB.getB3DPolygon(a));
301 : OSL_ENSURE(aSubA.count() == aSubB.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
302 15514 : const sal_uInt32 nPointCount(::std::min(aSubA.count(), aSubB.count()));
303 :
304 46850 : for(sal_uInt32 b(0L); b < nPointCount; b++)
305 : {
306 31336 : const basegfx::B3DVector aVA(aSubA.getNormal(b) * fWeightA);
307 62672 : const basegfx::B3DVector aVB(aSubB.getNormal(b) * fWeightB);
308 62672 : basegfx::B3DVector aVNew(aVA + aVB);
309 31336 : aVNew.normalize();
310 31336 : aSubA.setNormal(b, aVNew);
311 31336 : }
312 :
313 15514 : rPolA.setB3DPolygon(a, aSubA);
314 15514 : }
315 6298 : }
316 :
317 2120 : bool impHasCutWith(const basegfx::B2DPolygon& rPoly, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd)
318 : {
319 : // polygon is closed, one of the points is a member
320 2120 : const sal_uInt32 nPointCount(rPoly.count());
321 :
322 2120 : if(nPointCount)
323 : {
324 2120 : basegfx::B2DPoint aCurrent(rPoly.getB2DPoint(0));
325 3288 : const basegfx::B2DVector aVector(rEnd - rStart);
326 :
327 52506 : for(sal_uInt32 a(0); a < nPointCount; a++)
328 : {
329 51338 : const sal_uInt32 nNextIndex((a + 1) % nPointCount);
330 51338 : const basegfx::B2DPoint aNext(rPoly.getB2DPoint(nNextIndex));
331 101724 : const basegfx::B2DVector aEdgeVector(aNext - aCurrent);
332 :
333 51338 : if(basegfx::tools::findCut(
334 : rStart, aVector,
335 51338 : aCurrent, aEdgeVector) != CutFlagValue::NONE)
336 : {
337 952 : return true;
338 : }
339 :
340 50386 : aCurrent = aNext;
341 51554 : }
342 : }
343 :
344 1168 : return false;
345 : }
346 : } // end of anonymous namespace
347 :
348 :
349 :
350 : namespace drawinglayer
351 : {
352 : namespace primitive3d
353 : {
354 183 : void createLatheSlices(
355 : Slice3DVector& rSliceVector,
356 : const basegfx::B2DPolyPolygon& rSource,
357 : double fBackScale,
358 : double fDiagonal,
359 : double fRotation,
360 : sal_uInt32 nSteps,
361 : bool bCharacterMode,
362 : bool bCloseFront,
363 : bool bCloseBack)
364 : {
365 183 : if(basegfx::fTools::equalZero(fRotation) || 0L == nSteps)
366 : {
367 : // no rotation or no steps, just one plane
368 0 : rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix()));
369 : }
370 : else
371 : {
372 183 : const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0));
373 183 : const bool bClosedRotation(!bBackScale && basegfx::fTools::equal(fRotation, F_2PI));
374 183 : basegfx::B2DPolyPolygon aFront(rSource);
375 366 : basegfx::B2DPolyPolygon aBack(rSource);
376 366 : basegfx::B3DHomMatrix aTransformBack;
377 366 : basegfx::B2DPolyPolygon aOuterBack;
378 :
379 183 : if(bClosedRotation)
380 : {
381 183 : bCloseFront = bCloseBack = false;
382 : }
383 :
384 183 : if(bBackScale)
385 : {
386 : // avoid null zoom
387 0 : if(basegfx::fTools::equalZero(fBackScale))
388 : {
389 0 : fBackScale = 0.000001;
390 : }
391 :
392 : // back is scaled compared to front, create scaled version
393 0 : aBack = impScalePolyPolygonOnCenter(aBack, fBackScale);
394 : }
395 :
396 183 : if(bCloseFront || bCloseBack)
397 : {
398 0 : const basegfx::B2DRange aBaseRange(basegfx::tools::getRange(aFront));
399 0 : const double fOuterLength(aBaseRange.getMaxX() * fRotation);
400 0 : const double fInnerLength(aBaseRange.getMinX() * fRotation);
401 0 : const double fAverageLength((fOuterLength + fInnerLength) * 0.5);
402 :
403 0 : if(bCloseFront)
404 : {
405 0 : const double fOffsetLen((fAverageLength / 12.0) * fDiagonal);
406 0 : basegfx::B2DPolyPolygon aOuterFront;
407 0 : impGetOuterPolyPolygon(aFront, aOuterFront, fOffsetLen, bCharacterMode);
408 0 : basegfx::B3DHomMatrix aTransform;
409 0 : aTransform.translate(0.0, 0.0, fOffsetLen);
410 0 : rSliceVector.push_back(Slice3D(aOuterFront, aTransform, SLICETYPE3D_FRONTCAP));
411 : }
412 :
413 0 : if(bCloseBack)
414 : {
415 0 : const double fOffsetLen((fAverageLength / 12.0) * fDiagonal);
416 0 : impGetOuterPolyPolygon(aBack, aOuterBack, fOffsetLen, bCharacterMode);
417 0 : aTransformBack.translate(0.0, 0.0, -fOffsetLen);
418 0 : aTransformBack.rotate(0.0, fRotation, 0.0);
419 : }
420 : }
421 :
422 : // add start polygon (a = 0L)
423 183 : if(!bClosedRotation)
424 : {
425 0 : rSliceVector.push_back(Slice3D(aFront, basegfx::B3DHomMatrix()));
426 : }
427 :
428 : // create segments (a + 1 .. nSteps)
429 183 : const double fStepSize(1.0 / (double)nSteps);
430 :
431 5535 : for(sal_uInt32 a(0L); a < nSteps; a++)
432 : {
433 5352 : const double fStep((double)(a + 1L) * fStepSize);
434 5352 : basegfx::B2DPolyPolygon aNewPoly(bBackScale ? basegfx::tools::interpolate(aFront, aBack, fStep) : aFront);
435 10704 : basegfx::B3DHomMatrix aNewMat;
436 5352 : aNewMat.rotate(0.0, fRotation * fStep, 0.0);
437 5352 : rSliceVector.push_back(Slice3D(aNewPoly, aNewMat));
438 5352 : }
439 :
440 183 : if(bCloseBack)
441 : {
442 0 : rSliceVector.push_back(Slice3D(aOuterBack, aTransformBack, SLICETYPE3D_BACKCAP));
443 183 : }
444 : }
445 183 : }
446 :
447 4145 : void createExtrudeSlices(
448 : Slice3DVector& rSliceVector,
449 : const basegfx::B2DPolyPolygon& rSource,
450 : double fBackScale,
451 : double fDiagonal,
452 : double fDepth,
453 : bool bCharacterMode,
454 : bool bCloseFront,
455 : bool bCloseBack)
456 : {
457 4145 : if(basegfx::fTools::equalZero(fDepth))
458 : {
459 : // no depth, just one plane
460 0 : rSliceVector.push_back(Slice3D(rSource, basegfx::B3DHomMatrix()));
461 : }
462 : else
463 : {
464 : // there is depth, create Polygons for front,back and their default depth positions
465 4145 : basegfx::B2DPolyPolygon aFront(rSource);
466 8290 : basegfx::B2DPolyPolygon aBack(rSource);
467 4145 : const bool bBackScale(!basegfx::fTools::equal(fBackScale, 1.0));
468 4145 : double fZFront(fDepth); // default depth for aFront
469 4145 : double fZBack(0.0); // default depth for aBack
470 8290 : basegfx::B2DPolyPolygon aOuterBack;
471 :
472 4145 : if(bBackScale)
473 : {
474 : // avoid null zoom
475 0 : if(basegfx::fTools::equalZero(fBackScale))
476 : {
477 0 : fBackScale = 0.000001;
478 : }
479 :
480 : // aFront is scaled compared to aBack, create scaled version
481 0 : aFront = impScalePolyPolygonOnCenter(aFront, fBackScale);
482 : }
483 :
484 4145 : if(bCloseFront)
485 : {
486 4145 : const double fOffset(fDepth * fDiagonal * 0.5);
487 4145 : fZFront = fDepth - fOffset;
488 4145 : basegfx::B2DPolyPolygon aOuterFront;
489 4145 : impGetOuterPolyPolygon(aFront, aOuterFront, fOffset, bCharacterMode);
490 8290 : basegfx::B3DHomMatrix aTransformFront;
491 4145 : aTransformFront.translate(0.0, 0.0, fDepth);
492 8290 : rSliceVector.push_back(Slice3D(aOuterFront, aTransformFront, SLICETYPE3D_FRONTCAP));
493 : }
494 :
495 4145 : if(bCloseBack)
496 : {
497 4145 : const double fOffset(fDepth * fDiagonal * 0.5);
498 4145 : fZBack = fOffset;
499 4145 : impGetOuterPolyPolygon(aBack, aOuterBack, fOffset, bCharacterMode);
500 : }
501 :
502 : // add front and back polygons at evtl. changed depths
503 : {
504 8290 : basegfx::B3DHomMatrix aTransformA, aTransformB;
505 :
506 4145 : aTransformA.translate(0.0, 0.0, fZFront);
507 4145 : rSliceVector.push_back(Slice3D(aFront, aTransformA));
508 :
509 4145 : aTransformB.translate(0.0, 0.0, fZBack);
510 8290 : rSliceVector.push_back(Slice3D(aBack, aTransformB));
511 : }
512 :
513 4145 : if(bCloseBack)
514 : {
515 4145 : rSliceVector.push_back(Slice3D(aOuterBack, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP));
516 4145 : }
517 : }
518 4145 : }
519 :
520 48 : basegfx::B3DPolyPolygon extractHorizontalLinesFromSlice(const Slice3DVector& rSliceVector, bool bCloseHorLines)
521 : {
522 48 : basegfx::B3DPolyPolygon aRetval;
523 48 : const sal_uInt32 nNumSlices(rSliceVector.size());
524 :
525 48 : if(nNumSlices)
526 : {
527 48 : const sal_uInt32 nSlideSubPolygonCount(rSliceVector[0].getB3DPolyPolygon().count());
528 :
529 168 : for(sal_uInt32 b(0); b < nSlideSubPolygonCount; b++)
530 : {
531 120 : const sal_uInt32 nSubPolygonPointCount(rSliceVector[0].getB3DPolyPolygon().getB3DPolygon(b).count());
532 :
533 360 : for(sal_uInt32 c(0); c < nSubPolygonPointCount; c++)
534 : {
535 240 : basegfx::B3DPolygon aNew;
536 :
537 7920 : for(sal_uInt32 d(0); d < nNumSlices; d++)
538 : {
539 7680 : const bool bSamePolygonCount(nSlideSubPolygonCount == rSliceVector[d].getB3DPolyPolygon().count());
540 7680 : const bool bSamePointCount(nSubPolygonPointCount == rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).count());
541 :
542 7680 : if(bSamePolygonCount && bSamePointCount)
543 : {
544 7680 : aNew.append(rSliceVector[d].getB3DPolyPolygon().getB3DPolygon(b).getB3DPoint(c));
545 : }
546 : else
547 : {
548 : OSL_ENSURE(bSamePolygonCount, "Slice tools::PolyPolygon with different Polygon count (!)");
549 : OSL_ENSURE(bSamePointCount, "Slice Polygon with different point count (!)");
550 : }
551 : }
552 :
553 240 : aNew.setClosed(bCloseHorLines);
554 240 : aRetval.append(aNew);
555 240 : }
556 : }
557 : }
558 :
559 48 : return aRetval;
560 : }
561 :
562 0 : basegfx::B3DPolyPolygon extractVerticalLinesFromSlice(const Slice3DVector& rSliceVector)
563 : {
564 0 : basegfx::B3DPolyPolygon aRetval;
565 0 : const sal_uInt32 nNumSlices(rSliceVector.size());
566 :
567 0 : for(sal_uInt32 a(0L); a < nNumSlices; a++)
568 : {
569 0 : aRetval.append(rSliceVector[a].getB3DPolyPolygon());
570 : }
571 :
572 0 : return aRetval;
573 : }
574 :
575 173 : void extractPlanesFromSlice(
576 : ::std::vector< basegfx::B3DPolyPolygon >& rFill,
577 : const Slice3DVector& rSliceVector,
578 : bool bCreateNormals,
579 : bool bSmoothHorizontalNormals,
580 : bool bSmoothNormals,
581 : bool bSmoothLids,
582 : bool bClosed,
583 : double fSmoothNormalsMix,
584 : double fSmoothLidsMix,
585 : bool bCreateTextureCoordinates,
586 : const basegfx::B2DHomMatrix& rTexTransform)
587 : {
588 173 : const sal_uInt32 nNumSlices(rSliceVector.size());
589 :
590 173 : if(nNumSlices)
591 : {
592 : // common parameters
593 173 : const sal_uInt32 nLoopCount(bClosed ? nNumSlices : nNumSlices - 1L);
594 173 : basegfx::B3DPolyPolygon aEdgeRounding;
595 : sal_uInt32 a;
596 :
597 : // tetxture parameters
598 173 : double fInvTexHeight(1.0);
599 173 : double fTexHeightPos(0.0);
600 173 : double fTexStart(0.0);
601 173 : double fTexStop(1.0);
602 346 : ::std::vector<double> aTexHeightArray;
603 173 : basegfx::B3DRange aTexRangeFront;
604 173 : basegfx::B3DRange aTexRangeBack;
605 :
606 173 : if(bCreateTextureCoordinates)
607 : {
608 96 : aTexRangeFront = basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon());
609 96 : aTexRangeBack = basegfx::tools::getRange(rSliceVector[nNumSlices - 1L].getB3DPolyPolygon());
610 :
611 96 : if(aTexRangeBack.getDepth() > aTexRangeBack.getWidth())
612 : {
613 : // last polygon is rotated so that depth is bigger than width, exchange X and Z
614 : // for making applyDefaultTextureCoordinatesParallel use Z instead of X for
615 : // horizontal texture coordinate
616 : aTexRangeBack = basegfx::B3DRange(
617 : aTexRangeBack.getMinZ(), aTexRangeBack.getMinY(), aTexRangeBack.getMinX(),
618 0 : aTexRangeBack.getMaxZ(), aTexRangeBack.getMaxY(), aTexRangeBack.getMaxX());
619 : }
620 :
621 96 : basegfx::B3DPoint aCenter(basegfx::tools::getRange(rSliceVector[0L].getB3DPolyPolygon()).getCenter());
622 :
623 3168 : for(a = 0L; a < nLoopCount; a++)
624 : {
625 3072 : const basegfx::B3DPoint aNextCenter(basegfx::tools::getRange(rSliceVector[(a + 1L) % nNumSlices].getB3DPolyPolygon()).getCenter());
626 3072 : const double fLength(basegfx::B3DVector(aNextCenter - aCenter).getLength());
627 3072 : aTexHeightArray.push_back(fLength);
628 3072 : aCenter = aNextCenter;
629 3072 : }
630 :
631 96 : const double fTexHeight(::std::accumulate(aTexHeightArray.begin(), aTexHeightArray.end(), 0.0));
632 :
633 96 : if(!basegfx::fTools::equalZero(fTexHeight))
634 : {
635 96 : fInvTexHeight = 1.0 / fTexHeight;
636 96 : }
637 : }
638 :
639 173 : if(nLoopCount)
640 : {
641 3476 : for(a = 0L; a < nLoopCount; a++)
642 : {
643 3303 : const Slice3D& rSliceA(rSliceVector[a]);
644 3303 : const Slice3D& rSliceB(rSliceVector[(a + 1L) % nNumSlices]);
645 3303 : const bool bAcceptPair(SLICETYPE3D_REGULAR == rSliceA.getSliceType() && SLICETYPE3D_REGULAR == rSliceB.getSliceType());
646 3303 : basegfx::B3DPolyPolygon aPolA(rSliceA.getB3DPolyPolygon());
647 6606 : basegfx::B3DPolyPolygon aPolB(rSliceB.getB3DPolyPolygon());
648 :
649 3303 : if(bAcceptPair)
650 : {
651 3149 : if(bCreateNormals)
652 : {
653 3149 : impCreateInBetweenNormals(aPolB, aPolA, bSmoothHorizontalNormals);
654 : }
655 :
656 : {
657 3149 : const sal_uInt32 nIndPrev((a + nNumSlices - 1L) % nNumSlices);
658 3149 : const Slice3D& rSlicePrev(rSliceVector[nIndPrev]);
659 3149 : basegfx::B3DPolyPolygon aPrev(rSlicePrev.getB3DPolyPolygon());
660 6298 : basegfx::B3DPolyPolygon aPolAA(rSliceA.getB3DPolyPolygon());
661 :
662 3149 : if(SLICETYPE3D_FRONTCAP == rSlicePrev.getSliceType())
663 : {
664 77 : basegfx::B3DPolyPolygon aFront(rSlicePrev.getB3DPolyPolygon());
665 77 : const bool bHasSlant(aPolAA != aPrev);
666 :
667 77 : if(bCreateTextureCoordinates)
668 : {
669 0 : aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront);
670 : }
671 :
672 77 : if(bCreateNormals)
673 : {
674 77 : basegfx::B3DVector aNormal(0.0, 0.0, -1.0);
675 :
676 77 : if(aFront.count())
677 : {
678 77 : aNormal = -aFront.getB3DPolygon(0L).getNormal();
679 : }
680 :
681 77 : impSetNormal(aFront, aNormal);
682 :
683 77 : if(bHasSlant)
684 : {
685 0 : impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals);
686 :
687 0 : if(bSmoothNormals)
688 : {
689 : // smooth and copy
690 0 : impMixNormals(aPolA, aPolAA, fSmoothNormalsMix);
691 0 : aPolAA = aPolA;
692 : }
693 : else
694 : {
695 : // take over from surface
696 0 : aPolAA = aPolA;
697 : }
698 :
699 0 : if(bSmoothLids)
700 : {
701 : // smooth and copy
702 0 : impMixNormals(aFront, aPrev, fSmoothLidsMix);
703 0 : aPrev = aFront;
704 : }
705 : else
706 : {
707 : // take over from front
708 0 : aPrev = aFront;
709 : }
710 : }
711 : else
712 : {
713 77 : if(bSmoothNormals)
714 : {
715 : // smooth
716 77 : impMixNormals(aPolA, aFront, fSmoothNormalsMix);
717 : }
718 :
719 77 : if(bSmoothLids)
720 : {
721 : // smooth and copy
722 0 : impMixNormals(aFront, aPolA, fSmoothLidsMix);
723 0 : aPolA = aFront;
724 : }
725 77 : }
726 : }
727 :
728 77 : if(bHasSlant)
729 : {
730 0 : if(bCreateTextureCoordinates)
731 : {
732 0 : fTexStart = fTexHeightPos * fInvTexHeight;
733 0 : fTexStop = (fTexHeightPos - aTexHeightArray[(a + nLoopCount - 1L) % nLoopCount]) * fInvTexHeight;
734 : }
735 :
736 0 : impAddInBetweenFill(aEdgeRounding, aPolAA, aPrev, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
737 : }
738 :
739 77 : aFront.flip();
740 77 : rFill.push_back(aFront);
741 : }
742 : else
743 : {
744 3072 : if(bCreateNormals && bSmoothNormals && (nIndPrev != a + 1L))
745 : {
746 3072 : impCreateInBetweenNormals(aPolAA, aPrev, bSmoothHorizontalNormals);
747 3072 : impMixNormals(aPolA, aPolAA, 0.5);
748 : }
749 3149 : }
750 : }
751 :
752 : {
753 3149 : const sal_uInt32 nIndNext((a + 2L) % nNumSlices);
754 3149 : const Slice3D& rSliceNext(rSliceVector[nIndNext]);
755 3149 : basegfx::B3DPolyPolygon aNext(rSliceNext.getB3DPolyPolygon());
756 6298 : basegfx::B3DPolyPolygon aPolBB(rSliceB.getB3DPolyPolygon());
757 :
758 3149 : if(SLICETYPE3D_BACKCAP == rSliceNext.getSliceType())
759 : {
760 77 : basegfx::B3DPolyPolygon aBack(rSliceNext.getB3DPolyPolygon());
761 77 : const bool bHasSlant(aPolBB != aNext);
762 :
763 77 : if(bCreateTextureCoordinates)
764 : {
765 0 : aBack = basegfx::tools::applyDefaultTextureCoordinatesParallel(aBack, aTexRangeBack);
766 : }
767 :
768 77 : if(bCreateNormals)
769 : {
770 77 : const basegfx::B3DVector aNormal(aBack.count() ? aBack.getB3DPolygon(0L).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0));
771 77 : impSetNormal(aBack, aNormal);
772 :
773 77 : if(bHasSlant)
774 : {
775 0 : impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals);
776 :
777 0 : if(bSmoothNormals)
778 : {
779 : // smooth and copy
780 0 : impMixNormals(aPolB, aPolBB, fSmoothNormalsMix);
781 0 : aPolBB = aPolB;
782 : }
783 : else
784 : {
785 : // take over from surface
786 0 : aPolBB = aPolB;
787 : }
788 :
789 0 : if(bSmoothLids)
790 : {
791 : // smooth and copy
792 0 : impMixNormals(aBack, aNext, fSmoothLidsMix);
793 0 : aNext = aBack;
794 : }
795 : else
796 : {
797 : // take over from back
798 0 : aNext = aBack;
799 : }
800 : }
801 : else
802 : {
803 77 : if(bSmoothNormals)
804 : {
805 : // smooth
806 77 : impMixNormals(aPolB, aBack, fSmoothNormalsMix);
807 : }
808 :
809 77 : if(bSmoothLids)
810 : {
811 : // smooth and copy
812 0 : impMixNormals(aBack, aPolB, fSmoothLidsMix);
813 0 : aPolB = aBack;
814 : }
815 77 : }
816 : }
817 :
818 77 : if(bHasSlant)
819 : {
820 0 : if(bCreateTextureCoordinates)
821 : {
822 0 : fTexStart = (fTexHeightPos + aTexHeightArray[a] + aTexHeightArray[(a + 1L) % nLoopCount]) * fInvTexHeight;
823 0 : fTexStop = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight;
824 : }
825 :
826 0 : impAddInBetweenFill(aEdgeRounding, aNext, aPolBB, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
827 : }
828 :
829 77 : rFill.push_back(aBack);
830 : }
831 : else
832 : {
833 3072 : if(bCreateNormals && bSmoothNormals && (nIndNext != a))
834 : {
835 3072 : impCreateInBetweenNormals(aNext, aPolBB, bSmoothHorizontalNormals);
836 3072 : impMixNormals(aPolB, aPolBB, 0.5);
837 : }
838 3149 : }
839 : }
840 :
841 3149 : if(bCreateTextureCoordinates)
842 : {
843 3072 : fTexStart = (fTexHeightPos + aTexHeightArray[a]) * fInvTexHeight;
844 3072 : fTexStop = fTexHeightPos * fInvTexHeight;
845 : }
846 :
847 3149 : impAddInBetweenFill(aEdgeRounding, aPolB, aPolA, fTexStart, fTexStop, bCreateNormals, bCreateTextureCoordinates);
848 : }
849 :
850 3303 : if(bCreateTextureCoordinates)
851 : {
852 3072 : fTexHeightPos += aTexHeightArray[a];
853 : }
854 3303 : }
855 : }
856 : else
857 : {
858 : // no loop, but a single slice (1 == nNumSlices), create a filling from the single
859 : // front plane
860 0 : const Slice3D& rSlice(rSliceVector[0]);
861 0 : basegfx::B3DPolyPolygon aFront(rSlice.getB3DPolyPolygon());
862 :
863 0 : if(bCreateTextureCoordinates)
864 : {
865 0 : aFront = basegfx::tools::applyDefaultTextureCoordinatesParallel(aFront, aTexRangeFront);
866 : }
867 :
868 0 : if(bCreateNormals)
869 : {
870 0 : basegfx::B3DVector aNormal(0.0, 0.0, -1.0);
871 :
872 0 : if(aFront.count())
873 : {
874 0 : aNormal = -aFront.getB3DPolygon(0L).getNormal();
875 : }
876 :
877 0 : impSetNormal(aFront, aNormal);
878 : }
879 :
880 0 : aFront.flip();
881 0 : rFill.push_back(aFront);
882 : }
883 :
884 173 : if(bCreateTextureCoordinates)
885 : {
886 96 : aEdgeRounding.transformTextureCoordiantes(rTexTransform);
887 : }
888 :
889 8161 : for(a = 0L; a < aEdgeRounding.count(); a++)
890 : {
891 7988 : rFill.push_back(basegfx::B3DPolyPolygon(aEdgeRounding.getB3DPolygon(a)));
892 173 : }
893 : }
894 173 : }
895 :
896 192 : void createReducedOutlines(
897 : const geometry::ViewInformation3D& rViewInformation,
898 : const basegfx::B3DHomMatrix& rObjectTransform,
899 : const basegfx::B3DPolygon& rLoopA,
900 : const basegfx::B3DPolygon& rLoopB,
901 : basegfx::B3DPolyPolygon& rTarget)
902 : {
903 192 : const sal_uInt32 nPointCount(rLoopA.count());
904 :
905 : // with idetic polygons there are no outlines
906 192 : if(rLoopA != rLoopB)
907 : {
908 120 : if(nPointCount && nPointCount == rLoopB.count())
909 : {
910 120 : const basegfx::B3DHomMatrix aObjectTransform(rViewInformation.getObjectToView() * rObjectTransform);
911 240 : const basegfx::B2DPolygon a2DLoopA(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopA, aObjectTransform));
912 240 : const basegfx::B2DPolygon a2DLoopB(basegfx::tools::createB2DPolygonFromB3DPolygon(rLoopB, aObjectTransform));
913 240 : const basegfx::B2DPoint a2DCenterA(a2DLoopA.getB2DRange().getCenter());
914 240 : const basegfx::B2DPoint a2DCenterB(a2DLoopB.getB2DRange().getCenter());
915 :
916 : // without detectable Y-Axis there are no outlines
917 120 : if(!a2DCenterA.equal(a2DCenterB))
918 : {
919 : // search for outmost left and right inter-loop-edges which do not cut the loops
920 48 : const basegfx::B2DPoint aCommonCenter(basegfx::average(a2DCenterA, a2DCenterB));
921 96 : const basegfx::B2DVector aAxisVector(a2DCenterA - a2DCenterB);
922 48 : double fMaxLeft(0.0);
923 48 : double fMaxRight(0.0);
924 48 : sal_uInt32 nIndexLeft(0);
925 48 : sal_uInt32 nIndexRight(0);
926 :
927 1584 : for(sal_uInt32 a(0); a < nPointCount; a++)
928 : {
929 1536 : const basegfx::B2DPoint aStart(a2DLoopA.getB2DPoint(a));
930 3072 : const basegfx::B2DPoint aEnd(a2DLoopB.getB2DPoint(a));
931 3072 : const basegfx::B2DPoint aMiddle(basegfx::average(aStart, aEnd));
932 :
933 1536 : if(!basegfx::tools::isInside(a2DLoopA, aMiddle))
934 : {
935 1464 : if(!basegfx::tools::isInside(a2DLoopB, aMiddle))
936 : {
937 1392 : if(!impHasCutWith(a2DLoopA, aStart, aEnd))
938 : {
939 728 : if(!impHasCutWith(a2DLoopB, aStart, aEnd))
940 : {
941 440 : const basegfx::B2DVector aCandidateVector(aMiddle - aCommonCenter);
942 440 : const double fCross(aCandidateVector.cross(aAxisVector));
943 440 : const double fDistance(aCandidateVector.getLength());
944 :
945 440 : if(fCross > 0.0)
946 : {
947 216 : if(fDistance > fMaxLeft)
948 : {
949 72 : fMaxLeft = fDistance;
950 72 : nIndexLeft = a;
951 : }
952 : }
953 224 : else if(fCross < 0.0)
954 : {
955 224 : if(fDistance > fMaxRight)
956 : {
957 216 : fMaxRight = fDistance;
958 216 : nIndexRight = a;
959 : }
960 440 : }
961 : }
962 : }
963 : }
964 : }
965 1536 : }
966 :
967 48 : if(fMaxLeft != 0.0)
968 : {
969 48 : basegfx::B3DPolygon aToBeAdded;
970 48 : aToBeAdded.append(rLoopA.getB3DPoint(nIndexLeft));
971 48 : aToBeAdded.append(rLoopB.getB3DPoint(nIndexLeft));
972 48 : rTarget.append(aToBeAdded);
973 : }
974 :
975 48 : if(fMaxRight != 0.0)
976 : {
977 48 : basegfx::B3DPolygon aToBeAdded;
978 48 : aToBeAdded.append(rLoopA.getB3DPoint(nIndexRight));
979 48 : aToBeAdded.append(rLoopB.getB3DPoint(nIndexRight));
980 48 : rTarget.append(aToBeAdded);
981 48 : }
982 120 : }
983 : }
984 : }
985 192 : }
986 :
987 : } // end of namespace primitive3d
988 : } // end of namespace drawinglayer
989 :
990 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|