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