1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <svx/helperhittest3d.hxx>
22 #include <basegfx/point/b2dpoint.hxx>
23 #include <svx/svdpage.hxx>
24 #include <svx/scene3d.hxx>
25 #include <svx/svditer.hxx>
26 #include <drawinglayer/processor3d/cutfindprocessor3d.hxx>
27 #include <svx/sdr/contact/viewcontactofe3d.hxx>
28 #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
29 #include <com/sun/star/uno/Sequence.h>
31 //////////////////////////////////////////////////////////////////////////////
33 using namespace com::sun::star
;
35 //////////////////////////////////////////////////////////////////////////////
37 class ImplPairDephAndObject
40 const E3dCompoundObject
* mpObject
;
44 ImplPairDephAndObject(const E3dCompoundObject
* pObject
, double fDepth
)
50 bool operator<(const ImplPairDephAndObject
& rComp
) const
52 return (mfDepth
< rComp
.mfDepth
);
56 const E3dCompoundObject
* getObject() const { return mpObject
; }
57 double getDepth() const { return mfDepth
; }
60 //////////////////////////////////////////////////////////////////////////////
62 void getAllHit3DObjectWithRelativePoint(
63 const basegfx::B3DPoint
& rFront
,
64 const basegfx::B3DPoint
& rBack
,
65 const E3dCompoundObject
& rObject
,
66 const drawinglayer::geometry::ViewInformation3D
& rObjectViewInformation3D
,
67 ::std::vector
< basegfx::B3DPoint
>& o_rResult
,
72 if(!rFront
.equal(rBack
))
74 // rObject is a E3dCompoundObject, so it cannot be a scene (which is a E3dObject)
75 const sdr::contact::ViewContactOfE3d
& rVCObject
= static_cast< sdr::contact::ViewContactOfE3d
& >(rObject
.GetViewContact());
76 const drawinglayer::primitive3d::Primitive3DSequence
aPrimitives(rVCObject
.getViewIndependentPrimitive3DSequence());
78 if(aPrimitives
.hasElements())
80 // make BoundVolume empty and overlapping test for speedup
81 const basegfx::B3DRange
aObjectRange(drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(aPrimitives
, rObjectViewInformation3D
));
83 if(!aObjectRange
.isEmpty())
85 const basegfx::B3DRange
aFrontBackRange(rFront
, rBack
);
87 if(aObjectRange
.overlaps(aFrontBackRange
))
89 // bound volumes hit, geometric cut tests needed
90 drawinglayer::processor3d::CutFindProcessor
aCutFindProcessor(rObjectViewInformation3D
, rFront
, rBack
, bAnyHit
);
91 aCutFindProcessor
.process(aPrimitives
);
92 o_rResult
= aCutFindProcessor
.getCutPoints();
99 //////////////////////////////////////////////////////////////////////////////
101 E3dScene
* fillViewInformation3DForCompoundObject(drawinglayer::geometry::ViewInformation3D
& o_rViewInformation3D
, const E3dCompoundObject
& rCandidate
)
103 // Search for root scene (outmost scene) of the 3d object since e.g. in chart, multiple scenes may
104 // be placed between object and outmost scene. On that search, remember the in-between scene's
105 // transformation for the correct complete ObjectTransformation. For historical reasons, the
106 // root scene's own object transformation is part of the scene's ViewTransformation, o do not
107 // add it. For more details, see ViewContactOfE3dScene::createViewInformation3D.
108 E3dScene
* pParentScene
= dynamic_cast< E3dScene
* >(rCandidate
.GetParentObj());
109 E3dScene
* pRootScene
= 0;
110 basegfx::B3DHomMatrix aInBetweenSceneMatrix
;
114 E3dScene
* pParentParentScene
= dynamic_cast< E3dScene
* >(pParentScene
->GetParentObj());
116 if(pParentParentScene
)
118 // pParentScene is a in-between scene
119 aInBetweenSceneMatrix
= pParentScene
->GetTransform() * aInBetweenSceneMatrix
;
123 // pParentScene is the root scene
124 pRootScene
= pParentScene
;
127 pParentScene
= pParentParentScene
;
132 const sdr::contact::ViewContactOfE3dScene
& rVCScene
= static_cast< sdr::contact::ViewContactOfE3dScene
& >(pRootScene
->GetViewContact());
134 if(aInBetweenSceneMatrix
.isIdentity())
136 o_rViewInformation3D
= rVCScene
.getViewInformation3D();
140 // build new ViewInformation containing all transforms for the candidate
141 const drawinglayer::geometry::ViewInformation3D
aViewInfo3D(rVCScene
.getViewInformation3D());
143 o_rViewInformation3D
= drawinglayer::geometry::ViewInformation3D(
144 aViewInfo3D
.getObjectTransformation() * aInBetweenSceneMatrix
,
145 aViewInfo3D
.getOrientation(),
146 aViewInfo3D
.getProjection(),
147 aViewInfo3D
.getDeviceToView(),
148 aViewInfo3D
.getViewTime(),
149 aViewInfo3D
.getExtendedInformationSequence());
154 const uno::Sequence
< beans::PropertyValue
> aEmptyParameters
;
155 o_rViewInformation3D
= drawinglayer::geometry::ViewInformation3D(aEmptyParameters
);
161 //////////////////////////////////////////////////////////////////////////////
163 SVX_DLLPUBLIC
void getAllHit3DObjectsSortedFrontToBack(
164 const basegfx::B2DPoint
& rPoint
,
165 const E3dScene
& rScene
,
166 ::std::vector
< const E3dCompoundObject
* >& o_rResult
)
169 SdrObjList
* pList
= rScene
.GetSubList();
171 if(pList
&& pList
->GetObjCount())
173 // prepare relative HitPoint. To do so, get the VC of the 3DScene and from there
174 // the Scene's 2D transformation. Multiplying with the inverse transformation
175 // will create a point relative to the 3D scene as unit-2d-object
176 const sdr::contact::ViewContactOfE3dScene
& rVCScene
= static_cast< sdr::contact::ViewContactOfE3dScene
& >(rScene
.GetViewContact());
177 basegfx::B2DHomMatrix
aInverseSceneTransform(rVCScene
.getObjectTransformation());
178 aInverseSceneTransform
.invert();
179 const basegfx::B2DPoint
aRelativePoint(aInverseSceneTransform
* rPoint
);
181 // check if test point is inside scene's area at all
182 if(aRelativePoint
.getX() >= 0.0 && aRelativePoint
.getX() <= 1.0 && aRelativePoint
.getY() >= 0.0 && aRelativePoint
.getY() <= 1.0)
184 SdrObjListIter
aIterator(*pList
, IM_DEEPNOGROUPS
);
185 ::std::vector
< ImplPairDephAndObject
> aDepthAndObjectResults
;
186 const uno::Sequence
< beans::PropertyValue
> aEmptyParameters
;
187 drawinglayer::geometry::ViewInformation3D
aViewInfo3D(aEmptyParameters
);
189 while(aIterator
.IsMore())
191 const E3dCompoundObject
* pCandidate
= dynamic_cast< const E3dCompoundObject
* >(aIterator
.Next());
195 fillViewInformation3DForCompoundObject(aViewInfo3D
, *pCandidate
);
197 // create HitPoint Front and Back, transform to object coordinates
198 basegfx::B3DHomMatrix
aViewToObject(aViewInfo3D
.getObjectToView());
199 aViewToObject
.invert();
200 const basegfx::B3DPoint
aFront(aViewToObject
* basegfx::B3DPoint(aRelativePoint
.getX(), aRelativePoint
.getY(), 0.0));
201 const basegfx::B3DPoint
aBack(aViewToObject
* basegfx::B3DPoint(aRelativePoint
.getX(), aRelativePoint
.getY(), 1.0));
203 if(!aFront
.equal(aBack
))
205 // get all hit points with object
206 ::std::vector
< basegfx::B3DPoint
> aHitsWithObject
;
207 getAllHit3DObjectWithRelativePoint(aFront
, aBack
, *pCandidate
, aViewInfo3D
, aHitsWithObject
, false);
209 for(sal_uInt32
a(0); a
< aHitsWithObject
.size(); a
++)
211 const basegfx::B3DPoint
aPointInViewCoordinates(aViewInfo3D
.getObjectToView() * aHitsWithObject
[a
]);
212 aDepthAndObjectResults
.push_back(ImplPairDephAndObject(pCandidate
, aPointInViewCoordinates
.getZ()));
219 const sal_uInt32
nCount(aDepthAndObjectResults
.size());
223 // sort aDepthAndObjectResults by depth
224 ::std::sort(aDepthAndObjectResults
.begin(), aDepthAndObjectResults
.end());
226 // copy SdrObject pointers to return result set
227 ::std::vector
< ImplPairDephAndObject
>::iterator
aIterator2(aDepthAndObjectResults
.begin());
229 for(;aIterator2
!= aDepthAndObjectResults
.end(); ++aIterator2
)
231 o_rResult
.push_back(aIterator2
->getObject());
238 //////////////////////////////////////////////////////////////////////////////
240 bool checkHitSingle3DObject(
241 const basegfx::B2DPoint
& rPoint
,
242 const E3dCompoundObject
& rCandidate
)
244 const uno::Sequence
< beans::PropertyValue
> aEmptyParameters
;
245 drawinglayer::geometry::ViewInformation3D
aViewInfo3D(aEmptyParameters
);
246 E3dScene
* pRootScene
= fillViewInformation3DForCompoundObject(aViewInfo3D
, rCandidate
);
250 // prepare relative HitPoint. To do so, get the VC of the 3DScene and from there
251 // the Scene's 2D transformation. Multiplying with the inverse transformation
252 // will create a point relative to the 3D scene as unit-2d-object
253 const sdr::contact::ViewContactOfE3dScene
& rVCScene
= static_cast< sdr::contact::ViewContactOfE3dScene
& >(pRootScene
->GetViewContact());
254 basegfx::B2DHomMatrix
aInverseSceneTransform(rVCScene
.getObjectTransformation());
255 aInverseSceneTransform
.invert();
256 const basegfx::B2DPoint
aRelativePoint(aInverseSceneTransform
* rPoint
);
258 // check if test point is inside scene's area at all
259 if(aRelativePoint
.getX() >= 0.0 && aRelativePoint
.getX() <= 1.0 && aRelativePoint
.getY() >= 0.0 && aRelativePoint
.getY() <= 1.0)
261 // create HitPoint Front and Back, transform to object coordinates
262 basegfx::B3DHomMatrix
aViewToObject(aViewInfo3D
.getObjectToView());
263 aViewToObject
.invert();
264 const basegfx::B3DPoint
aFront(aViewToObject
* basegfx::B3DPoint(aRelativePoint
.getX(), aRelativePoint
.getY(), 0.0));
265 const basegfx::B3DPoint
aBack(aViewToObject
* basegfx::B3DPoint(aRelativePoint
.getX(), aRelativePoint
.getY(), 1.0));
267 if(!aFront
.equal(aBack
))
269 // get all hit points with object
270 ::std::vector
< basegfx::B3DPoint
> aHitsWithObject
;
271 getAllHit3DObjectWithRelativePoint(aFront
, aBack
, rCandidate
, aViewInfo3D
, aHitsWithObject
, true);
273 if(!aHitsWithObject
.empty())
284 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */