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 <drawinglayer/primitive3d/sdrextrudelathetools3d.hxx>
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>
38 // decomposition helpers for extrude/lathe (rotation) objects
45 basegfx::B2DPolyPolygon
impScalePolyPolygonOnCenter(
46 const basegfx::B2DPolyPolygon
& rSource
,
49 basegfx::B2DPolyPolygon
aRetval(rSource
);
51 if(!basegfx::fTools::equalZero(fScale
))
53 const basegfx::B2DRange
aRange(basegfx::utils::getRange(rSource
));
54 const basegfx::B2DPoint
aCenter(aRange
.getCenter());
55 basegfx::B2DHomMatrix aTrans
;
57 aTrans
.translate(-aCenter
.getX(), -aCenter
.getY());
58 aTrans
.scale(fScale
, fScale
);
59 aTrans
.translate(aCenter
.getX(), aCenter
.getY());
60 aRetval
.transform(aTrans
);
66 void impGetOuterPolyPolygon(
67 basegfx::B2DPolyPolygon
& rPolygon
,
68 basegfx::B2DPolyPolygon
& rOuterPolyPolygon
,
72 rOuterPolyPolygon
= rPolygon
;
74 if(basegfx::fTools::more(fOffset
, 0.0))
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 const basegfx::B2DRange
aRange(basegfx::utils::getRange(rPolygon
));
82 rPolygon
= basegfx::utils::growInNormalDirection(rPolygon
, fOffset
);
83 const basegfx::B2DRange
aGrownRange(basegfx::utils::getRange(rPolygon
));
84 const double fScaleX(basegfx::fTools::equalZero(aGrownRange
.getWidth()) ? 1.0 : aRange
.getWidth() / aGrownRange
.getWidth());
85 const double fScaleY(basegfx::fTools::equalZero(aGrownRange
.getHeight())? 1.0 : aRange
.getHeight() / aGrownRange
.getHeight());
86 basegfx::B2DHomMatrix aScaleTrans
;
88 aScaleTrans
.translate(-aGrownRange
.getMinX(), -aGrownRange
.getMinY());
89 aScaleTrans
.scale(fScaleX
, fScaleY
);
90 aScaleTrans
.translate(aRange
.getMinX(), aRange
.getMinY());
91 rPolygon
.transform(aScaleTrans
);
92 rOuterPolyPolygon
.transform(aScaleTrans
);
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 rOuterPolyPolygon
= basegfx::utils::growInNormalDirection(rPolygon
, -fOffset
);
99 // basegfx::utils::correctGrowShrinkPolygonPair(rPolygon, rOuterPolyPolygon);
104 void impAddInBetweenFill(
105 basegfx::B3DPolyPolygon
& rTarget
,
106 const basegfx::B3DPolyPolygon
& rPolA
,
107 const basegfx::B3DPolyPolygon
& rPolB
,
111 bool bCreateTextureCoordinates
)
113 OSL_ENSURE(rPolA
.count() == rPolB
.count(), "impAddInBetweenFill: unequally sized polygons (!)");
114 const sal_uInt32
nPolygonCount(std::min(rPolA
.count(), rPolB
.count()));
116 for(sal_uInt32
a(0); a
< nPolygonCount
; a
++)
118 const basegfx::B3DPolygon
& aSubA(rPolA
.getB3DPolygon(a
));
119 const basegfx::B3DPolygon
& aSubB(rPolB
.getB3DPolygon(a
));
120 OSL_ENSURE(aSubA
.count() == aSubB
.count(), "impAddInBetweenFill: unequally sized polygons (!)");
121 const sal_uInt32
nPointCount(std::min(aSubA
.count(), aSubB
.count()));
125 const sal_uInt32
nEdgeCount(aSubA
.isClosed() ? nPointCount
: nPointCount
- 1);
126 double fTexHorMultiplicatorA(0.0), fTexHorMultiplicatorB(0.0);
127 double fPolygonPosA(0.0), fPolygonPosB(0.0);
129 if(bCreateTextureCoordinates
)
131 const double fPolygonLengthA(basegfx::utils::getLength(aSubA
));
132 fTexHorMultiplicatorA
= basegfx::fTools::equalZero(fPolygonLengthA
) ? 1.0 : 1.0 / fPolygonLengthA
;
134 const double fPolygonLengthB(basegfx::utils::getLength(aSubB
));
135 fTexHorMultiplicatorB
= basegfx::fTools::equalZero(fPolygonLengthB
) ? 1.0 : 1.0 / fPolygonLengthB
;
138 for(sal_uInt32
b(0); b
< nEdgeCount
; b
++)
140 const sal_uInt32
nIndexA(b
);
141 const sal_uInt32
nIndexB((b
+ 1) % nPointCount
);
143 const basegfx::B3DPoint
aStartA(aSubA
.getB3DPoint(nIndexA
));
144 const basegfx::B3DPoint
aEndA(aSubA
.getB3DPoint(nIndexB
));
145 const basegfx::B3DPoint
aStartB(aSubB
.getB3DPoint(nIndexA
));
146 const basegfx::B3DPoint
aEndB(aSubB
.getB3DPoint(nIndexB
));
148 basegfx::B3DPolygon aNew
;
149 aNew
.setClosed(true);
151 aNew
.append(aStartA
);
152 aNew
.append(aStartB
);
158 aNew
.setNormal(0, aSubA
.getNormal(nIndexA
));
159 aNew
.setNormal(1, aSubB
.getNormal(nIndexA
));
160 aNew
.setNormal(2, aSubB
.getNormal(nIndexB
));
161 aNew
.setNormal(3, aSubA
.getNormal(nIndexB
));
164 if(bCreateTextureCoordinates
)
166 const double fRelTexAL(fPolygonPosA
* fTexHorMultiplicatorA
);
167 const double fEdgeLengthA(basegfx::B3DVector(aEndA
- aStartA
).getLength());
168 fPolygonPosA
+= fEdgeLengthA
;
169 const double fRelTexAR(fPolygonPosA
* fTexHorMultiplicatorA
);
171 const double fRelTexBL(fPolygonPosB
* fTexHorMultiplicatorB
);
172 const double fEdgeLengthB(basegfx::B3DVector(aEndB
- aStartB
).getLength());
173 fPolygonPosB
+= fEdgeLengthB
;
174 const double fRelTexBR(fPolygonPosB
* fTexHorMultiplicatorB
);
176 aNew
.setTextureCoordinate(0, basegfx::B2DPoint(fRelTexAL
, fTexVerStart
));
177 aNew
.setTextureCoordinate(1, basegfx::B2DPoint(fRelTexBL
, fTexVerStop
));
178 aNew
.setTextureCoordinate(2, basegfx::B2DPoint(fRelTexBR
, fTexVerStop
));
179 aNew
.setTextureCoordinate(3, basegfx::B2DPoint(fRelTexAR
, fTexVerStart
));
182 rTarget
.append(aNew
);
189 basegfx::B3DPolyPolygon
& rCandidate
,
190 const basegfx::B3DVector
& rNormal
)
192 for(sal_uInt32
a(0); a
< rCandidate
.count(); a
++)
194 basegfx::B3DPolygon
aSub(rCandidate
.getB3DPolygon(a
));
196 for(sal_uInt32
b(0); b
< aSub
.count(); b
++)
198 aSub
.setNormal(b
, rNormal
);
201 rCandidate
.setB3DPolygon(a
, aSub
);
205 void impCreateInBetweenNormals(
206 basegfx::B3DPolyPolygon
& rPolA
,
207 basegfx::B3DPolyPolygon
& rPolB
)
209 OSL_ENSURE(rPolA
.count() == rPolB
.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
210 const sal_uInt32
nPolygonCount(std::min(rPolA
.count(), rPolB
.count()));
212 for(sal_uInt32
a(0); a
< nPolygonCount
; a
++)
214 basegfx::B3DPolygon
aSubA(rPolA
.getB3DPolygon(a
));
215 basegfx::B3DPolygon
aSubB(rPolB
.getB3DPolygon(a
));
216 OSL_ENSURE(aSubA
.count() == aSubB
.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
217 const sal_uInt32
nPointCount(std::min(aSubA
.count(), aSubB
.count()));
221 basegfx::B3DPoint
aPrevA(aSubA
.getB3DPoint(nPointCount
- 1));
222 basegfx::B3DPoint
aCurrA(aSubA
.getB3DPoint(0));
223 const bool bClosed(aSubA
.isClosed());
225 for(sal_uInt32
b(0); b
< nPointCount
; b
++)
227 const sal_uInt32
nIndNext((b
+ 1) % nPointCount
);
228 const basegfx::B3DPoint
aNextA(aSubA
.getB3DPoint(nIndNext
));
229 const basegfx::B3DPoint
aCurrB(aSubB
.getB3DPoint(b
));
232 basegfx::B3DVector
aDepth(aCurrB
- aCurrA
);
235 if(aDepth
.equalZero())
237 // no difference, try to get depth from next point
238 const basegfx::B3DPoint
aNextB(aSubB
.getB3DPoint(nIndNext
));
239 aDepth
= aNextB
- aNextA
;
243 // vector to left (correct for non-closed lines)
244 const bool bFirstAndNotClosed(!bClosed
&& 0 == b
);
245 basegfx::B3DVector
aLeft(bFirstAndNotClosed
? aCurrA
- aNextA
: aPrevA
- aCurrA
);
248 // create left normal
249 const basegfx::B3DVector
aNormalLeft(aDepth
.getPerpendicular(aLeft
));
251 // smooth horizontal normals
253 // vector to right (correct for non-closed lines)
254 const bool bLastAndNotClosed(!bClosed
&& b
+ 1 == nPointCount
);
255 basegfx::B3DVector
aRight(bLastAndNotClosed
? aCurrA
- aPrevA
: aNextA
- aCurrA
);
258 // create right normal
259 const basegfx::B3DVector
aNormalRight(aRight
.getPerpendicular(aDepth
));
261 // create smoothed in-between normal
262 basegfx::B3DVector
aNewNormal(aNormalLeft
+ aNormalRight
);
263 aNewNormal
.normalize();
265 // set as new normal at polygons
266 aSubA
.setNormal(b
, aNewNormal
);
267 aSubB
.setNormal(b
, aNewNormal
);
275 rPolA
.setB3DPolygon(a
, aSubA
);
276 rPolB
.setB3DPolygon(a
, aSubB
);
282 basegfx::B3DPolyPolygon
& rPolA
,
283 const basegfx::B3DPolyPolygon
& rPolB
,
286 const double fWeightB(1.0 - fWeightA
);
287 OSL_ENSURE(rPolA
.count() == rPolB
.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
288 const sal_uInt32
nPolygonCount(std::min(rPolA
.count(), rPolB
.count()));
290 for(sal_uInt32
a(0); a
< nPolygonCount
; a
++)
292 basegfx::B3DPolygon
aSubA(rPolA
.getB3DPolygon(a
));
293 const basegfx::B3DPolygon
& aSubB(rPolB
.getB3DPolygon(a
));
294 OSL_ENSURE(aSubA
.count() == aSubB
.count(), "sdrExtrudePrimitive3D: unequally sized polygons (!)");
295 const sal_uInt32
nPointCount(std::min(aSubA
.count(), aSubB
.count()));
297 for(sal_uInt32
b(0); b
< nPointCount
; b
++)
299 const basegfx::B3DVector
aVA(aSubA
.getNormal(b
) * fWeightA
);
300 const basegfx::B3DVector
aVB(aSubB
.getNormal(b
) * fWeightB
);
301 basegfx::B3DVector
aVNew(aVA
+ aVB
);
303 aSubA
.setNormal(b
, aVNew
);
306 rPolA
.setB3DPolygon(a
, aSubA
);
310 bool impHasCutWith(const basegfx::B2DPolygon
& rPoly
, const basegfx::B2DPoint
& rStart
, const basegfx::B2DPoint
& rEnd
)
312 // polygon is closed, one of the points is a member
313 const sal_uInt32
nPointCount(rPoly
.count());
317 basegfx::B2DPoint
aCurrent(rPoly
.getB2DPoint(0));
318 const basegfx::B2DVector
aVector(rEnd
- rStart
);
320 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
322 const sal_uInt32
nNextIndex((a
+ 1) % nPointCount
);
323 const basegfx::B2DPoint
aNext(rPoly
.getB2DPoint(nNextIndex
));
324 const basegfx::B2DVector
aEdgeVector(aNext
- aCurrent
);
326 if(basegfx::utils::findCut(
328 aCurrent
, aEdgeVector
) != CutFlagValue::NONE
)
339 } // end of anonymous namespace
342 namespace drawinglayer
344 namespace primitive3d
346 void createLatheSlices(
347 Slice3DVector
& rSliceVector
,
348 const basegfx::B2DPolyPolygon
& rSource
,
357 if(basegfx::fTools::equalZero(fRotation
) || 0 == nSteps
)
359 // no rotation or no steps, just one plane
360 rSliceVector
.emplace_back(rSource
, basegfx::B3DHomMatrix());
364 const bool bBackScale(!basegfx::fTools::equal(fBackScale
, 1.0));
365 const bool bClosedRotation(!bBackScale
&& basegfx::fTools::equal(fRotation
, F_2PI
));
366 basegfx::B2DPolyPolygon
aFront(rSource
);
367 basegfx::B2DPolyPolygon
aBack(rSource
);
368 basegfx::B3DHomMatrix aTransformBack
;
369 basegfx::B2DPolyPolygon aOuterBack
;
373 bCloseFront
= bCloseBack
= false;
379 if(basegfx::fTools::equalZero(fBackScale
))
381 fBackScale
= 0.000001;
384 // back is scaled compared to front, create scaled version
385 aBack
= impScalePolyPolygonOnCenter(aBack
, fBackScale
);
388 if(bCloseFront
|| bCloseBack
)
390 const basegfx::B2DRange
aBaseRange(basegfx::utils::getRange(aFront
));
391 const double fOuterLength(aBaseRange
.getMaxX() * fRotation
);
392 const double fInnerLength(aBaseRange
.getMinX() * fRotation
);
393 const double fAverageLength((fOuterLength
+ fInnerLength
) * 0.5);
397 const double fOffsetLen((fAverageLength
/ 12.0) * fDiagonal
);
398 basegfx::B2DPolyPolygon aOuterFront
;
399 impGetOuterPolyPolygon(aFront
, aOuterFront
, fOffsetLen
, bCharacterMode
);
400 basegfx::B3DHomMatrix aTransform
;
401 aTransform
.translate(0.0, 0.0, fOffsetLen
);
402 rSliceVector
.emplace_back(aOuterFront
, aTransform
, SLICETYPE3D_FRONTCAP
);
407 const double fOffsetLen((fAverageLength
/ 12.0) * fDiagonal
);
408 impGetOuterPolyPolygon(aBack
, aOuterBack
, fOffsetLen
, bCharacterMode
);
409 aTransformBack
.translate(0.0, 0.0, -fOffsetLen
);
410 aTransformBack
.rotate(0.0, fRotation
, 0.0);
414 // add start polygon (a = 0)
417 rSliceVector
.emplace_back(aFront
, basegfx::B3DHomMatrix());
420 // create segments (a + 1 .. nSteps)
421 const double fStepSize(1.0 / static_cast<double>(nSteps
));
423 for(sal_uInt32
a(0); a
< nSteps
; a
++)
425 const double fStep(static_cast<double>(a
+ 1) * fStepSize
);
426 basegfx::B2DPolyPolygon
aNewPoly(bBackScale
? basegfx::utils::interpolate(aFront
, aBack
, fStep
) : aFront
);
427 basegfx::B3DHomMatrix aNewMat
;
428 aNewMat
.rotate(0.0, fRotation
* fStep
, 0.0);
429 rSliceVector
.emplace_back(aNewPoly
, aNewMat
);
434 rSliceVector
.emplace_back(aOuterBack
, aTransformBack
, SLICETYPE3D_BACKCAP
);
439 void createExtrudeSlices(
440 Slice3DVector
& rSliceVector
,
441 const basegfx::B2DPolyPolygon
& rSource
,
449 if(basegfx::fTools::equalZero(fDepth
))
451 // no depth, just one plane
452 rSliceVector
.emplace_back(rSource
, basegfx::B3DHomMatrix());
456 // there is depth, create Polygons for front,back and their default depth positions
457 basegfx::B2DPolyPolygon
aFront(rSource
);
458 basegfx::B2DPolyPolygon
aBack(rSource
);
459 const bool bBackScale(!basegfx::fTools::equal(fBackScale
, 1.0));
460 double fZFront(fDepth
); // default depth for aFront
461 double fZBack(0.0); // default depth for aBack
462 basegfx::B2DPolyPolygon aOuterBack
;
467 if(basegfx::fTools::equalZero(fBackScale
))
469 fBackScale
= 0.000001;
472 // aFront is scaled compared to aBack, create scaled version
473 aFront
= impScalePolyPolygonOnCenter(aFront
, fBackScale
);
478 const double fOffset(fDepth
* fDiagonal
* 0.5);
479 fZFront
= fDepth
- fOffset
;
480 basegfx::B2DPolyPolygon aOuterFront
;
481 impGetOuterPolyPolygon(aFront
, aOuterFront
, fOffset
, bCharacterMode
);
482 basegfx::B3DHomMatrix aTransformFront
;
483 aTransformFront
.translate(0.0, 0.0, fDepth
);
484 rSliceVector
.emplace_back(aOuterFront
, aTransformFront
, SLICETYPE3D_FRONTCAP
);
489 const double fOffset(fDepth
* fDiagonal
* 0.5);
491 impGetOuterPolyPolygon(aBack
, aOuterBack
, fOffset
, bCharacterMode
);
494 // add front and back polygons at evtl. changed depths
496 basegfx::B3DHomMatrix aTransformA
, aTransformB
;
498 aTransformA
.translate(0.0, 0.0, fZFront
);
499 rSliceVector
.emplace_back(aFront
, aTransformA
);
501 aTransformB
.translate(0.0, 0.0, fZBack
);
502 rSliceVector
.emplace_back(aBack
, aTransformB
);
507 rSliceVector
.emplace_back(aOuterBack
, basegfx::B3DHomMatrix(), SLICETYPE3D_BACKCAP
);
512 basegfx::B3DPolyPolygon
extractHorizontalLinesFromSlice(const Slice3DVector
& rSliceVector
, bool bCloseHorLines
)
514 basegfx::B3DPolyPolygon aRetval
;
515 const sal_uInt32
nNumSlices(rSliceVector
.size());
519 const sal_uInt32
nSlideSubPolygonCount(rSliceVector
[0].getB3DPolyPolygon().count());
521 for(sal_uInt32
b(0); b
< nSlideSubPolygonCount
; b
++)
523 const sal_uInt32
nSubPolygonPointCount(rSliceVector
[0].getB3DPolyPolygon().getB3DPolygon(b
).count());
525 for(sal_uInt32
c(0); c
< nSubPolygonPointCount
; c
++)
527 basegfx::B3DPolygon aNew
;
529 for(sal_uInt32
d(0); d
< nNumSlices
; d
++)
531 const bool bSamePolygonCount(nSlideSubPolygonCount
== rSliceVector
[d
].getB3DPolyPolygon().count());
532 const bool bSamePointCount(nSubPolygonPointCount
== rSliceVector
[d
].getB3DPolyPolygon().getB3DPolygon(b
).count());
534 if(bSamePolygonCount
&& bSamePointCount
)
536 aNew
.append(rSliceVector
[d
].getB3DPolyPolygon().getB3DPolygon(b
).getB3DPoint(c
));
540 OSL_ENSURE(bSamePolygonCount
, "Slice tools::PolyPolygon with different Polygon count (!)");
541 OSL_ENSURE(bSamePointCount
, "Slice Polygon with different point count (!)");
545 aNew
.setClosed(bCloseHorLines
);
546 aRetval
.append(aNew
);
554 basegfx::B3DPolyPolygon
extractVerticalLinesFromSlice(const Slice3DVector
& rSliceVector
)
556 basegfx::B3DPolyPolygon aRetval
;
557 const sal_uInt32
nNumSlices(rSliceVector
.size());
559 for(sal_uInt32
a(0); a
< nNumSlices
; a
++)
561 aRetval
.append(rSliceVector
[a
].getB3DPolyPolygon());
567 void extractPlanesFromSlice(
568 std::vector
< basegfx::B3DPolyPolygon
>& rFill
,
569 const Slice3DVector
& rSliceVector
,
574 double fSmoothNormalsMix
,
575 double fSmoothLidsMix
,
576 bool bCreateTextureCoordinates
,
577 const basegfx::B2DHomMatrix
& rTexTransform
)
579 const sal_uInt32
nNumSlices(rSliceVector
.size());
584 const sal_uInt32
nLoopCount(bClosed
? nNumSlices
: nNumSlices
- 1);
585 basegfx::B3DPolyPolygon aEdgeRounding
;
588 // texture parameters
589 double fInvTexHeight(1.0);
590 std::vector
<double> aTexHeightArray
;
591 basegfx::B3DRange aTexRangeFront
;
592 basegfx::B3DRange aTexRangeBack
;
594 if(bCreateTextureCoordinates
)
596 aTexRangeFront
= basegfx::utils::getRange(rSliceVector
[0].getB3DPolyPolygon());
597 aTexRangeBack
= basegfx::utils::getRange(rSliceVector
[nNumSlices
- 1].getB3DPolyPolygon());
599 if(aTexRangeBack
.getDepth() > aTexRangeBack
.getWidth())
601 // last polygon is rotated so that depth is bigger than width, exchange X and Z
602 // for making applyDefaultTextureCoordinatesParallel use Z instead of X for
603 // horizontal texture coordinate
604 aTexRangeBack
= basegfx::B3DRange(
605 aTexRangeBack
.getMinZ(), aTexRangeBack
.getMinY(), aTexRangeBack
.getMinX(),
606 aTexRangeBack
.getMaxZ(), aTexRangeBack
.getMaxY(), aTexRangeBack
.getMaxX());
609 basegfx::B3DPoint
aCenter(basegfx::utils::getRange(rSliceVector
[0].getB3DPolyPolygon()).getCenter());
611 for(a
= 0; a
< nLoopCount
; a
++)
613 const basegfx::B3DPoint
aNextCenter(basegfx::utils::getRange(rSliceVector
[(a
+ 1) % nNumSlices
].getB3DPolyPolygon()).getCenter());
614 const double fLength(basegfx::B3DVector(aNextCenter
- aCenter
).getLength());
615 aTexHeightArray
.push_back(fLength
);
616 aCenter
= aNextCenter
;
619 const double fTexHeight(std::accumulate(aTexHeightArray
.begin(), aTexHeightArray
.end(), 0.0));
621 if(!basegfx::fTools::equalZero(fTexHeight
))
623 fInvTexHeight
= 1.0 / fTexHeight
;
629 double fTexHeightPos(0.0);
630 for(a
= 0; a
< nLoopCount
; a
++)
632 const Slice3D
& rSliceA(rSliceVector
[a
]);
633 const Slice3D
& rSliceB(rSliceVector
[(a
+ 1) % nNumSlices
]);
634 const bool bAcceptPair(SLICETYPE3D_REGULAR
== rSliceA
.getSliceType() && SLICETYPE3D_REGULAR
== rSliceB
.getSliceType());
635 basegfx::B3DPolyPolygon
aPolA(rSliceA
.getB3DPolyPolygon());
636 basegfx::B3DPolyPolygon
aPolB(rSliceB
.getB3DPolyPolygon());
642 impCreateInBetweenNormals(aPolB
, aPolA
);
646 const sal_uInt32
nIndPrev((a
+ nNumSlices
- 1) % nNumSlices
);
647 const Slice3D
& rSlicePrev(rSliceVector
[nIndPrev
]);
648 basegfx::B3DPolyPolygon
aPrev(rSlicePrev
.getB3DPolyPolygon());
649 basegfx::B3DPolyPolygon
aPolAA(rSliceA
.getB3DPolyPolygon());
651 if(SLICETYPE3D_FRONTCAP
== rSlicePrev
.getSliceType())
653 basegfx::B3DPolyPolygon
aFront(rSlicePrev
.getB3DPolyPolygon());
654 const bool bHasSlant(aPolAA
!= aPrev
);
656 if(bCreateTextureCoordinates
)
658 aFront
= basegfx::utils::applyDefaultTextureCoordinatesParallel(aFront
, aTexRangeFront
);
663 basegfx::B3DVector
aNormal(0.0, 0.0, -1.0);
667 aNormal
= -aFront
.getB3DPolygon(0).getNormal();
670 impSetNormal(aFront
, aNormal
);
674 impCreateInBetweenNormals(aPolAA
, aPrev
);
679 impMixNormals(aPolA
, aPolAA
, fSmoothNormalsMix
);
684 // take over from surface
691 impMixNormals(aFront
, aPrev
, fSmoothLidsMix
);
696 // take over from front
705 impMixNormals(aPolA
, aFront
, fSmoothNormalsMix
);
711 impMixNormals(aFront
, aPolA
, fSmoothLidsMix
);
721 if(bCreateTextureCoordinates
)
723 fTexStart
= fTexHeightPos
* fInvTexHeight
;
724 fTexStop
= (fTexHeightPos
- aTexHeightArray
[(a
+ nLoopCount
- 1) % nLoopCount
]) * fInvTexHeight
;
727 impAddInBetweenFill(aEdgeRounding
, aPolAA
, aPrev
, fTexStart
, fTexStop
, bCreateNormals
, bCreateTextureCoordinates
);
731 rFill
.push_back(aFront
);
735 if(bCreateNormals
&& bSmoothNormals
&& (nIndPrev
!= a
+ 1))
737 impCreateInBetweenNormals(aPolAA
, aPrev
);
738 impMixNormals(aPolA
, aPolAA
, 0.5);
744 const sal_uInt32
nIndNext((a
+ 2) % nNumSlices
);
745 const Slice3D
& rSliceNext(rSliceVector
[nIndNext
]);
746 basegfx::B3DPolyPolygon
aNext(rSliceNext
.getB3DPolyPolygon());
747 basegfx::B3DPolyPolygon
aPolBB(rSliceB
.getB3DPolyPolygon());
749 if(SLICETYPE3D_BACKCAP
== rSliceNext
.getSliceType())
751 basegfx::B3DPolyPolygon
aBack(rSliceNext
.getB3DPolyPolygon());
752 const bool bHasSlant(aPolBB
!= aNext
);
754 if(bCreateTextureCoordinates
)
756 aBack
= basegfx::utils::applyDefaultTextureCoordinatesParallel(aBack
, aTexRangeBack
);
761 const basegfx::B3DVector
aNormal(aBack
.count() ? aBack
.getB3DPolygon(0).getNormal() : basegfx::B3DVector(0.0, 0.0, 1.0));
762 impSetNormal(aBack
, aNormal
);
766 impCreateInBetweenNormals(aNext
, aPolBB
);
771 impMixNormals(aPolB
, aPolBB
, fSmoothNormalsMix
);
776 // take over from surface
783 impMixNormals(aBack
, aNext
, fSmoothLidsMix
);
788 // take over from back
797 impMixNormals(aPolB
, aBack
, fSmoothNormalsMix
);
803 impMixNormals(aBack
, aPolB
, fSmoothLidsMix
);
813 if(bCreateTextureCoordinates
)
815 fTexStart
= (fTexHeightPos
+ aTexHeightArray
[a
] + aTexHeightArray
[(a
+ 1) % nLoopCount
]) * fInvTexHeight
;
816 fTexStop
= (fTexHeightPos
+ aTexHeightArray
[a
]) * fInvTexHeight
;
819 impAddInBetweenFill(aEdgeRounding
, aNext
, aPolBB
, fTexStart
, fTexStop
, bCreateNormals
, bCreateTextureCoordinates
);
822 rFill
.push_back(aBack
);
826 if(bCreateNormals
&& bSmoothNormals
&& (nIndNext
!= a
))
828 impCreateInBetweenNormals(aNext
, aPolBB
);
829 impMixNormals(aPolB
, aPolBB
, 0.5);
836 if(bCreateTextureCoordinates
)
838 fTexStart
= (fTexHeightPos
+ aTexHeightArray
[a
]) * fInvTexHeight
;
839 fTexStop
= fTexHeightPos
* fInvTexHeight
;
842 impAddInBetweenFill(aEdgeRounding
, aPolB
, aPolA
, fTexStart
, fTexStop
, bCreateNormals
, bCreateTextureCoordinates
);
845 if(bCreateTextureCoordinates
)
847 fTexHeightPos
+= aTexHeightArray
[a
];
853 // no loop, but a single slice (1 == nNumSlices), create a filling from the single
855 const Slice3D
& rSlice(rSliceVector
[0]);
856 basegfx::B3DPolyPolygon
aFront(rSlice
.getB3DPolyPolygon());
858 if(bCreateTextureCoordinates
)
860 aFront
= basegfx::utils::applyDefaultTextureCoordinatesParallel(aFront
, aTexRangeFront
);
865 basegfx::B3DVector
aNormal(0.0, 0.0, -1.0);
869 aNormal
= -aFront
.getB3DPolygon(0).getNormal();
872 impSetNormal(aFront
, aNormal
);
876 rFill
.push_back(aFront
);
879 if(bCreateTextureCoordinates
)
881 aEdgeRounding
.transformTextureCoordinates(rTexTransform
);
884 for(a
= 0; a
< aEdgeRounding
.count(); a
++)
886 rFill
.emplace_back(aEdgeRounding
.getB3DPolygon(a
));
891 void createReducedOutlines(
892 const geometry::ViewInformation3D
& rViewInformation
,
893 const basegfx::B3DHomMatrix
& rObjectTransform
,
894 const basegfx::B3DPolygon
& rLoopA
,
895 const basegfx::B3DPolygon
& rLoopB
,
896 basegfx::B3DPolyPolygon
& rTarget
)
898 const sal_uInt32
nPointCount(rLoopA
.count());
900 // with identical polygons there are no outlines
903 if(nPointCount
&& nPointCount
== rLoopB
.count())
905 const basegfx::B3DHomMatrix
aObjectTransform(rViewInformation
.getObjectToView() * rObjectTransform
);
906 const basegfx::B2DPolygon
a2DLoopA(basegfx::utils::createB2DPolygonFromB3DPolygon(rLoopA
, aObjectTransform
));
907 const basegfx::B2DPolygon
a2DLoopB(basegfx::utils::createB2DPolygonFromB3DPolygon(rLoopB
, aObjectTransform
));
908 const basegfx::B2DPoint
a2DCenterA(a2DLoopA
.getB2DRange().getCenter());
909 const basegfx::B2DPoint
a2DCenterB(a2DLoopB
.getB2DRange().getCenter());
911 // without detectable Y-Axis there are no outlines
912 if(!a2DCenterA
.equal(a2DCenterB
))
914 // search for outmost left and right inter-loop-edges which do not cut the loops
915 const basegfx::B2DPoint
aCommonCenter(basegfx::average(a2DCenterA
, a2DCenterB
));
916 const basegfx::B2DVector
aAxisVector(a2DCenterA
- a2DCenterB
);
917 double fMaxLeft(0.0);
918 double fMaxRight(0.0);
919 sal_uInt32
nIndexLeft(0);
920 sal_uInt32
nIndexRight(0);
922 for(sal_uInt32
a(0); a
< nPointCount
; a
++)
924 const basegfx::B2DPoint
aStart(a2DLoopA
.getB2DPoint(a
));
925 const basegfx::B2DPoint
aEnd(a2DLoopB
.getB2DPoint(a
));
926 const basegfx::B2DPoint
aMiddle(basegfx::average(aStart
, aEnd
));
928 if(!basegfx::utils::isInside(a2DLoopA
, aMiddle
))
930 if(!basegfx::utils::isInside(a2DLoopB
, aMiddle
))
932 if(!impHasCutWith(a2DLoopA
, aStart
, aEnd
))
934 if(!impHasCutWith(a2DLoopB
, aStart
, aEnd
))
936 const basegfx::B2DVector
aCandidateVector(aMiddle
- aCommonCenter
);
937 const double fCross(aCandidateVector
.cross(aAxisVector
));
938 const double fDistance(aCandidateVector
.getLength());
942 if(fDistance
> fMaxLeft
)
944 fMaxLeft
= fDistance
;
948 else if(fCross
< 0.0)
950 if(fDistance
> fMaxRight
)
952 fMaxRight
= fDistance
;
964 basegfx::B3DPolygon aToBeAdded
;
965 aToBeAdded
.append(rLoopA
.getB3DPoint(nIndexLeft
));
966 aToBeAdded
.append(rLoopB
.getB3DPoint(nIndexLeft
));
967 rTarget
.append(aToBeAdded
);
972 basegfx::B3DPolygon aToBeAdded
;
973 aToBeAdded
.append(rLoopA
.getB3DPoint(nIndexRight
));
974 aToBeAdded
.append(rLoopB
.getB3DPoint(nIndexRight
));
975 rTarget
.append(aToBeAdded
);
982 } // end of namespace primitive3d
983 } // end of namespace drawinglayer
985 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */