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 <primitive3d/polygontubeprimitive3d.hxx>
21 #include <drawinglayer/attribute/materialattribute3d.hxx>
22 #include <basegfx/matrix/b3dhommatrix.hxx>
23 #include <basegfx/polygon/b3dpolypolygon.hxx>
24 #include <drawinglayer/primitive3d/polypolygonprimitive3d.hxx>
25 #include <basegfx/polygon/b3dpolypolygontools.hxx>
26 #include <drawinglayer/primitive3d/transformprimitive3d.hxx>
27 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
30 namespace drawinglayer::primitive3d
32 namespace // anonymous namespace
37 // data for buffered tube primitives
38 Primitive3DContainer m_aLineTubeList
;
39 sal_uInt32 m_nLineTubeSegments
;
40 attribute::MaterialAttribute3D m_aLineMaterial
;
44 : m_nLineTubeSegments(0)
48 TubeBuffer(const TubeBuffer
&) = delete;
49 const TubeBuffer
& operator=(const TubeBuffer
&) = delete;
51 Primitive3DContainer
getLineTubeSegments(
53 const attribute::MaterialAttribute3D
& rMaterial
)
55 // may exclusively change cached data, use mutex
56 std::unique_lock
aGuard(m_aMutex
);
58 if (nSegments
!= m_nLineTubeSegments
|| !(rMaterial
== m_aLineMaterial
))
60 m_nLineTubeSegments
= nSegments
;
61 m_aLineMaterial
= rMaterial
;
62 m_aLineTubeList
= Primitive3DContainer();
65 if (m_aLineTubeList
.empty() && m_nLineTubeSegments
!= 0)
67 const basegfx::B3DPoint
aLeft(0.0, 0.0, 0.0);
68 const basegfx::B3DPoint
aRight(1.0, 0.0, 0.0);
69 basegfx::B3DPoint
aLastLeft(0.0, 1.0, 0.0);
70 basegfx::B3DPoint
aLastRight(1.0, 1.0, 0.0);
71 basegfx::B3DHomMatrix aRot
;
72 aRot
.rotate(2 * M_PI
/ static_cast<double>(m_nLineTubeSegments
), 0.0, 0.0);
73 m_aLineTubeList
.resize(m_nLineTubeSegments
);
75 for(sal_uInt32 a
= 0; a
< m_nLineTubeSegments
; ++a
)
77 const basegfx::B3DPoint
aNextLeft(aRot
* aLastLeft
);
78 const basegfx::B3DPoint
aNextRight(aRot
* aLastRight
);
79 basegfx::B3DPolygon aNewPolygon
;
81 aNewPolygon
.append(aNextLeft
);
82 aNewPolygon
.setNormal(0, basegfx::B3DVector(aNextLeft
- aLeft
));
84 aNewPolygon
.append(aLastLeft
);
85 aNewPolygon
.setNormal(1, basegfx::B3DVector(aLastLeft
- aLeft
));
87 aNewPolygon
.append(aLastRight
);
88 aNewPolygon
.setNormal(2, basegfx::B3DVector(aLastRight
- aRight
));
90 aNewPolygon
.append(aNextRight
);
91 aNewPolygon
.setNormal(3, basegfx::B3DVector(aNextRight
- aRight
));
93 aNewPolygon
.setClosed(true);
95 basegfx::B3DPolyPolygon
aNewPolyPolygon(aNewPolygon
);
96 m_aLineTubeList
[a
] = new PolyPolygonMaterialPrimitive3D(std::move(aNewPolyPolygon
), m_aLineMaterial
, false);
98 aLastLeft
= aNextLeft
;
99 aLastRight
= aNextRight
;
102 return m_aLineTubeList
;
106 Primitive3DContainer
getLineTubeSegments(
107 sal_uInt32 nSegments
,
108 const attribute::MaterialAttribute3D
& rMaterial
)
110 // static data for buffered tube primitives
111 static TubeBuffer theTubeBuffer
;
112 return theTubeBuffer
.getLineTubeSegments(nSegments
, rMaterial
);
118 // data for buffered cap primitives
119 Primitive3DContainer m_aLineCapList
;
120 sal_uInt32 m_nLineCapSegments
;
121 attribute::MaterialAttribute3D m_aLineMaterial
;
125 : m_nLineCapSegments(0)
128 CapBuffer(const CapBuffer
&) = delete;
129 const CapBuffer
& operator=(const CapBuffer
&) = delete;
131 Primitive3DContainer
getLineCapSegments(
132 sal_uInt32 nSegments
,
133 const attribute::MaterialAttribute3D
& rMaterial
)
135 // may exclusively change cached data, use mutex
136 std::unique_lock
aGuard(m_aMutex
);
138 if (nSegments
!= m_nLineCapSegments
|| !(rMaterial
== m_aLineMaterial
))
140 m_nLineCapSegments
= nSegments
;
141 m_aLineMaterial
= rMaterial
;
142 m_aLineCapList
= Primitive3DContainer();
145 if (m_aLineCapList
.empty() && m_nLineCapSegments
!= 0)
147 const basegfx::B3DPoint
aNull(0.0, 0.0, 0.0);
148 basegfx::B3DPoint
aLast(0.0, 1.0, 0.0);
149 basegfx::B3DHomMatrix aRot
;
150 aRot
.rotate(2 * M_PI
/ static_cast<double>(m_nLineCapSegments
), 0.0, 0.0);
151 m_aLineCapList
.resize(m_nLineCapSegments
);
153 for(sal_uInt32 a
= 0; a
< m_nLineCapSegments
; ++a
)
155 const basegfx::B3DPoint
aNext(aRot
* aLast
);
156 basegfx::B3DPolygon aNewPolygon
;
158 aNewPolygon
.append(aLast
);
159 aNewPolygon
.setNormal(0, basegfx::B3DVector(aLast
- aNull
));
161 aNewPolygon
.append(aNext
);
162 aNewPolygon
.setNormal(1, basegfx::B3DVector(aNext
- aNull
));
164 aNewPolygon
.append(aNull
);
165 aNewPolygon
.setNormal(2, basegfx::B3DVector(-1.0, 0.0, 0.0));
167 aNewPolygon
.setClosed(true);
169 basegfx::B3DPolyPolygon
aNewPolyPolygon(aNewPolygon
);
170 m_aLineCapList
[a
] = new PolyPolygonMaterialPrimitive3D(std::move(aNewPolyPolygon
), m_aLineMaterial
, false);
176 return m_aLineCapList
;
180 Primitive3DContainer
getLineCapSegments(
181 sal_uInt32 nSegments
,
182 const attribute::MaterialAttribute3D
& rMaterial
)
184 // static data for buffered cap primitives
185 static CapBuffer theCapBuffer
;
186 return theCapBuffer
.getLineCapSegments(nSegments
, rMaterial
);
192 // data for buffered capround primitives
193 Primitive3DContainer m_aLineCapRoundList
;
194 sal_uInt32 m_nLineCapRoundSegments
;
195 attribute::MaterialAttribute3D m_aLineMaterial
;
199 : m_nLineCapRoundSegments(0)
202 CapRoundBuffer(const CapRoundBuffer
&) = delete;
203 const CapRoundBuffer
& operator=(const CapRoundBuffer
&) = delete;
205 Primitive3DContainer
getLineCapRoundSegments(
206 sal_uInt32 nSegments
,
207 const attribute::MaterialAttribute3D
& rMaterial
)
209 // may exclusively change cached data, use mutex
210 std::unique_lock
aGuard(m_aMutex
);
212 if (nSegments
!= m_nLineCapRoundSegments
|| !(rMaterial
== m_aLineMaterial
))
214 m_nLineCapRoundSegments
= nSegments
;
215 m_aLineMaterial
= rMaterial
;
216 m_aLineCapRoundList
= Primitive3DContainer();
219 if (m_aLineCapRoundList
.empty() && m_nLineCapRoundSegments
)
221 // calculate new horizontal segments
222 sal_uInt32
nVerSeg(nSegments
/ 2);
229 // create half-sphere; upper half of unit sphere
230 basegfx::B3DPolyPolygon
aSphere(
231 basegfx::utils::createUnitSphereFillPolyPolygon(
237 const sal_uInt32
nCount(aSphere
.count());
241 // rotate to have sphere cap oriented to negative X-Axis; do not
242 // forget to transform normals, too
243 basegfx::B3DHomMatrix aSphereTrans
;
245 aSphereTrans
.rotate(0.0, 0.0, M_PI_2
);
246 aSphere
.transform(aSphereTrans
);
247 aSphere
.transformNormals(aSphereTrans
);
249 // realloc for primitives and create based on polygon snippets
250 m_aLineCapRoundList
.resize(nCount
);
252 for (sal_uInt32 a
= 0; a
< nCount
; ++a
)
254 const basegfx::B3DPolygon
& aPartPolygon(aSphere
.getB3DPolygon(a
));
255 basegfx::B3DPolyPolygon
aPartPolyPolygon(aPartPolygon
);
257 // need to create one primitive per Polygon since the primitive
258 // is for planar PolyPolygons which is definitely not the case here
259 m_aLineCapRoundList
[a
] = new PolyPolygonMaterialPrimitive3D(
260 std::move(aPartPolyPolygon
),
267 return m_aLineCapRoundList
;
272 Primitive3DContainer
getLineCapRoundSegments(
273 sal_uInt32 nSegments
,
274 const attribute::MaterialAttribute3D
& rMaterial
)
276 // static data for buffered cap primitives
277 static CapRoundBuffer theCapRoundBuffer
;
278 return theCapRoundBuffer
.getLineCapRoundSegments(nSegments
, rMaterial
);
281 Primitive3DContainer
getLineJoinSegments(
282 sal_uInt32 nSegments
,
283 const attribute::MaterialAttribute3D
& rMaterial
,
285 double fMiterMinimumAngle
,
286 basegfx::B2DLineJoin aLineJoin
)
288 // nSegments is for whole circle, adapt to half circle
289 const sal_uInt32
nVerSeg(nSegments
>> 1);
290 std::vector
< BasePrimitive3D
* > aResultVector
;
294 if(basegfx::B2DLineJoin::Round
== aLineJoin
)
296 // calculate new horizontal segments
297 const sal_uInt32
nHorSeg(basegfx::fround((fAngle
/ (2 * M_PI
)) * static_cast<double>(nSegments
)));
301 // create half-sphere
302 const basegfx::B3DPolyPolygon
aSphere(basegfx::utils::createUnitSphereFillPolyPolygon(nHorSeg
, nVerSeg
, true, M_PI_2
, -M_PI_2
, 0.0, fAngle
));
304 for(sal_uInt32
a(0); a
< aSphere
.count(); a
++)
306 const basegfx::B3DPolygon
& aPartPolygon(aSphere
.getB3DPolygon(a
));
307 basegfx::B3DPolyPolygon
aPartPolyPolygon(aPartPolygon
);
308 aResultVector
.push_back(new PolyPolygonMaterialPrimitive3D(std::move(aPartPolyPolygon
), rMaterial
, false));
313 // fallback to bevel when there is not at least one segment hor and ver
314 aLineJoin
= basegfx::B2DLineJoin::Bevel
;
318 if (basegfx::B2DLineJoin::Bevel
== aLineJoin
||
319 basegfx::B2DLineJoin::Miter
== aLineJoin
)
321 if(basegfx::B2DLineJoin::Miter
== aLineJoin
)
323 const double fMiterAngle(fAngle
/2.0);
325 if(fMiterAngle
< fMiterMinimumAngle
)
327 // fallback to bevel when miter's angle is too small
328 aLineJoin
= basegfx::B2DLineJoin::Bevel
;
332 const double fInc(M_PI
/ static_cast<double>(nVerSeg
));
333 const double fSin(sin(-fAngle
));
334 const double fCos(cos(-fAngle
));
335 const bool bMiter(basegfx::B2DLineJoin::Miter
== aLineJoin
);
336 const double fMiterSin(bMiter
? sin(-(fAngle
/2.0)) : 0.0);
337 const double fMiterCos(bMiter
? cos(-(fAngle
/2.0)) : 0.0);
338 double fPos(-M_PI_2
);
339 basegfx::B3DPoint aPointOnXY
, aPointRotY
, aNextPointOnXY
, aNextPointRotY
;
340 basegfx::B3DPoint aCurrMiter
, aNextMiter
;
341 basegfx::B3DPolygon aNewPolygon
, aMiterPolygon
;
344 aNewPolygon
.setClosed(true);
345 aMiterPolygon
.setClosed(true);
347 for(sal_uInt32
a(0); a
< nVerSeg
; a
++)
349 const bool bFirst(0 == a
);
350 const bool bLast(a
+ 1 == nVerSeg
);
356 aNextPointOnXY
= basegfx::B3DPoint(
361 aNextPointRotY
= basegfx::B3DPoint(
362 aNextPointOnXY
.getX() * fCos
,
363 aNextPointOnXY
.getY(),
364 aNextPointOnXY
.getX() * fSin
);
368 aNextMiter
= basegfx::B3DPoint(
369 aNextPointOnXY
.getX(),
370 aNextPointOnXY
.getY(),
371 fMiterSin
* (aNextPointOnXY
.getX() / fMiterCos
));
381 aNewPolygon
.append(basegfx::B3DPoint(0.0, -1.0, 0.0));
382 aNewPolygon
.append(aNextPointOnXY
);
383 aNewPolygon
.append(aNextMiter
);
385 aMiterPolygon
.clear();
386 aMiterPolygon
.append(basegfx::B3DPoint(0.0, -1.0, 0.0));
387 aMiterPolygon
.append(aNextMiter
);
388 aMiterPolygon
.append(aNextPointRotY
);
392 aNewPolygon
.append(basegfx::B3DPoint(0.0, -1.0, 0.0));
393 aNewPolygon
.append(aNextPointOnXY
);
394 aNewPolygon
.append(aNextPointRotY
);
403 aNewPolygon
.append(basegfx::B3DPoint(0.0, 1.0, 0.0));
404 aNewPolygon
.append(aCurrMiter
);
405 aNewPolygon
.append(aPointOnXY
);
407 aMiterPolygon
.clear();
408 aMiterPolygon
.append(basegfx::B3DPoint(0.0, 1.0, 0.0));
409 aMiterPolygon
.append(aPointRotY
);
410 aMiterPolygon
.append(aCurrMiter
);
414 aNewPolygon
.append(basegfx::B3DPoint(0.0, 1.0, 0.0));
415 aNewPolygon
.append(aPointRotY
);
416 aNewPolygon
.append(aPointOnXY
);
425 aNewPolygon
.append(aPointOnXY
);
426 aNewPolygon
.append(aNextPointOnXY
);
427 aNewPolygon
.append(aNextMiter
);
428 aNewPolygon
.append(aCurrMiter
);
430 aMiterPolygon
.clear();
431 aMiterPolygon
.append(aCurrMiter
);
432 aMiterPolygon
.append(aNextMiter
);
433 aMiterPolygon
.append(aNextPointRotY
);
434 aMiterPolygon
.append(aPointRotY
);
438 aNewPolygon
.append(aPointRotY
);
439 aNewPolygon
.append(aPointOnXY
);
440 aNewPolygon
.append(aNextPointOnXY
);
441 aNewPolygon
.append(aNextPointRotY
);
446 for(sal_uInt32
b(0); b
< aNewPolygon
.count(); b
++)
448 aNewPolygon
.setNormal(b
, basegfx::B3DVector(aNewPolygon
.getB3DPoint(b
)));
452 if(aNewPolygon
.count())
454 basegfx::B3DPolyPolygon
aNewPolyPolygon(aNewPolygon
);
455 aResultVector
.push_back(new PolyPolygonMaterialPrimitive3D(std::move(aNewPolyPolygon
), rMaterial
, false));
458 if(bMiter
&& aMiterPolygon
.count())
461 for(sal_uInt32
c(0); c
< aMiterPolygon
.count(); c
++)
463 aMiterPolygon
.setNormal(c
, basegfx::B3DVector(aMiterPolygon
.getB3DPoint(c
)));
467 basegfx::B3DPolyPolygon
aMiterPolyPolygon(aMiterPolygon
);
468 aResultVector
.push_back(new PolyPolygonMaterialPrimitive3D(std::move(aMiterPolyPolygon
), rMaterial
, false));
474 aPointOnXY
= aNextPointOnXY
;
475 aPointRotY
= aNextPointRotY
;
479 aCurrMiter
= aNextMiter
;
486 Primitive3DContainer
aRetval(aResultVector
.size());
488 std::transform(aResultVector
.cbegin(), aResultVector
.cend(), aRetval
.begin(), [](auto &rResult
){return Primitive3DReference(rResult
);});
493 basegfx::B3DHomMatrix
getRotationFromVector(const basegfx::B3DVector
& rVector
)
495 // build transformation from unit vector to vector
496 basegfx::B3DHomMatrix aRetval
;
498 // get applied rotations from angles in XY and in XZ (cartesian)
499 const double fRotInXY(atan2(rVector
.getY(), rVector
.getXZLength()));
500 const double fRotInXZ(atan2(-rVector
.getZ(), rVector
.getX()));
502 // apply rotations. Rot around Z needs to be done first, so apply in two steps
503 aRetval
.rotate(0.0, 0.0, fRotInXY
);
504 aRetval
.rotate(0.0, fRotInXZ
, 0.0);
508 } // end of anonymous namespace
511 using namespace com::sun::star
;
513 Primitive3DContainer
PolygonTubePrimitive3D::impCreate3DDecomposition(const geometry::ViewInformation3D
& /*rViewInformation*/) const
515 const sal_uInt32
nPointCount(getB3DPolygon().count());
516 std::vector
< BasePrimitive3D
* > aResultVector
;
520 if(getRadius() > 0.0)
522 const attribute::MaterialAttribute3D
aMaterial(getBColor());
523 static const sal_uInt32
nSegments(8); // default for 3d line segments, for more quality just raise this value (in even steps)
524 const bool bClosed(getB3DPolygon().isClosed());
525 const bool bNoLineJoin(basegfx::B2DLineJoin::NONE
== getLineJoin());
526 const sal_uInt32
nLoopCount(bClosed
? nPointCount
: nPointCount
- 1);
527 basegfx::B3DPoint
aLast(getB3DPolygon().getB3DPoint(nPointCount
- 1));
528 basegfx::B3DPoint
aCurr(getB3DPolygon().getB3DPoint(0));
530 for(sal_uInt32
a(0); a
< nLoopCount
; a
++)
533 const basegfx::B3DPoint
aNext(getB3DPolygon().getB3DPoint((a
+ 1) % nPointCount
));
534 const basegfx::B3DVector
aForw(aNext
- aCurr
);
535 const double fForwLen(aForw
.getLength());
539 // find out if linecap is active
540 const bool bFirst(!a
);
541 const bool bLast(a
+ 1 == nLoopCount
);
542 const bool bLineCapPossible(!bClosed
&& (bFirst
|| bLast
));
543 const bool bLineCapRound(bLineCapPossible
&& css::drawing::LineCap_ROUND
== getLineCap());
544 const bool bLineCapSquare(bLineCapPossible
&& css::drawing::LineCap_SQUARE
== getLineCap());
546 // get rotation from vector, this describes rotation from (1, 0, 0) to aForw
547 basegfx::B3DHomMatrix
aRotVector(getRotationFromVector(aForw
));
549 // prepare transformations for tube and cap
550 basegfx::B3DHomMatrix aTubeTrans
;
551 basegfx::B3DHomMatrix aCapTrans
;
553 // cap gets radius size
554 aCapTrans
.scale(getRadius(), getRadius(), getRadius());
558 // when square line cap just prolong line segment in X, maybe 2 x radius when
559 // first and last (simple line segment)
560 const double fExtraLength(bFirst
&& bLast
? getRadius() * 2.0 : getRadius());
562 aTubeTrans
.scale(fForwLen
+ fExtraLength
, getRadius(), getRadius());
566 // correct start positions for tube and cap when first and square prolonged
567 aTubeTrans
.translate(-getRadius(), 0.0, 0.0);
568 aCapTrans
.translate(-getRadius(), 0.0, 0.0);
574 aTubeTrans
.scale(fForwLen
, getRadius(), getRadius());
577 // rotate and translate tube and cap
578 aTubeTrans
*= aRotVector
;
579 aTubeTrans
.translate(aCurr
.getX(), aCurr
.getY(), aCurr
.getZ());
580 aCapTrans
*= aRotVector
;
581 aCapTrans
.translate(aCurr
.getX(), aCurr
.getY(), aCurr
.getZ());
583 if(bNoLineJoin
|| (!bClosed
&& bFirst
))
585 // line start edge, build transformed primitiveVector3D
586 Primitive3DContainer aSequence
;
588 if(bLineCapRound
&& bFirst
)
591 aSequence
= getLineCapRoundSegments(nSegments
, aMaterial
);
595 // simple closing cap
596 aSequence
= getLineCapSegments(nSegments
, aMaterial
);
599 aResultVector
.push_back(new TransformPrimitive3D(std::move(aCapTrans
), aSequence
));
603 const basegfx::B3DVector
aBack(aCurr
- aLast
);
604 const double fCross(basegfx::cross(aBack
, aForw
).getLength());
606 if(!basegfx::fTools::equalZero(fCross
))
608 // line connect non-parallel, aBack, aForw, use getLineJoin()
609 const double fAngle(acos(aBack
.scalar(aForw
) / (fForwLen
* aBack
.getLength()))); // 0.0 .. M_PI_2
610 Primitive3DContainer
aNewList(
615 getMiterMinimumAngle(),
618 // calculate transformation. First, get angle in YZ between nForw projected on (1, 0, 0) and nBack
619 basegfx::B3DHomMatrix
aInvRotVector(aRotVector
);
620 aInvRotVector
.invert();
621 basegfx::B3DVector
aTransBack(aInvRotVector
* aBack
);
622 const double fRotInYZ(atan2(aTransBack
.getY(), aTransBack
.getZ()));
624 // create trans by rotating unit sphere with angle 90 degrees around Y, then 180-fRot in X.
625 // Also apply usual scaling and translation
626 basegfx::B3DHomMatrix aSphereTrans
;
627 aSphereTrans
.rotate(0.0, M_PI_2
, 0.0);
628 aSphereTrans
.rotate(M_PI
- fRotInYZ
, 0.0, 0.0);
629 aSphereTrans
*= aRotVector
;
630 aSphereTrans
.scale(getRadius(), getRadius(), getRadius());
631 aSphereTrans
.translate(aCurr
.getX(), aCurr
.getY(), aCurr
.getZ());
633 // line start edge, build transformed primitiveVector3D
634 aResultVector
.push_back(
635 new TransformPrimitive3D(
636 std::move(aSphereTrans
),
641 // create line segments, build transformed primitiveVector3D
642 aResultVector
.push_back(
643 new TransformPrimitive3D(
644 std::move(aTubeTrans
),
645 getLineTubeSegments(nSegments
, aMaterial
)));
647 if(bNoLineJoin
|| (!bClosed
&& bLast
))
650 basegfx::B3DHomMatrix aBackCapTrans
;
652 // Mirror (line end) and radius scale
653 aBackCapTrans
.rotate(0.0, M_PI
, 0.0);
654 aBackCapTrans
.scale(getRadius(), getRadius(), getRadius());
656 if(bLineCapSquare
&& bLast
)
658 // correct position when square and prolonged
659 aBackCapTrans
.translate(fForwLen
+ getRadius(), 0.0, 0.0);
664 aBackCapTrans
.translate(fForwLen
, 0.0, 0.0);
667 // rotate and translate to destination
668 aBackCapTrans
*= aRotVector
;
669 aBackCapTrans
.translate(aCurr
.getX(), aCurr
.getY(), aCurr
.getZ());
671 // get primitiveVector3D
672 Primitive3DContainer aSequence
;
674 if(bLineCapRound
&& bLast
)
677 aSequence
= getLineCapRoundSegments(nSegments
, aMaterial
);
681 // simple closing cap
682 aSequence
= getLineCapSegments(nSegments
, aMaterial
);
685 aResultVector
.push_back(
686 new TransformPrimitive3D(
687 std::move(aBackCapTrans
),
692 // prepare next loop step
700 aResultVector
.push_back(new PolygonHairlinePrimitive3D(getB3DPolygon(), getBColor()));
704 // prepare return value
705 Primitive3DContainer
aRetval(aResultVector
.size());
707 std::transform(aResultVector
.cbegin(), aResultVector
.cend(), aRetval
.begin(), [](auto &rResult
){return Primitive3DReference(rResult
);});
712 PolygonTubePrimitive3D::PolygonTubePrimitive3D(
713 const basegfx::B3DPolygon
& rPolygon
,
714 const basegfx::BColor
& rBColor
,
715 double fRadius
, basegfx::B2DLineJoin aLineJoin
,
716 css::drawing::LineCap aLineCap
,
717 double fDegreeStepWidth
,
718 double fMiterMinimumAngle
)
719 : PolygonHairlinePrimitive3D(rPolygon
, rBColor
),
721 mfDegreeStepWidth(fDegreeStepWidth
),
722 mfMiterMinimumAngle(fMiterMinimumAngle
),
723 maLineJoin(aLineJoin
),
728 bool PolygonTubePrimitive3D::operator==(const BasePrimitive3D
& rPrimitive
) const
730 if(PolygonHairlinePrimitive3D::operator==(rPrimitive
))
732 const PolygonTubePrimitive3D
& rCompare
= static_cast<const PolygonTubePrimitive3D
&>(rPrimitive
);
734 return (getRadius() == rCompare
.getRadius()
735 && getDegreeStepWidth() == rCompare
.getDegreeStepWidth()
736 && getMiterMinimumAngle() == rCompare
.getMiterMinimumAngle()
737 && getLineJoin() == rCompare
.getLineJoin()
738 && getLineCap() == rCompare
.getLineCap());
744 Primitive3DContainer
PolygonTubePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
746 std::unique_lock
aGuard( m_aMutex
);
748 if(getLast3DDecomposition().empty())
750 const Primitive3DContainer
aNewSequence(impCreate3DDecomposition(rViewInformation
));
751 const_cast< PolygonTubePrimitive3D
* >(this)->maLast3DDecomposition
= aNewSequence
;
754 return getLast3DDecomposition();
758 ImplPrimitive3DIDBlock(PolygonTubePrimitive3D
, PRIMITIVE3D_ID_POLYGONTUBEPRIMITIVE3D
)
761 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */