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>
31 using namespace com::sun::star
;
34 namespace drawinglayer::primitive3d
36 Primitive3DContainer
SdrLathePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
38 Primitive3DContainer aRetval
;
41 const Slice3DVector
& rSliceVector
= getSlices();
43 if(!rSliceVector
.empty())
45 const bool bBackScale(!basegfx::fTools::equal(getBackScale(), 1.0));
46 const bool bClosedRotation(!bBackScale
&& getHorizontalSegments() && basegfx::fTools::equal(getRotation(), F_2PI
));
49 // decide what to create
50 const css::drawing::NormalsKind
eNormalsKind(getSdr3DObjectAttribute().getNormalsKind());
51 const bool bCreateNormals(css::drawing::NormalsKind_SPECIFIC
== eNormalsKind
);
52 const bool bCreateTextureCoordinatesX(css::drawing::TextureProjectionMode_OBJECTSPECIFIC
== getSdr3DObjectAttribute().getTextureProjectionX());
53 const bool bCreateTextureCoordinatesY(css::drawing::TextureProjectionMode_OBJECTSPECIFIC
== getSdr3DObjectAttribute().getTextureProjectionY());
54 basegfx::B2DHomMatrix aTexTransform
;
56 if(!getSdrLFSAttribute().getFill().isDefault()
57 && (bCreateTextureCoordinatesX
|| bCreateTextureCoordinatesY
))
59 aTexTransform
.set(0, 0, 0.0);
60 aTexTransform
.set(0, 1, 1.0);
61 aTexTransform
.set(1, 0, 1.0);
62 aTexTransform
.set(1, 1, 0.0);
64 aTexTransform
.translate(0.0, -0.5);
65 aTexTransform
.scale(1.0, -1.0);
66 aTexTransform
.translate(0.0, 0.5);
70 std::vector
< basegfx::B3DPolyPolygon
> aFill
;
71 extractPlanesFromSlice(aFill
, rSliceVector
,
72 bCreateNormals
, getSmoothNormals(), getSmoothLids(), bClosedRotation
,
73 0.85, 0.6, bCreateTextureCoordinatesX
|| bCreateTextureCoordinatesY
, aTexTransform
);
76 const basegfx::B3DRange
aRange(getRangeFrom3DGeometry(aFill
));
79 if(!getSdrLFSAttribute().getFill().isDefault())
81 if(css::drawing::NormalsKind_SPHERE
== eNormalsKind
)
83 applyNormalsKindSphereTo3DGeometry(aFill
, aRange
);
85 else if(css::drawing::NormalsKind_FLAT
== eNormalsKind
)
87 applyNormalsKindFlatTo3DGeometry(aFill
);
90 if(getSdr3DObjectAttribute().getNormalsInvert())
92 applyNormalsInvertTo3DGeometry(aFill
);
96 // texture coordinates
97 if(!getSdrLFSAttribute().getFill().isDefault())
99 applyTextureTo3DGeometry(
100 getSdr3DObjectAttribute().getTextureProjectionX(),
101 getSdr3DObjectAttribute().getTextureProjectionY(),
107 if(!getSdrLFSAttribute().getFill().isDefault())
110 aRetval
= create3DPolyPolygonFillPrimitives(
114 getSdr3DObjectAttribute(),
115 getSdrLFSAttribute().getFill(),
116 getSdrLFSAttribute().getFillFloatTransGradient());
120 // create simplified 3d hit test geometry
121 aRetval
= createHiddenGeometryPrimitives3D(
125 getSdr3DObjectAttribute());
129 if(!getSdrLFSAttribute().getLine().isDefault())
131 if(getSdr3DObjectAttribute().getReducedLineGeometry())
133 // create geometric outlines with reduced line geometry for chart
134 const basegfx::B3DPolyPolygon
aHorLine(extractHorizontalLinesFromSlice(rSliceVector
, bClosedRotation
));
135 const sal_uInt32
nCount(aHorLine
.count());
136 basegfx::B3DPolyPolygon aNewLineGeometry
;
138 for(a
= 1; a
< nCount
; a
++)
140 // for each loop pair create the connection edges
141 createReducedOutlines(
144 aHorLine
.getB3DPolygon(a
- 1),
145 aHorLine
.getB3DPolygon(a
),
149 for(a
= 0; a
< nCount
; a
++)
151 // filter hor lines for empty loops (those who have their defining point on the Y-Axis)
152 basegfx::B3DPolygon
aCandidate(aHorLine
.getB3DPolygon(a
));
153 aCandidate
.removeDoublePoints();
155 if(aCandidate
.count())
157 aNewLineGeometry
.append(aCandidate
);
161 if(aNewLineGeometry
.count())
163 const Primitive3DContainer
aLines(create3DPolyPolygonLinePrimitives(
164 aNewLineGeometry
, getTransform(), getSdrLFSAttribute().getLine()));
165 aRetval
.append(aLines
);
170 // extract line geometry from slices
171 const basegfx::B3DPolyPolygon
aHorLine(extractHorizontalLinesFromSlice(rSliceVector
, bClosedRotation
));
172 const basegfx::B3DPolyPolygon
aVerLine(extractVerticalLinesFromSlice(rSliceVector
));
174 // add horizontal lines
175 const Primitive3DContainer
aHorLines(create3DPolyPolygonLinePrimitives(
176 aHorLine
, getTransform(), getSdrLFSAttribute().getLine()));
177 aRetval
.append(aHorLines
);
179 // add vertical lines
180 const Primitive3DContainer
aVerLines(create3DPolyPolygonLinePrimitives(
181 aVerLine
, getTransform(), getSdrLFSAttribute().getLine()));
182 aRetval
.append(aVerLines
);
187 if(!getSdrLFSAttribute().getShadow().isDefault()
190 const Primitive3DContainer
aShadow(createShadowPrimitive3D(
191 aRetval
, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D()));
192 aRetval
.append(aShadow
);
199 void SdrLathePrimitive3D::impCreateSlices()
201 // prepare the polygon. No double points, correct orientations and a correct
202 // outmost polygon are needed
203 // Also important: subdivide here to ensure equal point count for all slices (!)
204 maCorrectedPolyPolygon
= basegfx::utils::adaptiveSubdivideByAngle(getPolyPolygon());
205 maCorrectedPolyPolygon
.removeDoublePoints();
206 maCorrectedPolyPolygon
= basegfx::utils::correctOrientations(maCorrectedPolyPolygon
);
207 maCorrectedPolyPolygon
= basegfx::utils::correctOutmostPolygon(maCorrectedPolyPolygon
);
209 // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures
210 // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0 is different
211 // at all (and not always)
212 const basegfx::B2DPolygon
aSubCandidate(maCorrectedPolyPolygon
.getB2DPolygon(0));
213 const sal_uInt32
nSubEdgeCount(aSubCandidate
.isClosed() ? aSubCandidate
.count() : (aSubCandidate
.count() ? aSubCandidate
.count() - 1 : 0));
215 if(nSubEdgeCount
!= getVerticalSegments())
217 maCorrectedPolyPolygon
= basegfx::utils::reSegmentPolyPolygon(maCorrectedPolyPolygon
, getVerticalSegments());
220 // prepare slices as geometry
221 createLatheSlices(maSlices
, maCorrectedPolyPolygon
, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack());
224 const Slice3DVector
& SdrLathePrimitive3D::getSlices() const
226 // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine()
227 // again when no longer geometry is needed for non-visible 3D objects as it is now for chart
228 if(getPolyPolygon().count() && maSlices
.empty())
230 ::osl::MutexGuard
aGuard( m_aMutex
);
232 const_cast< SdrLathePrimitive3D
& >(*this).impCreateSlices();
238 SdrLathePrimitive3D::SdrLathePrimitive3D(
239 const basegfx::B3DHomMatrix
& rTransform
,
240 const basegfx::B2DVector
& rTextureSize
,
241 const attribute::SdrLineFillShadowAttribute3D
& rSdrLFSAttribute
,
242 const attribute::Sdr3DObjectAttribute
& rSdr3DObjectAttribute
,
243 const basegfx::B2DPolyPolygon
& rPolyPolygon
,
244 sal_uInt32 nHorizontalSegments
,
245 sal_uInt32 nVerticalSegments
,
254 : SdrPrimitive3D(rTransform
, rTextureSize
, rSdrLFSAttribute
, rSdr3DObjectAttribute
),
255 maCorrectedPolyPolygon(),
257 maPolyPolygon(rPolyPolygon
),
258 mnHorizontalSegments(nHorizontalSegments
),
259 mnVerticalSegments(nVerticalSegments
),
260 mfDiagonal(fDiagonal
),
261 mfBackScale(fBackScale
),
262 mfRotation(fRotation
),
263 mbSmoothNormals(bSmoothNormals
),
264 mbSmoothLids(bSmoothLids
),
265 mbCharacterMode(bCharacterMode
),
266 mbCloseFront(bCloseFront
),
267 mbCloseBack(bCloseBack
)
269 // make sure Rotation is positive
270 if(basegfx::fTools::lessOrEqual(getRotation(), 0.0))
275 // make sure the percentage value getDiagonal() is between 0.0 and 1.0
276 if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0))
280 else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0))
285 // no close front/back when polygon is not closed
286 if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0).isClosed())
288 mbCloseFront
= mbCloseBack
= false;
291 // no edge rounding when not closing
292 if(!getCloseFront() && !getCloseBack())
298 SdrLathePrimitive3D::~SdrLathePrimitive3D()
302 bool SdrLathePrimitive3D::operator==(const BasePrimitive3D
& rPrimitive
) const
304 if(SdrPrimitive3D::operator==(rPrimitive
))
306 const SdrLathePrimitive3D
& rCompare
= static_cast< const SdrLathePrimitive3D
& >(rPrimitive
);
308 return (getPolyPolygon() == rCompare
.getPolyPolygon()
309 && getHorizontalSegments() == rCompare
.getHorizontalSegments()
310 && getVerticalSegments() == rCompare
.getVerticalSegments()
311 && getDiagonal() == rCompare
.getDiagonal()
312 && getBackScale() == rCompare
.getBackScale()
313 && getRotation() == rCompare
.getRotation()
314 && getSmoothNormals() == rCompare
.getSmoothNormals()
315 && getSmoothLids() == rCompare
.getSmoothLids()
316 && getCharacterMode() == rCompare
.getCharacterMode()
317 && getCloseFront() == rCompare
.getCloseFront()
318 && getCloseBack() == rCompare
.getCloseBack());
324 basegfx::B3DRange
SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D
& /*rViewInformation*/) const
326 // use default from sdrPrimitive3D which uses transformation expanded by line width/2
327 // The parent implementation which uses the ranges of the decomposition would be more
328 // correct, but for historical reasons it is necessary to do the old method: To get
329 // the range of the non-transformed geometry and transform it then. This leads to different
330 // ranges where the new method is more correct, but the need to keep the old behaviour
331 // has priority here.
332 return get3DRangeFromSlices(getSlices());
335 Primitive3DContainer
SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
337 if(getSdr3DObjectAttribute().getReducedLineGeometry())
339 if(!mpLastRLGViewInformation
||
340 (!getBuffered3DDecomposition().empty()
341 && *mpLastRLGViewInformation
!= rViewInformation
))
343 ::osl::MutexGuard
aGuard( m_aMutex
);
345 // conditions of last local decomposition with reduced lines have changed. Remember
346 // new one and clear current decompositiopn
347 SdrLathePrimitive3D
* pThat
= const_cast< SdrLathePrimitive3D
* >(this);
348 pThat
->setBuffered3DDecomposition(Primitive3DContainer());
349 pThat
->mpLastRLGViewInformation
.reset( new geometry::ViewInformation3D(rViewInformation
) );
353 // no test for buffering needed, call parent
354 return SdrPrimitive3D::get3DDecomposition(rViewInformation
);
358 ImplPrimitive3DIDBlock(SdrLathePrimitive3D
, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D
)
360 } // end of namespace
362 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */