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