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 27 #include <svx/helperhittest3d.hxx> 28 #include <basegfx/point/b2dpoint.hxx> 29 #include <svx/svdpage.hxx> 30 #include <svx/scene3d.hxx> 31 #include <svx/svditer.hxx> 32 #include <drawinglayer/processor3d/cutfindprocessor3d.hxx> 33 #include <svx/sdr/contact/viewcontactofe3d.hxx> 34 #include <svx/sdr/contact/viewcontactofe3dscene.hxx> 35 #include <com/sun/star/uno/Sequence.h> 36 37 ////////////////////////////////////////////////////////////////////////////// 38 39 using namespace com::sun::star; 40 41 ////////////////////////////////////////////////////////////////////////////// 42 43 class ImplPairDephAndObject 44 { 45 private: 46 const E3dCompoundObject* mpObject; 47 double mfDepth; 48 49 public: 50 ImplPairDephAndObject(const E3dCompoundObject* pObject, double fDepth) 51 : mpObject(pObject), 52 mfDepth(fDepth) 53 {} 54 55 // for ::std::sort 56 bool operator<(const ImplPairDephAndObject& rComp) const 57 { 58 return (mfDepth < rComp.mfDepth); 59 } 60 61 // data read access 62 const E3dCompoundObject* getObject() const { return mpObject; } 63 double getDepth() const { return mfDepth; } 64 }; 65 66 ////////////////////////////////////////////////////////////////////////////// 67 68 void getAllHit3DObjectWithRelativePoint( 69 const basegfx::B3DPoint& rFront, 70 const basegfx::B3DPoint& rBack, 71 const E3dCompoundObject& rObject, 72 const drawinglayer::geometry::ViewInformation3D& rObjectViewInformation3D, 73 ::std::vector< basegfx::B3DPoint >& o_rResult, 74 bool bAnyHit) 75 { 76 o_rResult.clear(); 77 78 if(!rFront.equal(rBack)) 79 { 80 // rObject is a E3dCompoundObject, so it cannot be a scene (which is a E3dObject) 81 const sdr::contact::ViewContactOfE3d& rVCObject = static_cast< sdr::contact::ViewContactOfE3d& >(rObject.GetViewContact()); 82 const drawinglayer::primitive3d::Primitive3DSequence aPrimitives(rVCObject.getViewIndependentPrimitive3DSequence()); 83 84 if(aPrimitives.hasElements()) 85 { 86 // make BoundVolume empty and overlapping test for speedup 87 const basegfx::B3DRange aObjectRange(drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(aPrimitives, rObjectViewInformation3D)); 88 89 if(!aObjectRange.isEmpty()) 90 { 91 const basegfx::B3DRange aFrontBackRange(rFront, rBack); 92 93 if(aObjectRange.overlaps(aFrontBackRange)) 94 { 95 // bound volumes hit, geometric cut tests needed 96 drawinglayer::processor3d::CutFindProcessor aCutFindProcessor(rObjectViewInformation3D, rFront, rBack, bAnyHit); 97 aCutFindProcessor.process(aPrimitives); 98 o_rResult = aCutFindProcessor.getCutPoints(); 99 } 100 } 101 } 102 } 103 } 104 105 ////////////////////////////////////////////////////////////////////////////// 106 107 E3dScene* fillViewInformation3DForCompoundObject(drawinglayer::geometry::ViewInformation3D& o_rViewInformation3D, const E3dCompoundObject& rCandidate) 108 { 109 // Search for root scene (outmost scene) of the 3d object since e.g. in chart, multiple scenes may 110 // be placed between object and outmost scene. On that search, remember the in-between scene's 111 // transformation for the correct complete ObjectTransformation. For historical reasons, the 112 // root scene's own object transformation is part of the scene's ViewTransformation, o do not 113 // add it. For more details, see ViewContactOfE3dScene::createViewInformation3D. 114 E3dScene* pParentScene = dynamic_cast< E3dScene* >(rCandidate.GetParentObj()); 115 E3dScene* pRootScene = 0; 116 basegfx::B3DHomMatrix aInBetweenSceneMatrix; 117 118 while(pParentScene) 119 { 120 E3dScene* pParentParentScene = dynamic_cast< E3dScene* >(pParentScene->GetParentObj()); 121 122 if(pParentParentScene) 123 { 124 // pParentScene is a in-between scene 125 aInBetweenSceneMatrix = pParentScene->GetTransform() * aInBetweenSceneMatrix; 126 } 127 else 128 { 129 // pParentScene is the root scene 130 pRootScene = pParentScene; 131 } 132 133 pParentScene = pParentParentScene; 134 } 135 136 if(pRootScene) 137 { 138 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact()); 139 140 if(aInBetweenSceneMatrix.isIdentity()) 141 { 142 o_rViewInformation3D = rVCScene.getViewInformation3D(); 143 } 144 else 145 { 146 // build new ViewInformation containing all transforms for the candidate 147 const drawinglayer::geometry::ViewInformation3D aViewInfo3D(rVCScene.getViewInformation3D()); 148 149 o_rViewInformation3D = drawinglayer::geometry::ViewInformation3D( 150 aViewInfo3D.getObjectTransformation() * aInBetweenSceneMatrix, 151 aViewInfo3D.getOrientation(), 152 aViewInfo3D.getProjection(), 153 aViewInfo3D.getDeviceToView(), 154 aViewInfo3D.getViewTime(), 155 aViewInfo3D.getExtendedInformationSequence()); 156 } 157 } 158 else 159 { 160 const uno::Sequence< beans::PropertyValue > aEmptyParameters; 161 o_rViewInformation3D = drawinglayer::geometry::ViewInformation3D(aEmptyParameters); 162 } 163 164 return pRootScene; 165 } 166 167 ////////////////////////////////////////////////////////////////////////////// 168 169 SVX_DLLPUBLIC void getAllHit3DObjectsSortedFrontToBack( 170 const basegfx::B2DPoint& rPoint, 171 const E3dScene& rScene, 172 ::std::vector< const E3dCompoundObject* >& o_rResult) 173 { 174 o_rResult.clear(); 175 SdrObjList* pList = rScene.GetSubList(); 176 177 if(pList && pList->GetObjCount()) 178 { 179 // prepare relative HitPoint. To do so, get the VC of the 3DScene and from there 180 // the Scene's 2D transformation. Multiplying with the inverse transformation 181 // will create a point relative to the 3D scene as unit-2d-object 182 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(rScene.GetViewContact()); 183 basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation()); 184 aInverseSceneTransform.invert(); 185 const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rPoint); 186 187 // check if test point is inside scene's area at all 188 if(aRelativePoint.getX() >= 0.0 && aRelativePoint.getX() <= 1.0 && aRelativePoint.getY() >= 0.0 && aRelativePoint.getY() <= 1.0) 189 { 190 SdrObjListIter aIterator(*pList, IM_DEEPNOGROUPS); 191 ::std::vector< ImplPairDephAndObject > aDepthAndObjectResults; 192 const uno::Sequence< beans::PropertyValue > aEmptyParameters; 193 drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters); 194 195 while(aIterator.IsMore()) 196 { 197 const E3dCompoundObject* pCandidate = dynamic_cast< const E3dCompoundObject* >(aIterator.Next()); 198 199 if(pCandidate) 200 { 201 fillViewInformation3DForCompoundObject(aViewInfo3D, *pCandidate); 202 203 // create HitPoint Front and Back, transform to object coordinates 204 basegfx::B3DHomMatrix aViewToObject(aViewInfo3D.getObjectToView()); 205 aViewToObject.invert(); 206 const basegfx::B3DPoint aFront(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 0.0)); 207 const basegfx::B3DPoint aBack(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 1.0)); 208 209 if(!aFront.equal(aBack)) 210 { 211 // get all hit points with object 212 ::std::vector< basegfx::B3DPoint > aHitsWithObject; 213 getAllHit3DObjectWithRelativePoint(aFront, aBack, *pCandidate, aViewInfo3D, aHitsWithObject, false); 214 215 for(sal_uInt32 a(0); a < aHitsWithObject.size(); a++) 216 { 217 const basegfx::B3DPoint aPointInViewCoordinates(aViewInfo3D.getObjectToView() * aHitsWithObject[a]); 218 aDepthAndObjectResults.push_back(ImplPairDephAndObject(pCandidate, aPointInViewCoordinates.getZ())); 219 } 220 } 221 } 222 } 223 224 // fill nRetval 225 const sal_uInt32 nCount(aDepthAndObjectResults.size()); 226 227 if(nCount) 228 { 229 // sort aDepthAndObjectResults by depth 230 ::std::sort(aDepthAndObjectResults.begin(), aDepthAndObjectResults.end()); 231 232 // copy SdrObject pointers to return result set 233 ::std::vector< ImplPairDephAndObject >::iterator aIterator2(aDepthAndObjectResults.begin()); 234 235 for(;aIterator2 != aDepthAndObjectResults.end(); aIterator2++) 236 { 237 o_rResult.push_back(aIterator2->getObject()); 238 } 239 } 240 } 241 } 242 } 243 244 ////////////////////////////////////////////////////////////////////////////// 245 246 bool checkHitSingle3DObject( 247 const basegfx::B2DPoint& rPoint, 248 const E3dCompoundObject& rCandidate) 249 { 250 const uno::Sequence< beans::PropertyValue > aEmptyParameters; 251 drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters); 252 E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, rCandidate); 253 254 if(pRootScene) 255 { 256 // prepare relative HitPoint. To do so, get the VC of the 3DScene and from there 257 // the Scene's 2D transformation. Multiplying with the inverse transformation 258 // will create a point relative to the 3D scene as unit-2d-object 259 const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact()); 260 basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation()); 261 aInverseSceneTransform.invert(); 262 const basegfx::B2DPoint aRelativePoint(aInverseSceneTransform * rPoint); 263 264 // check if test point is inside scene's area at all 265 if(aRelativePoint.getX() >= 0.0 && aRelativePoint.getX() <= 1.0 && aRelativePoint.getY() >= 0.0 && aRelativePoint.getY() <= 1.0) 266 { 267 // create HitPoint Front and Back, transform to object coordinates 268 basegfx::B3DHomMatrix aViewToObject(aViewInfo3D.getObjectToView()); 269 aViewToObject.invert(); 270 const basegfx::B3DPoint aFront(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 0.0)); 271 const basegfx::B3DPoint aBack(aViewToObject * basegfx::B3DPoint(aRelativePoint.getX(), aRelativePoint.getY(), 1.0)); 272 273 if(!aFront.equal(aBack)) 274 { 275 // get all hit points with object 276 ::std::vector< basegfx::B3DPoint > aHitsWithObject; 277 getAllHit3DObjectWithRelativePoint(aFront, aBack, rCandidate, aViewInfo3D, aHitsWithObject, true); 278 279 if(aHitsWithObject.size()) 280 { 281 return true; 282 } 283 } 284 } 285 } 286 287 return false; 288 } 289 290 ////////////////////////////////////////////////////////////////////////////// 291 // eof 292