xref: /AOO41X/main/svx/source/sdr/contact/viewcontactofe3dscene.cxx (revision f6e50924346d0b8c0b07c91832a97665dd718b0c)
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