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/b2dpolygontools.hxx>
23 #include <basegfx/polygon/b3dpolypolygontools.hxx>
24 #include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx>
25 #include <basegfx/utils/canvastools.hxx>
26 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx>
27 #include <drawinglayer/geometry/viewinformation3d.hxx>
28 #include <drawinglayer/attribute/sdrfillattribute.hxx>
29 #include <drawinglayer/attribute/sdrlineattribute.hxx>
30 #include <drawinglayer/attribute/sdrshadowattribute.hxx>
33 using namespace com::sun::star
;
36 namespace drawinglayer
40 Primitive3DContainer
SdrLathePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
42 Primitive3DContainer aRetval
;
45 const Slice3DVector
& rSliceVector
= getSlices();
47 if(!rSliceVector
.empty())
49 const bool bBackScale(!basegfx::fTools::equal(getBackScale(), 1.0));
50 const bool bClosedRotation(!bBackScale
&& getHorizontalSegments() && basegfx::fTools::equal(getRotation(), F_2PI
));
53 // decide what to create
54 const css::drawing::NormalsKind
eNormalsKind(getSdr3DObjectAttribute().getNormalsKind());
55 const bool bCreateNormals(css::drawing::NormalsKind_SPECIFIC
== eNormalsKind
);
56 const bool bCreateTextureCoordinatesX(css::drawing::TextureProjectionMode_OBJECTSPECIFIC
== getSdr3DObjectAttribute().getTextureProjectionX());
57 const bool bCreateTextureCoordinatesY(css::drawing::TextureProjectionMode_OBJECTSPECIFIC
== getSdr3DObjectAttribute().getTextureProjectionY());
58 basegfx::B2DHomMatrix aTexTransform
;
60 if(!getSdrLFSAttribute().getFill().isDefault()
61 && (bCreateTextureCoordinatesX
|| bCreateTextureCoordinatesY
))
63 aTexTransform
.set(0, 0, 0.0);
64 aTexTransform
.set(0, 1, 1.0);
65 aTexTransform
.set(1, 0, 1.0);
66 aTexTransform
.set(1, 1, 0.0);
68 aTexTransform
.translate(0.0, -0.5);
69 aTexTransform
.scale(1.0, -1.0);
70 aTexTransform
.translate(0.0, 0.5);
74 std::vector
< basegfx::B3DPolyPolygon
> aFill
;
75 extractPlanesFromSlice(aFill
, rSliceVector
,
76 bCreateNormals
, getSmoothNormals(), getSmoothLids(), bClosedRotation
,
77 0.85, 0.6, bCreateTextureCoordinatesX
|| bCreateTextureCoordinatesY
, aTexTransform
);
80 const basegfx::B3DRange
aRange(getRangeFrom3DGeometry(aFill
));
83 if(!getSdrLFSAttribute().getFill().isDefault())
85 if(css::drawing::NormalsKind_SPHERE
== eNormalsKind
)
87 applyNormalsKindSphereTo3DGeometry(aFill
, aRange
);
89 else if(css::drawing::NormalsKind_FLAT
== eNormalsKind
)
91 applyNormalsKindFlatTo3DGeometry(aFill
);
94 if(getSdr3DObjectAttribute().getNormalsInvert())
96 applyNormalsInvertTo3DGeometry(aFill
);
100 // texture coordinates
101 if(!getSdrLFSAttribute().getFill().isDefault())
103 applyTextureTo3DGeometry(
104 getSdr3DObjectAttribute().getTextureProjectionX(),
105 getSdr3DObjectAttribute().getTextureProjectionY(),
111 if(!getSdrLFSAttribute().getFill().isDefault())
114 aRetval
= create3DPolyPolygonFillPrimitives(
118 getSdr3DObjectAttribute(),
119 getSdrLFSAttribute().getFill(),
120 getSdrLFSAttribute().getFillFloatTransGradient());
124 // create simplified 3d hit test geometry
125 aRetval
= createHiddenGeometryPrimitives3D(
129 getSdr3DObjectAttribute());
133 if(!getSdrLFSAttribute().getLine().isDefault())
135 if(getSdr3DObjectAttribute().getReducedLineGeometry())
137 // create geometric outlines with reduced line geometry for chart
138 const basegfx::B3DPolyPolygon
aHorLine(extractHorizontalLinesFromSlice(rSliceVector
, bClosedRotation
));
139 const sal_uInt32
nCount(aHorLine
.count());
140 basegfx::B3DPolyPolygon aNewLineGeometry
;
142 for(a
= 1; a
< nCount
; a
++)
144 // for each loop pair create the connection edges
145 createReducedOutlines(
148 aHorLine
.getB3DPolygon(a
- 1),
149 aHorLine
.getB3DPolygon(a
),
153 for(a
= 0; a
< nCount
; a
++)
155 // filter hor lines for empty loops (those who have their defining point on the Y-Axis)
156 basegfx::B3DPolygon
aCandidate(aHorLine
.getB3DPolygon(a
));
157 aCandidate
.removeDoublePoints();
159 if(aCandidate
.count())
161 aNewLineGeometry
.append(aCandidate
);
165 if(aNewLineGeometry
.count())
167 const Primitive3DContainer
aLines(create3DPolyPolygonLinePrimitives(
168 aNewLineGeometry
, getTransform(), getSdrLFSAttribute().getLine()));
169 aRetval
.append(aLines
);
174 // extract line geometry from slices
175 const basegfx::B3DPolyPolygon
aHorLine(extractHorizontalLinesFromSlice(rSliceVector
, bClosedRotation
));
176 const basegfx::B3DPolyPolygon
aVerLine(extractVerticalLinesFromSlice(rSliceVector
));
178 // add horizontal lines
179 const Primitive3DContainer
aHorLines(create3DPolyPolygonLinePrimitives(
180 aHorLine
, getTransform(), getSdrLFSAttribute().getLine()));
181 aRetval
.append(aHorLines
);
183 // add vertical lines
184 const Primitive3DContainer
aVerLines(create3DPolyPolygonLinePrimitives(
185 aVerLine
, getTransform(), getSdrLFSAttribute().getLine()));
186 aRetval
.append(aVerLines
);
191 if(!getSdrLFSAttribute().getShadow().isDefault()
194 const Primitive3DContainer
aShadow(createShadowPrimitive3D(
195 aRetval
, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D()));
196 aRetval
.append(aShadow
);
203 void SdrLathePrimitive3D::impCreateSlices()
205 // prepare the polygon. No double points, correct orientations and a correct
206 // outmost polygon are needed
207 // Also important: subdivide here to ensure equal point count for all slices (!)
208 maCorrectedPolyPolygon
= basegfx::utils::adaptiveSubdivideByAngle(getPolyPolygon());
209 maCorrectedPolyPolygon
.removeDoublePoints();
210 maCorrectedPolyPolygon
= basegfx::utils::correctOrientations(maCorrectedPolyPolygon
);
211 maCorrectedPolyPolygon
= basegfx::utils::correctOutmostPolygon(maCorrectedPolyPolygon
);
213 // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures
214 // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0 is different
215 // at all (and not always)
216 const basegfx::B2DPolygon
aSubCandidate(maCorrectedPolyPolygon
.getB2DPolygon(0));
217 const sal_uInt32
nSubEdgeCount(aSubCandidate
.isClosed() ? aSubCandidate
.count() : (aSubCandidate
.count() ? aSubCandidate
.count() - 1 : 0));
219 if(nSubEdgeCount
!= getVerticalSegments())
221 maCorrectedPolyPolygon
= basegfx::utils::reSegmentPolyPolygon(maCorrectedPolyPolygon
, getVerticalSegments());
224 // prepare slices as geometry
225 createLatheSlices(maSlices
, maCorrectedPolyPolygon
, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack());
228 const Slice3DVector
& SdrLathePrimitive3D::getSlices() const
230 // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine()
231 // again when no longer geometry is needed for non-visible 3D objects as it is now for chart
232 if(getPolyPolygon().count() && maSlices
.empty())
234 ::osl::MutexGuard
aGuard( m_aMutex
);
236 const_cast< SdrLathePrimitive3D
& >(*this).impCreateSlices();
242 SdrLathePrimitive3D::SdrLathePrimitive3D(
243 const basegfx::B3DHomMatrix
& rTransform
,
244 const basegfx::B2DVector
& rTextureSize
,
245 const attribute::SdrLineFillShadowAttribute3D
& rSdrLFSAttribute
,
246 const attribute::Sdr3DObjectAttribute
& rSdr3DObjectAttribute
,
247 const basegfx::B2DPolyPolygon
& rPolyPolygon
,
248 sal_uInt32 nHorizontalSegments
,
249 sal_uInt32 nVerticalSegments
,
258 : SdrPrimitive3D(rTransform
, rTextureSize
, rSdrLFSAttribute
, rSdr3DObjectAttribute
),
259 maCorrectedPolyPolygon(),
261 maPolyPolygon(rPolyPolygon
),
262 mnHorizontalSegments(nHorizontalSegments
),
263 mnVerticalSegments(nVerticalSegments
),
264 mfDiagonal(fDiagonal
),
265 mfBackScale(fBackScale
),
266 mfRotation(fRotation
),
267 mbSmoothNormals(bSmoothNormals
),
268 mbSmoothLids(bSmoothLids
),
269 mbCharacterMode(bCharacterMode
),
270 mbCloseFront(bCloseFront
),
271 mbCloseBack(bCloseBack
)
273 // make sure Rotation is positive
274 if(basegfx::fTools::lessOrEqual(getRotation(), 0.0))
279 // make sure the percentage value getDiagonal() is between 0.0 and 1.0
280 if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0))
284 else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0))
289 // no close front/back when polygon is not closed
290 if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0).isClosed())
292 mbCloseFront
= mbCloseBack
= false;
295 // no edge rounding when not closing
296 if(!getCloseFront() && !getCloseBack())
302 SdrLathePrimitive3D::~SdrLathePrimitive3D()
306 bool SdrLathePrimitive3D::operator==(const BasePrimitive3D
& rPrimitive
) const
308 if(SdrPrimitive3D::operator==(rPrimitive
))
310 const SdrLathePrimitive3D
& rCompare
= static_cast< const SdrLathePrimitive3D
& >(rPrimitive
);
312 return (getPolyPolygon() == rCompare
.getPolyPolygon()
313 && getHorizontalSegments() == rCompare
.getHorizontalSegments()
314 && getVerticalSegments() == rCompare
.getVerticalSegments()
315 && getDiagonal() == rCompare
.getDiagonal()
316 && getBackScale() == rCompare
.getBackScale()
317 && getRotation() == rCompare
.getRotation()
318 && getSmoothNormals() == rCompare
.getSmoothNormals()
319 && getSmoothLids() == rCompare
.getSmoothLids()
320 && getCharacterMode() == rCompare
.getCharacterMode()
321 && getCloseFront() == rCompare
.getCloseFront()
322 && getCloseBack() == rCompare
.getCloseBack());
328 basegfx::B3DRange
SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D
& /*rViewInformation*/) const
330 // use default from sdrPrimitive3D which uses transformation expanded by line width/2
331 // The parent implementation which uses the ranges of the decomposition would be more
332 // correct, but for historical reasons it is necessary to do the old method: To get
333 // the range of the non-transformed geometry and transform it then. This leads to different
334 // ranges where the new method is more correct, but the need to keep the old behaviour
335 // has priority here.
336 return get3DRangeFromSlices(getSlices());
339 Primitive3DContainer
SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
341 if(getSdr3DObjectAttribute().getReducedLineGeometry())
343 if(!mpLastRLGViewInformation
||
344 (!getBuffered3DDecomposition().empty()
345 && *mpLastRLGViewInformation
!= rViewInformation
))
347 ::osl::MutexGuard
aGuard( m_aMutex
);
349 // conditions of last local decomposition with reduced lines have changed. Remember
350 // new one and clear current decompositiopn
351 SdrLathePrimitive3D
* pThat
= const_cast< SdrLathePrimitive3D
* >(this);
352 pThat
->setBuffered3DDecomposition(Primitive3DContainer());
353 pThat
->mpLastRLGViewInformation
.reset( new geometry::ViewInformation3D(rViewInformation
) );
357 // no test for buffering needed, call parent
358 return SdrPrimitive3D::get3DDecomposition(rViewInformation
);
362 ImplPrimitive3DIDBlock(SdrLathePrimitive3D
, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D
)
364 } // end of namespace primitive3d
365 } // end of namespace drawinglayer
367 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */