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/tools/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>
32 //////////////////////////////////////////////////////////////////////////////
34 using namespace com::sun::star
;
36 //////////////////////////////////////////////////////////////////////////////
38 namespace drawinglayer
42 Primitive3DSequence
SdrLathePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
44 Primitive3DSequence aRetval
;
47 const Slice3DVector
& rSliceVector
= getSlices();
49 if(!rSliceVector
.empty())
51 const bool bBackScale(!basegfx::fTools::equal(getBackScale(), 1.0));
52 const bool bClosedRotation(!bBackScale
&& getHorizontalSegments() && basegfx::fTools::equal(getRotation(), F_2PI
));
55 // decide what to create
56 const ::com::sun::star::drawing::NormalsKind
eNormalsKind(getSdr3DObjectAttribute().getNormalsKind());
57 const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC
== eNormalsKind
);
58 const bool bCreateTextureCoordiantesX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC
== getSdr3DObjectAttribute().getTextureProjectionX());
59 const bool bCreateTextureCoordiantesY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC
== getSdr3DObjectAttribute().getTextureProjectionY());
60 basegfx::B2DHomMatrix aTexTransform
;
62 if(!getSdrLFSAttribute().getFill().isDefault()
63 && (bCreateTextureCoordiantesX
|| bCreateTextureCoordiantesY
))
65 aTexTransform
.set(0, 0, 0.0);
66 aTexTransform
.set(0, 1, 1.0);
67 aTexTransform
.set(1, 0, 1.0);
68 aTexTransform
.set(1, 1, 0.0);
70 aTexTransform
.translate(0.0, -0.5);
71 aTexTransform
.scale(1.0, -1.0);
72 aTexTransform
.translate(0.0, 0.5);
76 ::std::vector
< basegfx::B3DPolyPolygon
> aFill
;
77 extractPlanesFromSlice(aFill
, rSliceVector
,
78 bCreateNormals
, getSmoothHorizontalNormals(), getSmoothNormals(), getSmoothLids(), bClosedRotation
,
79 0.85, 0.6, bCreateTextureCoordiantesX
|| bCreateTextureCoordiantesY
, aTexTransform
);
82 const basegfx::B3DRange
aRange(getRangeFrom3DGeometry(aFill
));
85 if(!getSdrLFSAttribute().getFill().isDefault())
87 if(::com::sun::star::drawing::NormalsKind_SPHERE
== eNormalsKind
)
89 applyNormalsKindSphereTo3DGeometry(aFill
, aRange
);
91 else if(::com::sun::star::drawing::NormalsKind_FLAT
== eNormalsKind
)
93 applyNormalsKindFlatTo3DGeometry(aFill
);
96 if(getSdr3DObjectAttribute().getNormalsInvert())
98 applyNormalsInvertTo3DGeometry(aFill
);
102 // texture coordinates
103 if(!getSdrLFSAttribute().getFill().isDefault())
105 applyTextureTo3DGeometry(
106 getSdr3DObjectAttribute().getTextureProjectionX(),
107 getSdr3DObjectAttribute().getTextureProjectionY(),
113 if(!getSdrLFSAttribute().getFill().isDefault())
116 aRetval
= create3DPolyPolygonFillPrimitives(
120 getSdr3DObjectAttribute(),
121 getSdrLFSAttribute().getFill(),
122 getSdrLFSAttribute().getFillFloatTransGradient());
126 // create simplified 3d hit test geometry
127 aRetval
= createHiddenGeometryPrimitives3D(
131 getSdr3DObjectAttribute());
135 if(!getSdrLFSAttribute().getLine().isDefault())
137 if(getSdr3DObjectAttribute().getReducedLineGeometry())
139 // create geometric outlines with reduced line geometry for chart
140 const basegfx::B3DPolyPolygon
aHorLine(extractHorizontalLinesFromSlice(rSliceVector
, bClosedRotation
));
141 const sal_uInt32
nCount(aHorLine
.count());
142 basegfx::B3DPolyPolygon aNewLineGeometry
;
144 for(a
= 1; a
< nCount
; a
++)
146 // for each loop pair create the connection edges
147 createReducedOutlines(
150 aHorLine
.getB3DPolygon(a
- 1),
151 aHorLine
.getB3DPolygon(a
),
155 for(a
= 0; a
< nCount
; a
++)
157 // filter hor lines for empty loops (those who have their defining point on the Y-Axis)
158 basegfx::B3DPolygon
aCandidate(aHorLine
.getB3DPolygon(a
));
159 aCandidate
.removeDoublePoints();
161 if(aCandidate
.count())
163 aNewLineGeometry
.append(aCandidate
);
167 if(aNewLineGeometry
.count())
169 const Primitive3DSequence
aLines(create3DPolyPolygonLinePrimitives(
170 aNewLineGeometry
, getTransform(), getSdrLFSAttribute().getLine()));
171 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval
, aLines
);
176 // extract line geometry from slices
177 const basegfx::B3DPolyPolygon
aHorLine(extractHorizontalLinesFromSlice(rSliceVector
, bClosedRotation
));
178 const basegfx::B3DPolyPolygon
aVerLine(extractVerticalLinesFromSlice(rSliceVector
));
180 // add horizontal lines
181 const Primitive3DSequence
aHorLines(create3DPolyPolygonLinePrimitives(
182 aHorLine
, getTransform(), getSdrLFSAttribute().getLine()));
183 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval
, aHorLines
);
185 // add vertical lines
186 const Primitive3DSequence
aVerLines(create3DPolyPolygonLinePrimitives(
187 aVerLine
, getTransform(), getSdrLFSAttribute().getLine()));
188 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval
, aVerLines
);
193 if(!getSdrLFSAttribute().getShadow().isDefault()
194 && aRetval
.hasElements())
196 const Primitive3DSequence
aShadow(createShadowPrimitive3D(
197 aRetval
, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D()));
198 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval
, aShadow
);
205 void SdrLathePrimitive3D::impCreateSlices()
207 // prepare the polygon. No double points, correct orientations and a correct
208 // outmost polygon are needed
209 // Also important: subdivide here to ensure equal point count for all slices (!)
210 maCorrectedPolyPolygon
= basegfx::tools::adaptiveSubdivideByAngle(getPolyPolygon());
211 maCorrectedPolyPolygon
.removeDoublePoints();
212 maCorrectedPolyPolygon
= basegfx::tools::correctOrientations(maCorrectedPolyPolygon
);
213 maCorrectedPolyPolygon
= basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon
);
215 // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures
216 // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0L is different
217 // at all (and not always)
218 const basegfx::B2DPolygon
aSubCandidate(maCorrectedPolyPolygon
.getB2DPolygon(0));
219 const sal_uInt32
nSubEdgeCount(aSubCandidate
.isClosed() ? aSubCandidate
.count() : (aSubCandidate
.count() ? aSubCandidate
.count() - 1L : 0L));
221 if(nSubEdgeCount
!= getVerticalSegments())
223 maCorrectedPolyPolygon
= basegfx::tools::reSegmentPolyPolygon(maCorrectedPolyPolygon
, getVerticalSegments());
226 // prepare slices as geometry
227 createLatheSlices(maSlices
, maCorrectedPolyPolygon
, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack());
230 const Slice3DVector
& SdrLathePrimitive3D::getSlices() const
232 // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine()
233 // again when no longer geometry is needed for non-visible 3D objects as it is now for chart
234 if(getPolyPolygon().count() && !maSlices
.size())
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
,
254 bool bSmoothHorizontalNormals
,
259 : SdrPrimitive3D(rTransform
, rTextureSize
, rSdrLFSAttribute
, rSdr3DObjectAttribute
),
260 maCorrectedPolyPolygon(),
262 maPolyPolygon(rPolyPolygon
),
263 mnHorizontalSegments(nHorizontalSegments
),
264 mnVerticalSegments(nVerticalSegments
),
265 mfDiagonal(fDiagonal
),
266 mfBackScale(fBackScale
),
267 mfRotation(fRotation
),
268 mpLastRLGViewInformation(0),
269 mbSmoothNormals(bSmoothNormals
),
270 mbSmoothHorizontalNormals(bSmoothHorizontalNormals
),
271 mbSmoothLids(bSmoothLids
),
272 mbCharacterMode(bCharacterMode
),
273 mbCloseFront(bCloseFront
),
274 mbCloseBack(bCloseBack
)
276 // make sure Rotation is positive
277 if(basegfx::fTools::lessOrEqual(getRotation(), 0.0))
282 // make sure the percentage value getDiagonal() is between 0.0 and 1.0
283 if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0))
287 else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0))
292 // no close front/back when polygon is not closed
293 if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed())
295 mbCloseFront
= mbCloseBack
= false;
298 // no edge rounding when not closing
299 if(!getCloseFront() && !getCloseBack())
305 SdrLathePrimitive3D::~SdrLathePrimitive3D()
307 if(mpLastRLGViewInformation
)
309 delete mpLastRLGViewInformation
;
313 bool SdrLathePrimitive3D::operator==(const BasePrimitive3D
& rPrimitive
) const
315 if(SdrPrimitive3D::operator==(rPrimitive
))
317 const SdrLathePrimitive3D
& rCompare
= static_cast< const SdrLathePrimitive3D
& >(rPrimitive
);
319 return (getPolyPolygon() == rCompare
.getPolyPolygon()
320 && getHorizontalSegments() == rCompare
.getHorizontalSegments()
321 && getVerticalSegments() == rCompare
.getVerticalSegments()
322 && getDiagonal() == rCompare
.getDiagonal()
323 && getBackScale() == rCompare
.getBackScale()
324 && getRotation() == rCompare
.getRotation()
325 && getSmoothNormals() == rCompare
.getSmoothNormals()
326 && getSmoothHorizontalNormals() == rCompare
.getSmoothHorizontalNormals()
327 && getSmoothLids() == rCompare
.getSmoothLids()
328 && getCharacterMode() == rCompare
.getCharacterMode()
329 && getCloseFront() == rCompare
.getCloseFront()
330 && getCloseBack() == rCompare
.getCloseBack());
336 basegfx::B3DRange
SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D
& /*rViewInformation*/) const
338 // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2
339 // The parent implementation which uses the ranges of the decomposition would be more
340 // corrcet, but for historical reasons it is necessary to do the old method: To get
341 // the range of the non-transformed geometry and transform it then. This leads to different
342 // ranges where the new method is more correct, but the need to keep the old behaviour
343 // has priority here.
344 return get3DRangeFromSlices(getSlices());
347 Primitive3DSequence
SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D
& rViewInformation
) const
349 if(getSdr3DObjectAttribute().getReducedLineGeometry())
351 if(!mpLastRLGViewInformation
||
352 (getBuffered3DDecomposition().hasElements()
353 && *mpLastRLGViewInformation
!= rViewInformation
))
355 // conditions of last local decomposition with reduced lines have changed. Remember
356 // new one and clear current decompositiopn
357 SdrLathePrimitive3D
* pThat
= const_cast< SdrLathePrimitive3D
* >(this);
358 pThat
->setBuffered3DDecomposition(Primitive3DSequence());
359 delete pThat
->mpLastRLGViewInformation
;
360 pThat
->mpLastRLGViewInformation
= new geometry::ViewInformation3D(rViewInformation
);
364 // no test for buffering needed, call parent
365 return SdrPrimitive3D::get3DDecomposition(rViewInformation
);
369 ImplPrimitive3DIDBlock(SdrLathePrimitive3D
, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D
)
371 } // end of namespace primitive3d
372 } // end of namespace drawinglayer
374 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */