1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 23 24 // MARKER(update_precomp.py): autogen include statement, do not remove 25 #include "precompiled_drawinglayer.hxx" 26 27 #include <drawinglayer/primitive3d/sdrlatheprimitive3d.hxx> 28 #include <basegfx/matrix/b2dhommatrix.hxx> 29 #include <basegfx/polygon/b2dpolygontools.hxx> 30 #include <basegfx/polygon/b3dpolypolygontools.hxx> 31 #include <drawinglayer/primitive3d/sdrdecompositiontools3d.hxx> 32 #include <basegfx/tools/canvastools.hxx> 33 #include <drawinglayer/primitive3d/drawinglayer_primitivetypes3d.hxx> 34 #include <drawinglayer/geometry/viewinformation3d.hxx> 35 #include <drawinglayer/attribute/sdrfillattribute.hxx> 36 #include <drawinglayer/attribute/sdrlineattribute.hxx> 37 #include <drawinglayer/attribute/sdrshadowattribute.hxx> 38 39 ////////////////////////////////////////////////////////////////////////////// 40 41 using namespace com::sun::star; 42 43 ////////////////////////////////////////////////////////////////////////////// 44 45 namespace drawinglayer 46 { 47 namespace primitive3d 48 { create3DDecomposition(const geometry::ViewInformation3D & rViewInformation) const49 Primitive3DSequence SdrLathePrimitive3D::create3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const 50 { 51 Primitive3DSequence aRetval; 52 53 // get slices 54 const Slice3DVector& rSliceVector = getSlices(); 55 56 if(rSliceVector.size()) 57 { 58 const bool bBackScale(!basegfx::fTools::equal(getBackScale(), 1.0)); 59 const bool bClosedRotation(!bBackScale && getHorizontalSegments() && basegfx::fTools::equal(getRotation(), F_2PI)); 60 sal_uInt32 a; 61 62 // decide what to create 63 const ::com::sun::star::drawing::NormalsKind eNormalsKind(getSdr3DObjectAttribute().getNormalsKind()); 64 const bool bCreateNormals(::com::sun::star::drawing::NormalsKind_SPECIFIC == eNormalsKind); 65 const bool bCreateTextureCoordiantesX(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionX()); 66 const bool bCreateTextureCoordiantesY(::com::sun::star::drawing::TextureProjectionMode_OBJECTSPECIFIC == getSdr3DObjectAttribute().getTextureProjectionY()); 67 basegfx::B2DHomMatrix aTexTransform; 68 69 if(!getSdrLFSAttribute().getFill().isDefault() 70 && (bCreateTextureCoordiantesX || bCreateTextureCoordiantesY)) 71 { 72 aTexTransform.set(0, 0, 0.0); 73 aTexTransform.set(0, 1, 1.0); 74 aTexTransform.set(1, 0, 1.0); 75 aTexTransform.set(1, 1, 0.0); 76 77 aTexTransform.translate(0.0, -0.5); 78 aTexTransform.scale(1.0, -1.0); 79 aTexTransform.translate(0.0, 0.5); 80 } 81 82 // create geometry 83 ::std::vector< basegfx::B3DPolyPolygon > aFill; 84 extractPlanesFromSlice(aFill, rSliceVector, 85 bCreateNormals, getSmoothHorizontalNormals(), getSmoothNormals(), getSmoothLids(), bClosedRotation, 86 0.85, 0.6, bCreateTextureCoordiantesX || bCreateTextureCoordiantesY, aTexTransform); 87 88 // get full range 89 const basegfx::B3DRange aRange(getRangeFrom3DGeometry(aFill)); 90 91 // normal creation 92 if(!getSdrLFSAttribute().getFill().isDefault()) 93 { 94 if(::com::sun::star::drawing::NormalsKind_SPHERE == eNormalsKind) 95 { 96 applyNormalsKindSphereTo3DGeometry(aFill, aRange); 97 } 98 else if(::com::sun::star::drawing::NormalsKind_FLAT == eNormalsKind) 99 { 100 applyNormalsKindFlatTo3DGeometry(aFill); 101 } 102 103 if(getSdr3DObjectAttribute().getNormalsInvert()) 104 { 105 applyNormalsInvertTo3DGeometry(aFill); 106 } 107 } 108 109 // texture coordinates 110 if(!getSdrLFSAttribute().getFill().isDefault()) 111 { 112 applyTextureTo3DGeometry( 113 getSdr3DObjectAttribute().getTextureProjectionX(), 114 getSdr3DObjectAttribute().getTextureProjectionY(), 115 aFill, 116 aRange, 117 getTextureSize()); 118 } 119 120 if(!getSdrLFSAttribute().getFill().isDefault()) 121 { 122 // add fill 123 aRetval = create3DPolyPolygonFillPrimitives( 124 aFill, 125 getTransform(), 126 getTextureSize(), 127 getSdr3DObjectAttribute(), 128 getSdrLFSAttribute().getFill(), 129 getSdrLFSAttribute().getFillFloatTransGradient()); 130 } 131 else 132 { 133 // create simplified 3d hit test geometry 134 aRetval = createHiddenGeometryPrimitives3D( 135 aFill, 136 getTransform(), 137 getTextureSize(), 138 getSdr3DObjectAttribute()); 139 } 140 141 // add line 142 if(!getSdrLFSAttribute().getLine().isDefault()) 143 { 144 if(getSdr3DObjectAttribute().getReducedLineGeometry()) 145 { 146 // create geometric outlines with reduced line geometry for chart 147 const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, bClosedRotation)); 148 const sal_uInt32 nCount(aHorLine.count()); 149 basegfx::B3DPolyPolygon aNewLineGeometry; 150 151 for(a = 1; a < nCount; a++) 152 { 153 // for each loop pair create the connection edges 154 createReducedOutlines( 155 rViewInformation, 156 getTransform(), 157 aHorLine.getB3DPolygon(a - 1), 158 aHorLine.getB3DPolygon(a), 159 aNewLineGeometry); 160 } 161 162 for(a = 0; a < nCount; a++) 163 { 164 // filter hor lines for empty loops (those who have their defining point on the Y-Axis) 165 basegfx::B3DPolygon aCandidate(aHorLine.getB3DPolygon(a)); 166 aCandidate.removeDoublePoints(); 167 168 if(aCandidate.count()) 169 { 170 aNewLineGeometry.append(aCandidate); 171 } 172 } 173 174 if(aNewLineGeometry.count()) 175 { 176 const Primitive3DSequence aLines(create3DPolyPolygonLinePrimitives( 177 aNewLineGeometry, getTransform(), getSdrLFSAttribute().getLine())); 178 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aLines); 179 } 180 } 181 else 182 { 183 // extract line geometry from slices 184 const basegfx::B3DPolyPolygon aHorLine(extractHorizontalLinesFromSlice(rSliceVector, bClosedRotation)); 185 const basegfx::B3DPolyPolygon aVerLine(extractVerticalLinesFromSlice(rSliceVector)); 186 187 // add horizontal lines 188 const Primitive3DSequence aHorLines(create3DPolyPolygonLinePrimitives( 189 aHorLine, getTransform(), getSdrLFSAttribute().getLine())); 190 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aHorLines); 191 192 // add vertical lines 193 const Primitive3DSequence aVerLines(create3DPolyPolygonLinePrimitives( 194 aVerLine, getTransform(), getSdrLFSAttribute().getLine())); 195 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aVerLines); 196 } 197 } 198 199 // add shadow 200 if(!getSdrLFSAttribute().getShadow().isDefault() 201 && aRetval.hasElements()) 202 { 203 const Primitive3DSequence aShadow(createShadowPrimitive3D( 204 aRetval, getSdrLFSAttribute().getShadow(), getSdr3DObjectAttribute().getShadow3D())); 205 appendPrimitive3DSequenceToPrimitive3DSequence(aRetval, aShadow); 206 } 207 } 208 209 return aRetval; 210 } 211 impCreateSlices()212 void SdrLathePrimitive3D::impCreateSlices() 213 { 214 // prepare the polygon. No double points, correct orientations and a correct 215 // outmost polygon are needed 216 // Also important: subdivide here to ensure equal point count for all slices (!) 217 maCorrectedPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(getPolyPolygon()); 218 maCorrectedPolyPolygon.removeDoublePoints(); 219 maCorrectedPolyPolygon = basegfx::tools::correctOrientations(maCorrectedPolyPolygon); 220 maCorrectedPolyPolygon = basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon); 221 222 // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures 223 // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0L is different 224 // at all (and not always) 225 const basegfx::B2DPolygon aSubCandidate(maCorrectedPolyPolygon.getB2DPolygon(0)); 226 const sal_uInt32 nSubEdgeCount(aSubCandidate.isClosed() ? aSubCandidate.count() : (aSubCandidate.count() ? aSubCandidate.count() - 1L : 0L)); 227 228 if(nSubEdgeCount != getVerticalSegments()) 229 { 230 maCorrectedPolyPolygon = basegfx::tools::reSegmentPolyPolygon(maCorrectedPolyPolygon, getVerticalSegments()); 231 } 232 233 // prepare slices as geometry 234 createLatheSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack()); 235 } 236 getSlices() const237 const Slice3DVector& SdrLathePrimitive3D::getSlices() const 238 { 239 // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine() 240 // again when no longer geometry is needed for non-visible 3D objects as it is now for chart 241 if(getPolyPolygon().count() && !maSlices.size()) 242 { 243 ::osl::Mutex m_mutex; 244 const_cast< SdrLathePrimitive3D& >(*this).impCreateSlices(); 245 } 246 247 return maSlices; 248 } 249 SdrLathePrimitive3D(const basegfx::B3DHomMatrix & rTransform,const basegfx::B2DVector & rTextureSize,const attribute::SdrLineFillShadowAttribute3D & rSdrLFSAttribute,const attribute::Sdr3DObjectAttribute & rSdr3DObjectAttribute,const basegfx::B2DPolyPolygon & rPolyPolygon,sal_uInt32 nHorizontalSegments,sal_uInt32 nVerticalSegments,double fDiagonal,double fBackScale,double fRotation,bool bSmoothNormals,bool bSmoothHorizontalNormals,bool bSmoothLids,bool bCharacterMode,bool bCloseFront,bool bCloseBack)250 SdrLathePrimitive3D::SdrLathePrimitive3D( 251 const basegfx::B3DHomMatrix& rTransform, 252 const basegfx::B2DVector& rTextureSize, 253 const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, 254 const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, 255 const basegfx::B2DPolyPolygon& rPolyPolygon, 256 sal_uInt32 nHorizontalSegments, 257 sal_uInt32 nVerticalSegments, 258 double fDiagonal, 259 double fBackScale, 260 double fRotation, 261 bool bSmoothNormals, 262 bool bSmoothHorizontalNormals, 263 bool bSmoothLids, 264 bool bCharacterMode, 265 bool bCloseFront, 266 bool bCloseBack) 267 : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), 268 maCorrectedPolyPolygon(), 269 maSlices(), 270 maPolyPolygon(rPolyPolygon), 271 mnHorizontalSegments(nHorizontalSegments), 272 mnVerticalSegments(nVerticalSegments), 273 mfDiagonal(fDiagonal), 274 mfBackScale(fBackScale), 275 mfRotation(fRotation), 276 mpLastRLGViewInformation(0), 277 mbSmoothNormals(bSmoothNormals), 278 mbSmoothHorizontalNormals(bSmoothHorizontalNormals), 279 mbSmoothLids(bSmoothLids), 280 mbCharacterMode(bCharacterMode), 281 mbCloseFront(bCloseFront), 282 mbCloseBack(bCloseBack) 283 { 284 // make sure Rotation is positive 285 if(basegfx::fTools::lessOrEqual(getRotation(), 0.0)) 286 { 287 mfRotation = 0.0; 288 } 289 290 // make sure the percentage value getDiagonal() is between 0.0 and 1.0 291 if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0)) 292 { 293 mfDiagonal = 0.0; 294 } 295 else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0)) 296 { 297 mfDiagonal = 1.0; 298 } 299 300 // no close front/back when polygon is not closed 301 if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed()) 302 { 303 mbCloseFront = mbCloseBack = false; 304 } 305 306 // no edge rounding when not closing 307 if(!getCloseFront() && !getCloseBack()) 308 { 309 mfDiagonal = 0.0; 310 } 311 } 312 ~SdrLathePrimitive3D()313 SdrLathePrimitive3D::~SdrLathePrimitive3D() 314 { 315 if(mpLastRLGViewInformation) 316 { 317 delete mpLastRLGViewInformation; 318 } 319 } 320 operator ==(const BasePrimitive3D & rPrimitive) const321 bool SdrLathePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const 322 { 323 if(SdrPrimitive3D::operator==(rPrimitive)) 324 { 325 const SdrLathePrimitive3D& rCompare = static_cast< const SdrLathePrimitive3D& >(rPrimitive); 326 327 return (getPolyPolygon() == rCompare.getPolyPolygon() 328 && getHorizontalSegments() == rCompare.getHorizontalSegments() 329 && getVerticalSegments() == rCompare.getVerticalSegments() 330 && getDiagonal() == rCompare.getDiagonal() 331 && getBackScale() == rCompare.getBackScale() 332 && getRotation() == rCompare.getRotation() 333 && getSmoothNormals() == rCompare.getSmoothNormals() 334 && getSmoothHorizontalNormals() == rCompare.getSmoothHorizontalNormals() 335 && getSmoothLids() == rCompare.getSmoothLids() 336 && getCharacterMode() == rCompare.getCharacterMode() 337 && getCloseFront() == rCompare.getCloseFront() 338 && getCloseBack() == rCompare.getCloseBack()); 339 } 340 341 return false; 342 } 343 getB3DRange(const geometry::ViewInformation3D &) const344 basegfx::B3DRange SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const 345 { 346 // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2 347 // The parent implementation which uses the ranges of the decomposition would be more 348 // corrcet, but for historical reasons it is necessary to do the old method: To get 349 // the range of the non-transformed geometry and transform it then. This leads to different 350 // ranges where the new method is more correct, but the need to keep the old behaviour 351 // has priority here. 352 return get3DRangeFromSlices(getSlices()); 353 } 354 get3DDecomposition(const geometry::ViewInformation3D & rViewInformation) const355 Primitive3DSequence SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const 356 { 357 if(getSdr3DObjectAttribute().getReducedLineGeometry()) 358 { 359 if(!mpLastRLGViewInformation || 360 (getBuffered3DDecomposition().hasElements() 361 && *mpLastRLGViewInformation != rViewInformation)) 362 { 363 // conditions of last local decomposition with reduced lines have changed. Remember 364 // new one and clear current decompositiopn 365 ::osl::Mutex m_mutex; 366 SdrLathePrimitive3D* pThat = const_cast< SdrLathePrimitive3D* >(this); 367 pThat->setBuffered3DDecomposition(Primitive3DSequence()); 368 delete pThat->mpLastRLGViewInformation; 369 pThat->mpLastRLGViewInformation = new geometry::ViewInformation3D(rViewInformation); 370 } 371 } 372 373 // no test for buffering needed, call parent 374 return SdrPrimitive3D::get3DDecomposition(rViewInformation); 375 } 376 377 // provide unique ID 378 ImplPrimitrive3DIDBlock(SdrLathePrimitive3D, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D) 379 380 } // end of namespace primitive3d 381 } // end of namespace drawinglayer 382 383 ////////////////////////////////////////////////////////////////////////////// 384 // eof 385