/src/libreoffice/drawinglayer/source/primitive3d/sdrlatheprimitive3d.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | * |
9 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <com/sun/star/drawing/NormalsKind.hpp> |
21 | | #include <drawinglayer/primitive3d/sdrlatheprimitive3d.hxx> |
22 | | #include <basegfx/matrix/b2dhommatrix.hxx> |
23 | | #include <basegfx/polygon/b3dpolygon.hxx> |
24 | | #include <basegfx/range/b3drange.hxx> |
25 | | #include <primitive3d/sdrdecompositiontools3d.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> |
31 | | #include <utility> |
32 | | |
33 | | |
34 | | using namespace com::sun::star; |
35 | | |
36 | | |
37 | | namespace drawinglayer::primitive3d |
38 | | { |
39 | | Primitive3DContainer SdrLathePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const |
40 | 0 | { |
41 | 0 | Primitive3DContainer aRetval; |
42 | | |
43 | | // get slices |
44 | 0 | const Slice3DVector& rSliceVector = getSlices(); |
45 | |
|
46 | 0 | if(!rSliceVector.empty()) |
47 | 0 | { |
48 | 0 | const bool bBackScale(!basegfx::fTools::equal(getBackScale(), 1.0)); |
49 | 0 | const bool bClosedRotation(!bBackScale && getHorizontalSegments() && basegfx::fTools::equal(getRotation(), 2 * M_PI)); |
50 | 0 | sal_uInt32 a; |
51 | | |
52 | | // decide what to create |
53 | 0 | const css::drawing::NormalsKind eNormalsKind(getSdr3DObjectAttribute().getNormalsKind()); |
54 | 0 | const bool bCreateNormals(css::drawing::NormalsKind_SPECIFIC == eNormalsKind); |
55 | 0 | const bool bCreateTextureCoordinatesX(css::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); |
56 | 0 | const bool bCreateTextureCoordinatesY(css::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); |
57 | 0 | basegfx::B2DHomMatrix aTexTransform; |
58 | |
|
59 | 0 | if(!getSdrLFSAttribute().getFill().isDefault() |
60 | 0 | && (bCreateTextureCoordinatesX || bCreateTextureCoordinatesY)) |
61 | 0 | { |
62 | 0 | aTexTransform.set(0, 0, 0.0); |
63 | 0 | aTexTransform.set(0, 1, 1.0); |
64 | 0 | aTexTransform.set(1, 0, 1.0); |
65 | 0 | aTexTransform.set(1, 1, 0.0); |
66 | |
|
67 | 0 | aTexTransform.translate(0.0, -0.5); |
68 | 0 | aTexTransform.scale(1.0, -1.0); |
69 | 0 | aTexTransform.translate(0.0, 0.5); |
70 | 0 | } |
71 | | |
72 | | // create geometry |
73 | 0 | std::vector< basegfx::B3DPolyPolygon > aFill; |
74 | 0 | extractPlanesFromSlice(aFill, rSliceVector, |
75 | 0 | bCreateNormals, getSmoothNormals(), getSmoothLids(), bClosedRotation, |
76 | 0 | 0.85, 0.6, bCreateTextureCoordinatesX || bCreateTextureCoordinatesY, aTexTransform); |
77 | | |
78 | | // get full range |
79 | 0 | const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill)); |
80 | | |
81 | | // normal creation |
82 | 0 | if(!getSdrLFSAttribute().getFill().isDefault()) |
83 | 0 | { |
84 | 0 | if(css::drawing::NormalsKind_SPHERE == eNormalsKind) |
85 | 0 | { |
86 | 0 | applyNormalsKindSphereTo3DGeometry(aFill, aRange); |
87 | 0 | } |
88 | 0 | else if(css::drawing::NormalsKind_FLAT == eNormalsKind) |
89 | 0 | { |
90 | 0 | applyNormalsKindFlatTo3DGeometry(aFill); |
91 | 0 | } |
92 | |
|
93 | 0 | if(getSdr3DObjectAttribute().getNormalsInvert()) |
94 | 0 | { |
95 | 0 | applyNormalsInvertTo3DGeometry(aFill); |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | // texture coordinates |
100 | 0 | if(!getSdrLFSAttribute().getFill().isDefault()) |
101 | 0 | { |
102 | 0 | applyTextureTo3DGeometry( |
103 | 0 | getSdr3DObjectAttribute().getTextureProjectionX(), |
104 | 0 | getSdr3DObjectAttribute().getTextureProjectionY(), |
105 | 0 | aFill, |
106 | 0 | aRange, |
107 | 0 | getTextureSize()); |
108 | 0 | } |
109 | |
|
110 | 0 | if(!getSdrLFSAttribute().getFill().isDefault()) |
111 | 0 | { |
112 | | // add fill |
113 | 0 | aRetval = create3DPolyPolygonFillPrimitives( |
114 | 0 | aFill, |
115 | 0 | getTransform(), |
116 | 0 | getTextureSize(), |
117 | 0 | getSdr3DObjectAttribute(), |
118 | 0 | getSdrLFSAttribute().getFill(), |
119 | 0 | getSdrLFSAttribute().getFillFloatTransGradient()); |
120 | 0 | } |
121 | 0 | else |
122 | 0 | { |
123 | | // create simplified 3d hit test geometry |
124 | 0 | aRetval = createHiddenGeometryPrimitives3D( |
125 | 0 | aFill, |
126 | 0 | getTransform(), |
127 | 0 | getTextureSize(), |
128 | 0 | getSdr3DObjectAttribute()); |
129 | 0 | } |
130 | | |
131 | | // add line |
132 | 0 | if(!getSdrLFSAttribute().getLine().isDefault()) |
133 | 0 | { |
134 | 0 | if(getSdr3DObjectAttribute().getReducedLineGeometry()) |
135 | 0 | { |
136 | | // create geometric outlines with reduced line geometry for chart |
137 | 0 | const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, bClosedRotation)); |
138 | 0 | const sal_uInt32 nCount(aHorLine.count()); |
139 | 0 | basegfx::B3DPolyPolygon aNewLineGeometry; |
140 | |
|
141 | 0 | for(a = 1; a < nCount; a++) |
142 | 0 | { |
143 | | // for each loop pair create the connection edges |
144 | 0 | createReducedOutlines( |
145 | 0 | rViewInformation, |
146 | 0 | getTransform(), |
147 | 0 | aHorLine.getB3DPolygon(a - 1), |
148 | 0 | aHorLine.getB3DPolygon(a), |
149 | 0 | aNewLineGeometry); |
150 | 0 | } |
151 | |
|
152 | 0 | for(a = 0; a < nCount; a++) |
153 | 0 | { |
154 | | // filter hor lines for empty loops (those who have their defining point on the Y-Axis) |
155 | 0 | basegfx::B3DPolygon aCandidate(aHorLine.getB3DPolygon(a)); |
156 | 0 | aCandidate.removeDoublePoints(); |
157 | |
|
158 | 0 | if(aCandidate.count()) |
159 | 0 | { |
160 | 0 | aNewLineGeometry.append(aCandidate); |
161 | 0 | } |
162 | 0 | } |
163 | |
|
164 | 0 | if(aNewLineGeometry.count()) |
165 | 0 | { |
166 | 0 | const Primitive3DContainer aLines(create3DPolyPolygonLinePrimitives( |
167 | 0 | aNewLineGeometry, getTransform(), getSdrLFSAttribute().getLine())); |
168 | 0 | aRetval.append(aLines); |
169 | 0 | } |
170 | 0 | } |
171 | 0 | else |
172 | 0 | { |
173 | | // extract line geometry from slices |
174 | 0 | const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, bClosedRotation)); |
175 | 0 | const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector)); |
176 | | |
177 | | // add horizontal lines |
178 | 0 | const Primitive3DContainer aHorLines(create3DPolyPolygonLinePrimitives( |
179 | 0 | aHorLine, getTransform(), getSdrLFSAttribute().getLine())); |
180 | 0 | aRetval.append(aHorLines); |
181 | | |
182 | | // add vertical lines |
183 | 0 | const Primitive3DContainer aVerLines(create3DPolyPolygonLinePrimitives( |
184 | 0 | aVerLine, getTransform(), getSdrLFSAttribute().getLine())); |
185 | 0 | aRetval.append(aVerLines); |
186 | 0 | } |
187 | 0 | } |
188 | | |
189 | | // add shadow |
190 | 0 | if(!getSdrLFSAttribute().getShadow().isDefault() |
191 | 0 | && !aRetval.empty()) |
192 | 0 | { |
193 | 0 | const Primitive3DContainer aShadow(createShadowPrimitive3D( |
194 | 0 | aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); |
195 | 0 | aRetval.append(aShadow); |
196 | 0 | } |
197 | 0 | } |
198 | |
|
199 | 0 | return aRetval; |
200 | 0 | } |
201 | | |
202 | | void SdrLathePrimitive3D::impCreateSlices() |
203 | 0 | { |
204 | | // prepare the polygon. No double points, correct orientations and a correct |
205 | | // outmost polygon are needed |
206 | | // Also important: subdivide here to ensure equal point count for all slices (!) |
207 | 0 | maCorrectedPolyPolygon = basegfx::utils::adaptiveSubdivideByAngle(getPolyPolygon()); |
208 | 0 | maCorrectedPolyPolygon.removeDoublePoints(); |
209 | 0 | maCorrectedPolyPolygon = basegfx::utils::correctOrientations(maCorrectedPolyPolygon); |
210 | 0 | maCorrectedPolyPolygon = basegfx::utils::correctOutmostPolygon(maCorrectedPolyPolygon); |
211 | | |
212 | | // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures |
213 | | // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0 is different |
214 | | // at all (and not always) |
215 | 0 | const basegfx::B2DPolygon aSubCandidate(maCorrectedPolyPolygon.getB2DPolygon(0)); |
216 | 0 | const sal_uInt32 nSubEdgeCount(aSubCandidate.isClosed() ? aSubCandidate.count() : (aSubCandidate.count() ? aSubCandidate.count() - 1 : 0)); |
217 | |
|
218 | 0 | if(nSubEdgeCount != getVerticalSegments()) |
219 | 0 | { |
220 | 0 | maCorrectedPolyPolygon = basegfx::utils::reSegmentPolyPolygon(maCorrectedPolyPolygon, getVerticalSegments()); |
221 | 0 | } |
222 | | |
223 | | // prepare slices as geometry |
224 | 0 | createLatheSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack()); |
225 | 0 | } |
226 | | |
227 | | const Slice3DVector& SdrLathePrimitive3D::getSlices() const |
228 | 0 | { |
229 | | // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine() |
230 | | // again when no longer geometry is needed for non-visible 3D objects as it is now for chart |
231 | 0 | if(getPolyPolygon().count() && maSlices.empty()) |
232 | 0 | { |
233 | 0 | std::unique_lock aGuard( m_aMutex ); |
234 | |
|
235 | 0 | const_cast< SdrLathePrimitive3D& >(*this).impCreateSlices(); |
236 | 0 | } |
237 | |
|
238 | 0 | return maSlices; |
239 | 0 | } |
240 | | |
241 | | SdrLathePrimitive3D::SdrLathePrimitive3D( |
242 | | const basegfx::B3DHomMatrix& rTransform, |
243 | | const basegfx::B2DVector& rTextureSize, |
244 | | const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, |
245 | | const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, |
246 | | basegfx::B2DPolyPolygon aPolyPolygon, |
247 | | sal_uInt32 nHorizontalSegments, |
248 | | sal_uInt32 nVerticalSegments, |
249 | | double fDiagonal, |
250 | | double fBackScale, |
251 | | double fRotation, |
252 | | bool bSmoothNormals, |
253 | | bool bSmoothLids, |
254 | | bool bCharacterMode, |
255 | | bool bCloseFront, |
256 | | bool bCloseBack) |
257 | 0 | : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), |
258 | 0 | maPolyPolygon(std::move(aPolyPolygon)), |
259 | 0 | mnHorizontalSegments(nHorizontalSegments), |
260 | 0 | mnVerticalSegments(nVerticalSegments), |
261 | 0 | mfDiagonal(fDiagonal), |
262 | 0 | mfBackScale(fBackScale), |
263 | 0 | mfRotation(fRotation), |
264 | 0 | mbSmoothNormals(bSmoothNormals), |
265 | 0 | mbSmoothLids(bSmoothLids), |
266 | 0 | mbCharacterMode(bCharacterMode), |
267 | 0 | mbCloseFront(bCloseFront), |
268 | 0 | mbCloseBack(bCloseBack) |
269 | 0 | { |
270 | | // make sure Rotation is positive |
271 | 0 | if(getRotation() <= 0.0) |
272 | 0 | { |
273 | 0 | mfRotation = 0.0; |
274 | 0 | } |
275 | | |
276 | | // make sure the percentage value getDiagonal() is between 0.0 and 1.0 |
277 | 0 | if(getDiagonal() <= 0.0) |
278 | 0 | { |
279 | 0 | mfDiagonal = 0.0; |
280 | 0 | } |
281 | 0 | else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0)) |
282 | 0 | { |
283 | 0 | mfDiagonal = 1.0; |
284 | 0 | } |
285 | | |
286 | | // no close front/back when polygon is not closed |
287 | 0 | if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0).isClosed()) |
288 | 0 | { |
289 | 0 | mbCloseFront = mbCloseBack = false; |
290 | 0 | } |
291 | | |
292 | | // no edge rounding when not closing |
293 | 0 | if(!getCloseFront() && !getCloseBack()) |
294 | 0 | { |
295 | 0 | mfDiagonal = 0.0; |
296 | 0 | } |
297 | 0 | } Unexecuted instantiation: drawinglayer::primitive3d::SdrLathePrimitive3D::SdrLathePrimitive3D(basegfx::B3DHomMatrix const&, basegfx::B2DVector const&, drawinglayer::attribute::SdrLineFillShadowAttribute3D const&, drawinglayer::attribute::Sdr3DObjectAttribute const&, basegfx::B2DPolyPolygon, unsigned int, unsigned int, double, double, double, bool, bool, bool, bool, bool) Unexecuted instantiation: drawinglayer::primitive3d::SdrLathePrimitive3D::SdrLathePrimitive3D(basegfx::B3DHomMatrix const&, basegfx::B2DVector const&, drawinglayer::attribute::SdrLineFillShadowAttribute3D const&, drawinglayer::attribute::Sdr3DObjectAttribute const&, basegfx::B2DPolyPolygon, unsigned int, unsigned int, double, double, double, bool, bool, bool, bool, bool) |
298 | | |
299 | | SdrLathePrimitive3D::~SdrLathePrimitive3D() |
300 | 0 | { |
301 | 0 | } |
302 | | |
303 | | bool SdrLathePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const |
304 | 0 | { |
305 | 0 | if(SdrPrimitive3D::operator==(rPrimitive)) |
306 | 0 | { |
307 | 0 | const SdrLathePrimitive3D& rCompare = static_cast< const SdrLathePrimitive3D& >(rPrimitive); |
308 | |
|
309 | 0 | return (getPolyPolygon() == rCompare.getPolyPolygon() |
310 | 0 | && getHorizontalSegments() == rCompare.getHorizontalSegments() |
311 | 0 | && getVerticalSegments() == rCompare.getVerticalSegments() |
312 | 0 | && getDiagonal() == rCompare.getDiagonal() |
313 | 0 | && getBackScale() == rCompare.getBackScale() |
314 | 0 | && getRotation() == rCompare.getRotation() |
315 | 0 | && getSmoothNormals() == rCompare.getSmoothNormals() |
316 | 0 | && getSmoothLids() == rCompare.getSmoothLids() |
317 | 0 | && getCharacterMode() == rCompare.getCharacterMode() |
318 | 0 | && getCloseFront() == rCompare.getCloseFront() |
319 | 0 | && getCloseBack() == rCompare.getCloseBack()); |
320 | 0 | } |
321 | | |
322 | 0 | return false; |
323 | 0 | } |
324 | | |
325 | | basegfx::B3DRange SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const |
326 | 0 | { |
327 | | // use default from sdrPrimitive3D which uses transformation expanded by line width/2 |
328 | | // The parent implementation which uses the ranges of the decomposition would be more |
329 | | // correct, but for historical reasons it is necessary to do the old method: To get |
330 | | // the range of the non-transformed geometry and transform it then. This leads to different |
331 | | // ranges where the new method is more correct, but the need to keep the old behaviour |
332 | | // has priority here. |
333 | 0 | return get3DRangeFromSlices(getSlices()); |
334 | 0 | } |
335 | | |
336 | | Primitive3DContainer SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const |
337 | 0 | { |
338 | 0 | if(getSdr3DObjectAttribute().getReducedLineGeometry()) |
339 | 0 | { |
340 | 0 | if(!mpLastRLGViewInformation || |
341 | 0 | (!getBuffered3DDecomposition().empty() |
342 | 0 | && *mpLastRLGViewInformation != rViewInformation)) |
343 | 0 | { |
344 | 0 | std::unique_lock aGuard( m_aMutex ); |
345 | | |
346 | | // conditions of last local decomposition with reduced lines have changed. Remember |
347 | | // new one and clear current decompositiopn |
348 | 0 | SdrLathePrimitive3D* pThat = const_cast< SdrLathePrimitive3D* >(this); |
349 | 0 | pThat->setBuffered3DDecomposition(Primitive3DContainer()); |
350 | 0 | pThat->mpLastRLGViewInformation = rViewInformation; |
351 | 0 | } |
352 | 0 | } |
353 | | |
354 | | // no test for buffering needed, call parent |
355 | 0 | return SdrPrimitive3D::get3DDecomposition(rViewInformation); |
356 | 0 | } |
357 | | |
358 | | // provide unique ID |
359 | | ImplPrimitive3DIDBlock(SdrLathePrimitive3D, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D) |
360 | | |
361 | | } // end of namespace |
362 | | |
363 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |