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_svx.hxx" 26 #include <svx/sdr/contact/viewcontactofe3dscene.hxx> 27 #include <svx/polysc3d.hxx> 28 #include <svx/sdr/contact/displayinfo.hxx> 29 #include <svx/sdr/contact/viewobjectcontact.hxx> 30 #include <basegfx/polygon/b2dpolygontools.hxx> 31 #include <basegfx/color/bcolor.hxx> 32 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx> 33 #include <svx/sdr/primitive2d/sdrattributecreator.hxx> 34 #include <svx/sdr/contact/viewobjectcontactofe3dscene.hxx> 35 #include <basegfx/matrix/b2dhommatrix.hxx> 36 #include <basegfx/range/b3drange.hxx> 37 #include <drawinglayer/primitive3d/baseprimitive3d.hxx> 38 #include <svx/sdr/contact/viewcontactofe3d.hxx> 39 #include <drawinglayer/primitive2d/sceneprimitive2d.hxx> 40 #include <drawinglayer/primitive3d/transformprimitive3d.hxx> 41 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx> 42 43 ////////////////////////////////////////////////////////////////////////////// 44 45 using namespace com::sun::star; 46 47 ////////////////////////////////////////////////////////////////////////////// 48 49 namespace 50 { 51 // pActiveVC is only true if ghosted is still activated and maybe needs to be switched off in this path createSubPrimitive3DVector(const sdr::contact::ViewContact & rCandidate,drawinglayer::primitive3d::Primitive3DSequence & o_rAllTarget,drawinglayer::primitive3d::Primitive3DSequence * o_pVisibleTarget,const SetOfByte * pVisibleLayerSet,const bool bTestSelectedVisibility)52 void createSubPrimitive3DVector( 53 const sdr::contact::ViewContact& rCandidate, 54 drawinglayer::primitive3d::Primitive3DSequence& o_rAllTarget, 55 drawinglayer::primitive3d::Primitive3DSequence* o_pVisibleTarget, 56 const SetOfByte* pVisibleLayerSet, 57 const bool bTestSelectedVisibility) 58 { 59 const sdr::contact::ViewContactOfE3dScene* pViewContactOfE3dScene = dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(&rCandidate); 60 61 if(pViewContactOfE3dScene) 62 { 63 const sal_uInt32 nChildrenCount(rCandidate.GetObjectCount()); 64 65 if(nChildrenCount) 66 { 67 // provide new collection sequences 68 drawinglayer::primitive3d::Primitive3DSequence aNewAllTarget; 69 drawinglayer::primitive3d::Primitive3DSequence aNewVisibleTarget; 70 71 // add children recursively 72 for(sal_uInt32 a(0L); a < nChildrenCount; a++) 73 { 74 createSubPrimitive3DVector( 75 rCandidate.GetViewContact(a), 76 aNewAllTarget, 77 o_pVisibleTarget ? &aNewVisibleTarget : 0, 78 pVisibleLayerSet, 79 bTestSelectedVisibility); 80 } 81 82 // create transform primitive for the created content combining content and transformtion 83 const drawinglayer::primitive3d::Primitive3DReference xReference(new drawinglayer::primitive3d::TransformPrimitive3D( 84 pViewContactOfE3dScene->GetE3dScene().GetTransform(), 85 aNewAllTarget)); 86 87 // add created content to all target 88 drawinglayer::primitive3d::appendPrimitive3DReferenceToPrimitive3DSequence(o_rAllTarget, xReference); 89 90 // add created content to visibiel target if exists 91 if(o_pVisibleTarget) 92 { 93 drawinglayer::primitive3d::appendPrimitive3DReferenceToPrimitive3DSequence(*o_pVisibleTarget, xReference); 94 } 95 } 96 } 97 else 98 { 99 // access view independent representation of rCandidate 100 const sdr::contact::ViewContactOfE3d* pViewContactOfE3d = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&rCandidate); 101 102 if(pViewContactOfE3d) 103 { 104 drawinglayer::primitive3d::Primitive3DSequence xPrimitive3DSeq(pViewContactOfE3d->getViewIndependentPrimitive3DSequence()); 105 106 if(xPrimitive3DSeq.hasElements()) 107 { 108 // add to all target vector 109 drawinglayer::primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(o_rAllTarget, xPrimitive3DSeq); 110 111 if(o_pVisibleTarget) 112 { 113 // test visibility. Primitive is visible when both tests are true (AND) 114 bool bVisible(true); 115 116 if(pVisibleLayerSet) 117 { 118 // test layer visibility 119 const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject(); 120 const SdrLayerID aLayerID(rE3dObject.GetLayer()); 121 122 bVisible = pVisibleLayerSet->IsSet(aLayerID); 123 } 124 125 if(bVisible && bTestSelectedVisibility) 126 { 127 // test selected visibility (see 3D View's DrawMarkedObj implementation) 128 const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject(); 129 130 bVisible = rE3dObject.GetSelected(); 131 } 132 133 if(bVisible && o_pVisibleTarget) 134 { 135 // add to visible target vector 136 drawinglayer::primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(*o_pVisibleTarget, xPrimitive3DSeq); 137 } 138 } 139 } 140 } 141 } 142 } 143 } // end of anonymous namespace 144 145 ////////////////////////////////////////////////////////////////////////////// 146 147 namespace sdr 148 { 149 namespace contact 150 { 151 // Create a Object-Specific ViewObjectContact, set ViewContact and 152 // ObjectContact. Always needs to return something. CreateObjectSpecificViewObjectContact(ObjectContact & rObjectContact)153 ViewObjectContact& ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) 154 { 155 ViewObjectContact* pRetval = new ViewObjectContactOfE3dScene(rObjectContact, *this); 156 DBG_ASSERT(pRetval, "ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact() failed (!)"); 157 158 return *pRetval; 159 } 160 ViewContactOfE3dScene(E3dScene & rScene)161 ViewContactOfE3dScene::ViewContactOfE3dScene(E3dScene& rScene) 162 : ViewContactOfSdrObj(rScene), 163 maViewInformation3D(), 164 maObjectTransformation(), 165 maSdrSceneAttribute(), 166 maSdrLightingAttribute() 167 { 168 } 169 createViewInformation3D(const basegfx::B3DRange & rContentRange)170 void ViewContactOfE3dScene::createViewInformation3D(const basegfx::B3DRange& rContentRange) 171 { 172 basegfx::B3DHomMatrix aTransformation; 173 basegfx::B3DHomMatrix aOrientation; 174 basegfx::B3DHomMatrix aProjection; 175 basegfx::B3DHomMatrix aDeviceToView; 176 177 // create transformation (scene as group's transformation) 178 // For historical reasons, the outmost scene's transformation is handles as part of the 179 // view transformation. This means that the BoundRect of the contained 3D Objects is 180 // without that transformation and makes it necessary to NOT add the first scene to the 181 // Primitive3DSequence of contained objects. 182 { 183 aTransformation = GetE3dScene().GetTransform(); 184 } 185 186 // create orientation (world to camera coordinate system) 187 { 188 // calculate orientation from VRP, VPN and VUV 189 const B3dCamera& rSceneCamera = GetE3dScene().GetCameraSet(); 190 const basegfx::B3DPoint aVRP(rSceneCamera.GetVRP()); 191 const basegfx::B3DVector aVPN(rSceneCamera.GetVRP()); 192 const basegfx::B3DVector aVUV(rSceneCamera.GetVUV()); 193 194 aOrientation.orientation(aVRP, aVPN, aVUV); 195 } 196 197 // create projection (camera coordinate system to relative 2d where X,Y and Z are [0.0 .. 1.0]) 198 { 199 const basegfx::B3DHomMatrix aWorldToCamera(aOrientation * aTransformation); 200 basegfx::B3DRange aCameraRange(rContentRange); 201 aCameraRange.transform(aWorldToCamera); 202 203 // remember Z-Values, but change orientation 204 const double fMinZ(-aCameraRange.getMaxZ()); 205 const double fMaxZ(-aCameraRange.getMinZ()); 206 207 // construct temorary matrix from world to device. Use unit values here to measure expansion 208 basegfx::B3DHomMatrix aWorldToDevice(aWorldToCamera); 209 const drawinglayer::attribute::SdrSceneAttribute& rSdrSceneAttribute = getSdrSceneAttribute(); 210 211 if(::com::sun::star::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode()) 212 { 213 aWorldToDevice.frustum(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ); 214 } 215 else 216 { 217 aWorldToDevice.ortho(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ); 218 } 219 220 // create B3DRange in device. This will create the real used ranges 221 // in camera space. Do not use the Z-Values, though. 222 basegfx::B3DRange aDeviceRange(rContentRange); 223 aDeviceRange.transform(aWorldToDevice); 224 225 // set projection 226 if(::com::sun::star::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode()) 227 { 228 aProjection.frustum( 229 aDeviceRange.getMinX(), aDeviceRange.getMaxX(), 230 aDeviceRange.getMinY(), aDeviceRange.getMaxY(), 231 fMinZ, fMaxZ); 232 } 233 else 234 { 235 aProjection.ortho( 236 aDeviceRange.getMinX(), aDeviceRange.getMaxX(), 237 aDeviceRange.getMinY(), aDeviceRange.getMaxY(), 238 fMinZ, fMaxZ); 239 } 240 } 241 242 // create device to view transform 243 { 244 // create standard deviceToView projection for geometry 245 // input is [-1.0 .. 1.0] in X,Y and Z. bring to [0.0 .. 1.0]. Also 246 // necessary to flip Y due to screen orientation 247 // Z is not needed, but will also be brought to [0.0 .. 1.0] 248 aDeviceToView.scale(0.5, -0.5, 0.5); 249 aDeviceToView.translate(0.5, 0.5, 0.5); 250 } 251 252 const uno::Sequence< beans::PropertyValue > aEmptyProperties; 253 maViewInformation3D = drawinglayer::geometry::ViewInformation3D( 254 aTransformation, aOrientation, aProjection, 255 aDeviceToView, 0.0, aEmptyProperties); 256 } 257 createObjectTransformation()258 void ViewContactOfE3dScene::createObjectTransformation() 259 { 260 // create 2d Object Transformation from relative point in 2d scene to world 261 const Rectangle& rRectangle = GetE3dScene().GetSnapRect(); 262 263 maObjectTransformation.set(0, 0, rRectangle.getWidth()); 264 maObjectTransformation.set(1, 1, rRectangle.getHeight()); 265 maObjectTransformation.set(0, 2, rRectangle.Left()); 266 maObjectTransformation.set(1, 2, rRectangle.Top()); 267 } 268 createSdrSceneAttribute()269 void ViewContactOfE3dScene::createSdrSceneAttribute() 270 { 271 const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet(); 272 maSdrSceneAttribute = drawinglayer::primitive2d::createNewSdrSceneAttribute(rItemSet); 273 } 274 createSdrLightingAttribute()275 void ViewContactOfE3dScene::createSdrLightingAttribute() 276 { 277 const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet(); 278 maSdrLightingAttribute = drawinglayer::primitive2d::createNewSdrLightingAttribute(rItemSet); 279 } 280 createScenePrimitive2DSequence(const SetOfByte * pLayerVisibility) const281 drawinglayer::primitive2d::Primitive2DSequence ViewContactOfE3dScene::createScenePrimitive2DSequence( 282 const SetOfByte* pLayerVisibility) const 283 { 284 drawinglayer::primitive2d::Primitive2DSequence xRetval; 285 const sal_uInt32 nChildrenCount(GetObjectCount()); 286 287 if(nChildrenCount) 288 { 289 // create 3d scene primitive with visible content tested against rLayerVisibility 290 drawinglayer::primitive3d::Primitive3DSequence aAllSequence; 291 drawinglayer::primitive3d::Primitive3DSequence aVisibleSequence; 292 const bool bTestLayerVisibility(0 != pLayerVisibility); 293 const bool bTestSelectedVisibility(GetE3dScene().GetDrawOnlySelected()); 294 const bool bTestVisibility(bTestLayerVisibility || bTestSelectedVisibility); 295 296 // add children recursively. Do NOT start with (*this), this would create 297 // a 3D transformPrimitive for the start scene. While this is theoretically not 298 // a bad thing, for historical reasons the transformation of the outmost scene 299 // is seen as part of the ViewTransformation (see text in createViewInformation3D) 300 for(sal_uInt32 a(0L); a < nChildrenCount; a++) 301 { 302 createSubPrimitive3DVector( 303 GetViewContact(a), 304 aAllSequence, 305 bTestLayerVisibility ? &aVisibleSequence : 0, 306 bTestLayerVisibility ? pLayerVisibility : 0, 307 bTestSelectedVisibility); 308 } 309 310 const sal_uInt32 nAllSize(aAllSequence.hasElements() ? aAllSequence.getLength() : 0); 311 const sal_uInt32 nVisibleSize(aVisibleSequence.hasElements() ? aVisibleSequence.getLength() : 0); 312 313 if((bTestVisibility && nVisibleSize) || nAllSize) 314 { 315 // for getting the 3D range using getB3DRangeFromPrimitive3DSequence a ViewInformation3D 316 // needs to be given for evtl. decompositions. At the same time createViewInformation3D 317 // currently is based on creating the target-ViewInformation3D using a given range. To 318 // get the true range, use a neutral ViewInformation3D here. This leaves all matrices 319 // on identity and the time on 0.0. 320 const uno::Sequence< beans::PropertyValue > aEmptyProperties; 321 const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties); 322 const basegfx::B3DRange aContentRange( 323 drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(aAllSequence, aNeutralViewInformation3D)); 324 325 // create 2d primitive 3dscene with generated sub-list from collector 326 const drawinglayer::primitive2d::Primitive2DReference xReference( 327 new drawinglayer::primitive2d::ScenePrimitive2D( 328 bTestVisibility ? aVisibleSequence : aAllSequence, 329 getSdrSceneAttribute(), 330 getSdrLightingAttribute(), 331 getObjectTransformation(), 332 getViewInformation3D(aContentRange))); 333 334 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); 335 } 336 } 337 338 // always append an invisible outline for the cases where no visible content exists 339 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval, 340 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D( 341 false, getObjectTransformation())); 342 343 return xRetval; 344 } 345 createViewIndependentPrimitive2DSequence() const346 drawinglayer::primitive2d::Primitive2DSequence ViewContactOfE3dScene::createViewIndependentPrimitive2DSequence() const 347 { 348 drawinglayer::primitive2d::Primitive2DSequence xRetval; 349 350 if(GetObjectCount()) 351 { 352 // create a default ScenePrimitive2D (without visibility test of members) 353 xRetval = createScenePrimitive2DSequence(0); 354 } 355 356 return xRetval; 357 } 358 ActionChanged()359 void ViewContactOfE3dScene::ActionChanged() 360 { 361 // call parent 362 ViewContactOfSdrObj::ActionChanged(); 363 364 // mark locally cached values as invalid 365 maViewInformation3D = drawinglayer::geometry::ViewInformation3D(); 366 maObjectTransformation.identity(); 367 maSdrSceneAttribute = drawinglayer::attribute::SdrSceneAttribute(); 368 maSdrLightingAttribute = drawinglayer::attribute::SdrLightingAttribute(); 369 } 370 getViewInformation3D() const371 const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D() const 372 { 373 if(maViewInformation3D.isDefault()) 374 { 375 // this version will create the content range on demand locally and thus is less 376 // performant than the other one. Since the information is buffered the planned 377 // behaviour is that the version with the given range is used initially. 378 basegfx::B3DRange aContentRange(getAllContentRange3D()); 379 380 if(aContentRange.isEmpty()) 381 { 382 // empty scene, no 3d action should be necessary. Prepare some 383 // fallback size 384 OSL_ENSURE(false, "No need to get ViewInformation3D from an empty scene (!)"); 385 aContentRange.expand(basegfx::B3DPoint(-100.0, -100.0, -100.0)); 386 aContentRange.expand(basegfx::B3DPoint( 100.0, 100.0, 100.0)); 387 } 388 389 const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(aContentRange); 390 } 391 392 return maViewInformation3D; 393 } 394 getViewInformation3D(const basegfx::B3DRange & rContentRange) const395 const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D(const basegfx::B3DRange& rContentRange) const 396 { 397 if(maViewInformation3D.isDefault()) 398 { 399 const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(rContentRange); 400 } 401 402 return maViewInformation3D; 403 } 404 getObjectTransformation() const405 const basegfx::B2DHomMatrix& ViewContactOfE3dScene::getObjectTransformation() const 406 { 407 if(maObjectTransformation.isIdentity()) 408 { 409 const_cast < ViewContactOfE3dScene* >(this)->createObjectTransformation(); 410 } 411 412 return maObjectTransformation; 413 } 414 getSdrSceneAttribute() const415 const drawinglayer::attribute::SdrSceneAttribute& ViewContactOfE3dScene::getSdrSceneAttribute() const 416 { 417 if(maSdrSceneAttribute.isDefault()) 418 { 419 const_cast < ViewContactOfE3dScene* >(this)->createSdrSceneAttribute(); 420 } 421 422 return maSdrSceneAttribute; 423 } 424 getSdrLightingAttribute() const425 const drawinglayer::attribute::SdrLightingAttribute& ViewContactOfE3dScene::getSdrLightingAttribute() const 426 { 427 if(maSdrLightingAttribute.isDefault()) 428 { 429 const_cast < ViewContactOfE3dScene* >(this)->createSdrLightingAttribute(); 430 } 431 432 return maSdrLightingAttribute; 433 } 434 getAllPrimitive3DSequence() const435 drawinglayer::primitive3d::Primitive3DSequence ViewContactOfE3dScene::getAllPrimitive3DSequence() const 436 { 437 drawinglayer::primitive3d::Primitive3DSequence aAllPrimitive3DSequence; 438 const sal_uInt32 nChildrenCount(GetObjectCount()); 439 440 // add children recursively. Do NOT start with (*this), this would create 441 // a 3D transformPrimitive for the start scene. While this is theoretically not 442 // a bad thing, for historical reasons the transformation of the outmost scene 443 // is seen as part of the ViewTransformation (see text in createViewInformation3D) 444 for(sal_uInt32 a(0L); a < nChildrenCount; a++) 445 { 446 createSubPrimitive3DVector(GetViewContact(a), aAllPrimitive3DSequence, 0, 0, false); 447 } 448 449 return aAllPrimitive3DSequence; 450 } 451 getAllContentRange3D() const452 basegfx::B3DRange ViewContactOfE3dScene::getAllContentRange3D() const 453 { 454 const drawinglayer::primitive3d::Primitive3DSequence xAllSequence(getAllPrimitive3DSequence()); 455 basegfx::B3DRange aAllContentRange3D; 456 457 if(xAllSequence.hasElements()) 458 { 459 // for getting the 3D range using getB3DRangeFromPrimitive3DSequence a ViewInformation3D 460 // needs to be given for evtl. decompositions. Use a neutral ViewInformation3D here. This 461 // leaves all matrices on identity and the time on 0.0. 462 const uno::Sequence< beans::PropertyValue > aEmptyProperties; 463 const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties); 464 465 aAllContentRange3D = drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(xAllSequence, aNeutralViewInformation3D); 466 } 467 468 return aAllContentRange3D; 469 } 470 } // end of namespace contact 471 } // end of namespace sdr 472 473 ////////////////////////////////////////////////////////////////////////////// 474 // eof 475