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/sdrlatheprimitive3d.hxx>
21 #include <basegfx/matrix/b2dhommatrix.hxx>
22 #include <basegfx/polygon/b3dpolygon.hxx>
23 #include <primitive3d/sdrdecompositiontools3d.hxx>
24 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
25 #include <drawinglayer/geometry/viewinformation3d.hxx>
26 #include <drawinglayer/attribute/sdrfillattribute.hxx>
27 #include <drawinglayer/attribute/sdrlineattribute.hxx>
28 #include <drawinglayer/attribute/sdrshadowattribute.hxx>
32 using namespace com::sun::star
;
35 namespace drawinglayer::primitive3d
37 Primitive3DContainer
SdrLathePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
39 Primitive3DContainer aRetval
;
42 const Slice3DVector
& rSliceVector
= getSlices();
44 if(!rSliceVector
.empty())
46 const bool bBackScale(!basegfx::fTools::equal(getBackScale(), 1.0));
47 const bool bClosedRotation(!bBackScale
&& getHorizontalSegments() && basegfx::fTools::equal(getRotation(), 2 * M_PI
));
50 // decide what to create
51 const css::drawing::NormalsKind
eNormalsKind(getSdr3DObjectAttribute().getNormalsKind());
52 const bool bCreateNormals(css::drawing::NormalsKind_SPECIFIC
== eNormalsKind
);
53 const bool bCreateTextureCoordinatesX(css::drawing::TextureProjectionMode_OBJECTSPECIFIC
== getSdr3DObjectAttribute().getTextureProjectionX());
54 const bool bCreateTextureCoordinatesY(css::drawing::TextureProjectionMode_OBJECTSPECIFIC
== getSdr3DObjectAttribute().getTextureProjectionY());
55 basegfx::B2DHomMatrix aTexTransform
;
57 if(!getSdrLFSAttribute().getFill().isDefault()
58 && (bCreateTextureCoordinatesX
|| bCreateTextureCoordinatesY
))
60 aTexTransform
.set(0, 0, 0.0);
61 aTexTransform
.set(0, 1, 1.0);
62 aTexTransform
.set(1, 0, 1.0);
63 aTexTransform
.set(1, 1, 0.0);
65 aTexTransform
.translate(0.0, -0.5);
66 aTexTransform
.scale(1.0, -1.0);
67 aTexTransform
.translate(0.0, 0.5);
71 std::vector
< basegfx::B3DPolyPolygon
> aFill
;
72 extractPlanesFromSlice(aFill
, rSliceVector
,
73 bCreateNormals
, getSmoothNormals(), getSmoothLids(), bClosedRotation
,
74 0.85, 0.6, bCreateTextureCoordinatesX
|| bCreateTextureCoordinatesY
, aTexTransform
);
77 const basegfx::B3DRange
aRange(getRangeFrom3DGeometry(aFill
));
80 if(!getSdrLFSAttribute().getFill().isDefault())
82 if(css::drawing::NormalsKind_SPHERE
== eNormalsKind
)
84 applyNormalsKindSphereTo3DGeometry(aFill
, aRange
);
86 else if(css::drawing::NormalsKind_FLAT
== eNormalsKind
)
88 applyNormalsKindFlatTo3DGeometry(aFill
);
91 if(getSdr3DObjectAttribute().getNormalsInvert())
93 applyNormalsInvertTo3DGeometry(aFill
);
97 // texture coordinates
98 if(!getSdrLFSAttribute().getFill().isDefault())
100 applyTextureTo3DGeometry(
101 getSdr3DObjectAttribute().getTextureProjectionX(),
102 getSdr3DObjectAttribute().getTextureProjectionY(),
108 if(!getSdrLFSAttribute().getFill().isDefault())
111 aRetval
= create3DPolyPolygonFillPrimitives(
115 getSdr3DObjectAttribute(),
116 getSdrLFSAttribute().getFill(),
117 getSdrLFSAttribute().getFillFloatTransGradient());
121 // create simplified 3d hit test geometry
122 aRetval
= createHiddenGeometryPrimitives3D(
126 getSdr3DObjectAttribute());
130 if(!getSdrLFSAttribute().getLine().isDefault())
132 if(getSdr3DObjectAttribute().getReducedLineGeometry())
134 // create geometric outlines with reduced line geometry for chart
135 const basegfx::B3DPolyPolygon
aHorLine(extractHorizontalLinesFromSlice(rSliceVector
, bClosedRotation
));
136 const sal_uInt32
nCount(aHorLine
.count());
137 basegfx::B3DPolyPolygon aNewLineGeometry
;
139 for(a
= 1; a
< nCount
; a
++)
141 // for each loop pair create the connection edges
142 createReducedOutlines(
145 aHorLine
.getB3DPolygon(a
- 1),
146 aHorLine
.getB3DPolygon(a
),
150 for(a
= 0; a
< nCount
; a
++)
152 // filter hor lines for empty loops (those who have their defining point on the Y-Axis)
153 basegfx::B3DPolygon
aCandidate(aHorLine
.getB3DPolygon(a
));
154 aCandidate
.removeDoublePoints();
156 if(aCandidate
.count())
158 aNewLineGeometry
.append(aCandidate
);
162 if(aNewLineGeometry
.count())
164 const Primitive3DContainer
aLines(create3DPolyPolygonLinePrimitives(
165 aNewLineGeometry
, getTransform(), getSdrLFSAttribute().getLine()));
166 aRetval
.append(aLines
);
171 // extract line geometry from slices
172 const basegfx::B3DPolyPolygon
aHorLine(extractHorizontalLinesFromSlice(rSliceVector
, bClosedRotation
));
173 const basegfx::B3DPolyPolygon
aVerLine(extractVerticalLinesFromSlice(rSliceVector
));
175 // add horizontal lines
176 const Primitive3DContainer
aHorLines(create3DPolyPolygonLinePrimitives(
177 aHorLine
, getTransform(), getSdrLFSAttribute().getLine()));
178 aRetval
.append(aHorLines
);
180 // add vertical lines
181 const Primitive3DContainer
aVerLines(create3DPolyPolygonLinePrimitives(
182 aVerLine
, getTransform(), getSdrLFSAttribute().getLine()));
183 aRetval
.append(aVerLines
);
188 if(!getSdrLFSAttribute().getShadow().isDefault()
191 const Primitive3DContainer
aShadow(createShadowPrimitive3D(
192 aRetval
, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D()));
193 aRetval
.append(aShadow
);
200 void SdrLathePrimitive3D::impCreateSlices()
202 // prepare the polygon. No double points, correct orientations and a correct
203 // outmost polygon are needed
204 // Also important: subdivide here to ensure equal point count for all slices (!)
205 maCorrectedPolyPolygon
= basegfx::utils::adaptiveSubdivideByAngle(getPolyPolygon());
206 maCorrectedPolyPolygon
.removeDoublePoints();
207 maCorrectedPolyPolygon
= basegfx::utils::correctOrientations(maCorrectedPolyPolygon
);
208 maCorrectedPolyPolygon
= basegfx::utils::correctOutmostPolygon(maCorrectedPolyPolygon
);
210 // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures
211 // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0 is different
212 // at all (and not always)
213 const basegfx::B2DPolygon
aSubCandidate(maCorrectedPolyPolygon
.getB2DPolygon(0));
214 const sal_uInt32
nSubEdgeCount(aSubCandidate
.isClosed() ? aSubCandidate
.count() : (aSubCandidate
.count() ? aSubCandidate
.count() - 1 : 0));
216 if(nSubEdgeCount
!= getVerticalSegments())
218 maCorrectedPolyPolygon
= basegfx::utils::reSegmentPolyPolygon(maCorrectedPolyPolygon
, getVerticalSegments());
221 // prepare slices as geometry
222 createLatheSlices(maSlices
, maCorrectedPolyPolygon
, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack());
225 const Slice3DVector
& SdrLathePrimitive3D::getSlices() const
227 // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine()
228 // again when no longer geometry is needed for non-visible 3D objects as it is now for chart
229 if(getPolyPolygon().count() && maSlices
.empty())
231 std::unique_lock
aGuard( m_aMutex
);
233 const_cast< SdrLathePrimitive3D
& >(*this).impCreateSlices();
239 SdrLathePrimitive3D::SdrLathePrimitive3D(
240 const basegfx::B3DHomMatrix
& rTransform
,
241 const basegfx::B2DVector
& rTextureSize
,
242 const attribute::SdrLineFillShadowAttribute3D
& rSdrLFSAttribute
,
243 const attribute::Sdr3DObjectAttribute
& rSdr3DObjectAttribute
,
244 basegfx::B2DPolyPolygon aPolyPolygon
,
245 sal_uInt32 nHorizontalSegments
,
246 sal_uInt32 nVerticalSegments
,
255 : SdrPrimitive3D(rTransform
, rTextureSize
, rSdrLFSAttribute
, rSdr3DObjectAttribute
),
256 maPolyPolygon(std::move(aPolyPolygon
)),
257 mnHorizontalSegments(nHorizontalSegments
),
258 mnVerticalSegments(nVerticalSegments
),
259 mfDiagonal(fDiagonal
),
260 mfBackScale(fBackScale
),
261 mfRotation(fRotation
),
262 mbSmoothNormals(bSmoothNormals
),
263 mbSmoothLids(bSmoothLids
),
264 mbCharacterMode(bCharacterMode
),
265 mbCloseFront(bCloseFront
),
266 mbCloseBack(bCloseBack
)
268 // make sure Rotation is positive
269 if(getRotation() <= 0.0)
274 // make sure the percentage value getDiagonal() is between 0.0 and 1.0
275 if(getDiagonal() <= 0.0)
279 else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0))
284 // no close front/back when polygon is not closed
285 if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0).isClosed())
287 mbCloseFront
= mbCloseBack
= false;
290 // no edge rounding when not closing
291 if(!getCloseFront() && !getCloseBack())
297 SdrLathePrimitive3D::~SdrLathePrimitive3D()
301 bool SdrLathePrimitive3D::operator==(const BasePrimitive3D
& rPrimitive
) const
303 if(SdrPrimitive3D::operator==(rPrimitive
))
305 const SdrLathePrimitive3D
& rCompare
= static_cast< const SdrLathePrimitive3D
& >(rPrimitive
);
307 return (getPolyPolygon() == rCompare
.getPolyPolygon()
308 && getHorizontalSegments() == rCompare
.getHorizontalSegments()
309 && getVerticalSegments() == rCompare
.getVerticalSegments()
310 && getDiagonal() == rCompare
.getDiagonal()
311 && getBackScale() == rCompare
.getBackScale()
312 && getRotation() == rCompare
.getRotation()
313 && getSmoothNormals() == rCompare
.getSmoothNormals()
314 && getSmoothLids() == rCompare
.getSmoothLids()
315 && getCharacterMode() == rCompare
.getCharacterMode()
316 && getCloseFront() == rCompare
.getCloseFront()
317 && getCloseBack() == rCompare
.getCloseBack());
323 basegfx::B3DRange
SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D
& /*rViewInformation*/) const
325 // use default from sdrPrimitive3D which uses transformation expanded by line width/2
326 // The parent implementation which uses the ranges of the decomposition would be more
327 // correct, but for historical reasons it is necessary to do the old method: To get
328 // the range of the non-transformed geometry and transform it then. This leads to different
329 // ranges where the new method is more correct, but the need to keep the old behaviour
330 // has priority here.
331 return get3DRangeFromSlices(getSlices());
334 Primitive3DContainer
SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
336 if(getSdr3DObjectAttribute().getReducedLineGeometry())
338 if(!mpLastRLGViewInformation
||
339 (!getBuffered3DDecomposition().empty()
340 && *mpLastRLGViewInformation
!= rViewInformation
))
342 std::unique_lock
aGuard( m_aMutex
);
344 // conditions of last local decomposition with reduced lines have changed. Remember
345 // new one and clear current decompositiopn
346 SdrLathePrimitive3D
* pThat
= const_cast< SdrLathePrimitive3D
* >(this);
347 pThat
->setBuffered3DDecomposition(Primitive3DContainer());
348 pThat
->mpLastRLGViewInformation
= rViewInformation
;
352 // no test for buffering needed, call parent
353 return SdrPrimitive3D::get3DDecomposition(rViewInformation
);
357 ImplPrimitive3DIDBlock(SdrLathePrimitive3D
, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D
)
359 } // end of namespace
361 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */