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:
ImplPairDephAndObject(const E3dCompoundObject * pObject,double fDepth)50 ImplPairDephAndObject(const E3dCompoundObject* pObject, double fDepth)
51 : mpObject(pObject),
52 mfDepth(fDepth)
53 {}
54
55 // for ::std::sort
operator <(const ImplPairDephAndObject & rComp) const56 bool operator<(const ImplPairDephAndObject& rComp) const
57 {
58 return (mfDepth < rComp.mfDepth);
59 }
60
61 // data read access
getObject() const62 const E3dCompoundObject* getObject() const { return mpObject; }
getDepth() const63 double getDepth() const { return mfDepth; }
64 };
65
66 //////////////////////////////////////////////////////////////////////////////
67
getAllHit3DObjectWithRelativePoint(const basegfx::B3DPoint & rFront,const basegfx::B3DPoint & rBack,const E3dCompoundObject & rObject,const drawinglayer::geometry::ViewInformation3D & rObjectViewInformation3D,::std::vector<basegfx::B3DPoint> & o_rResult,bool bAnyHit)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
fillViewInformation3DForCompoundObject(drawinglayer::geometry::ViewInformation3D & o_rViewInformation3D,const E3dCompoundObject & rCandidate)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
getAllHit3DObjectsSortedFrontToBack(const basegfx::B2DPoint & rPoint,const E3dScene & rScene,::std::vector<const E3dCompoundObject * > & o_rResult)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
checkHitSingle3DObject(const basegfx::B2DPoint & rPoint,const E3dCompoundObject & rCandidate)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