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 { 49 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 212 void SdrLathePrimitive3D::impCreateSlices() 213 { 214 // prepare the polygon. No double points, correct orientations and a correct 215 // outmost polygon are needed 216 maCorrectedPolyPolygon = basegfx::tools::adaptiveSubdivideByAngle(getPolyPolygon()); 217 maCorrectedPolyPolygon.removeDoublePoints(); 218 maCorrectedPolyPolygon = basegfx::tools::correctOrientations(maCorrectedPolyPolygon); 219 maCorrectedPolyPolygon = basegfx::tools::correctOutmostPolygon(maCorrectedPolyPolygon); 220 221 // check edge count of first sub-polygon. If different, reSegment polyPolygon. This ensures 222 // that for polyPolygons, the subPolys 1..n only get reSegmented when polygon 0L is different 223 // at all (and not always) 224 const basegfx::B2DPolygon aSubCandidate(maCorrectedPolyPolygon.getB2DPolygon(0)); 225 const sal_uInt32 nSubEdgeCount(aSubCandidate.isClosed() ? aSubCandidate.count() : (aSubCandidate.count() ? aSubCandidate.count() - 1L : 0L)); 226 227 if(nSubEdgeCount != getVerticalSegments()) 228 { 229 maCorrectedPolyPolygon = basegfx::tools::reSegmentPolyPolygon(maCorrectedPolyPolygon, getVerticalSegments()); 230 } 231 232 // prepare slices as geometry 233 createLatheSlices(maSlices, maCorrectedPolyPolygon, getBackScale(), getDiagonal(), getRotation(), getHorizontalSegments(), getCharacterMode(), getCloseFront(), getCloseBack()); 234 } 235 236 const Slice3DVector& SdrLathePrimitive3D::getSlices() const 237 { 238 // This can be made dependent of getSdrLFSAttribute().getFill() and getSdrLFSAttribute().getLine() 239 // again when no longer geometry is needed for non-visible 3D objects as it is now for chart 240 if(getPolyPolygon().count() && !maSlices.size()) 241 { 242 ::osl::Mutex m_mutex; 243 const_cast< SdrLathePrimitive3D& >(*this).impCreateSlices(); 244 } 245 246 return maSlices; 247 } 248 249 SdrLathePrimitive3D::SdrLathePrimitive3D( 250 const basegfx::B3DHomMatrix& rTransform, 251 const basegfx::B2DVector& rTextureSize, 252 const attribute::SdrLineFillShadowAttribute3D& rSdrLFSAttribute, 253 const attribute::Sdr3DObjectAttribute& rSdr3DObjectAttribute, 254 const basegfx::B2DPolyPolygon& rPolyPolygon, 255 sal_uInt32 nHorizontalSegments, 256 sal_uInt32 nVerticalSegments, 257 double fDiagonal, 258 double fBackScale, 259 double fRotation, 260 bool bSmoothNormals, 261 bool bSmoothHorizontalNormals, 262 bool bSmoothLids, 263 bool bCharacterMode, 264 bool bCloseFront, 265 bool bCloseBack) 266 : SdrPrimitive3D(rTransform, rTextureSize, rSdrLFSAttribute, rSdr3DObjectAttribute), 267 maCorrectedPolyPolygon(), 268 maSlices(), 269 maPolyPolygon(rPolyPolygon), 270 mnHorizontalSegments(nHorizontalSegments), 271 mnVerticalSegments(nVerticalSegments), 272 mfDiagonal(fDiagonal), 273 mfBackScale(fBackScale), 274 mfRotation(fRotation), 275 mpLastRLGViewInformation(0), 276 mbSmoothNormals(bSmoothNormals), 277 mbSmoothHorizontalNormals(bSmoothHorizontalNormals), 278 mbSmoothLids(bSmoothLids), 279 mbCharacterMode(bCharacterMode), 280 mbCloseFront(bCloseFront), 281 mbCloseBack(bCloseBack) 282 { 283 // make sure Rotation is positive 284 if(basegfx::fTools::lessOrEqual(getRotation(), 0.0)) 285 { 286 mfRotation = 0.0; 287 } 288 289 // make sure the percentage value getDiagonal() is between 0.0 and 1.0 290 if(basegfx::fTools::lessOrEqual(getDiagonal(), 0.0)) 291 { 292 mfDiagonal = 0.0; 293 } 294 else if(basegfx::fTools::moreOrEqual(getDiagonal(), 1.0)) 295 { 296 mfDiagonal = 1.0; 297 } 298 299 // no close front/back when polygon is not closed 300 if(getPolyPolygon().count() && !getPolyPolygon().getB2DPolygon(0L).isClosed()) 301 { 302 mbCloseFront = mbCloseBack = false; 303 } 304 305 // no edge rounding when not closing 306 if(!getCloseFront() && !getCloseBack()) 307 { 308 mfDiagonal = 0.0; 309 } 310 } 311 312 SdrLathePrimitive3D::~SdrLathePrimitive3D() 313 { 314 if(mpLastRLGViewInformation) 315 { 316 delete mpLastRLGViewInformation; 317 } 318 } 319 320 bool SdrLathePrimitive3D::operator==(const BasePrimitive3D& rPrimitive) const 321 { 322 if(SdrPrimitive3D::operator==(rPrimitive)) 323 { 324 const SdrLathePrimitive3D& rCompare = static_cast< const SdrLathePrimitive3D& >(rPrimitive); 325 326 return (getPolyPolygon() == rCompare.getPolyPolygon() 327 && getHorizontalSegments() == rCompare.getHorizontalSegments() 328 && getVerticalSegments() == rCompare.getVerticalSegments() 329 && getDiagonal() == rCompare.getDiagonal() 330 && getBackScale() == rCompare.getBackScale() 331 && getRotation() == rCompare.getRotation() 332 && getSmoothNormals() == rCompare.getSmoothNormals() 333 && getSmoothHorizontalNormals() == rCompare.getSmoothHorizontalNormals() 334 && getSmoothLids() == rCompare.getSmoothLids() 335 && getCharacterMode() == rCompare.getCharacterMode() 336 && getCloseFront() == rCompare.getCloseFront() 337 && getCloseBack() == rCompare.getCloseBack()); 338 } 339 340 return false; 341 } 342 343 basegfx::B3DRange SdrLathePrimitive3D::getB3DRange(const geometry::ViewInformation3D& /*rViewInformation*/) const 344 { 345 // use defaut from sdrPrimitive3D which uses transformation expanded by line width/2 346 // The parent implementation which uses the ranges of the decomposition would be more 347 // corrcet, but for historical reasons it is necessary to do the old method: To get 348 // the range of the non-transformed geometry and transform it then. This leads to different 349 // ranges where the new method is more correct, but the need to keep the old behaviour 350 // has priority here. 351 return get3DRangeFromSlices(getSlices()); 352 } 353 354 Primitive3DSequence SdrLathePrimitive3D::get3DDecomposition(const geometry::ViewInformation3D& rViewInformation) const 355 { 356 if(getSdr3DObjectAttribute().getReducedLineGeometry()) 357 { 358 if(!mpLastRLGViewInformation || 359 (getBuffered3DDecomposition().hasElements() 360 && *mpLastRLGViewInformation != rViewInformation)) 361 { 362 // conditions of last local decomposition with reduced lines have changed. Remember 363 // new one and clear current decompositiopn 364 ::osl::Mutex m_mutex; 365 SdrLathePrimitive3D* pThat = const_cast< SdrLathePrimitive3D* >(this); 366 pThat->setBuffered3DDecomposition(Primitive3DSequence()); 367 delete pThat->mpLastRLGViewInformation; 368 pThat->mpLastRLGViewInformation = new geometry::ViewInformation3D(rViewInformation); 369 } 370 } 371 372 // no test for buffering needed, call parent 373 return SdrPrimitive3D::get3DDecomposition(rViewInformation); 374 } 375 376 // provide unique ID 377 ImplPrimitrive3DIDBlock(SdrLathePrimitive3D, PRIMITIVE3D_ID_SDRLATHEPRIMITIVE3D) 378 379 } // end of namespace primitive3d 380 } // end of namespace drawinglayer 381 382 ////////////////////////////////////////////////////////////////////////////// 383 // eof 384