LibreOffice Module svx (master)  1
viewcontactofe3dscene.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
24 #include <basegfx/color/bcolor.hxx>
35 
36 using namespace com::sun::star;
37 
38 namespace {
39 
40 // pActiveVC is only true if ghosted is still activated and maybe needs to be switched off in this path
41 void createSubPrimitive3DVector(
42  const sdr::contact::ViewContact& rCandidate,
45  const SdrLayerIDSet* pVisibleSdrLayerIDSet,
46  const bool bTestSelectedVisibility)
47 {
48  const sdr::contact::ViewContactOfE3dScene* pViewContactOfE3dScene = dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(&rCandidate);
49 
50  if(pViewContactOfE3dScene)
51  {
52  const sal_uInt32 nChildrenCount(rCandidate.GetObjectCount());
53 
54  if(nChildrenCount)
55  {
56  // provide new collection sequences
59 
60  // add children recursively
61  for(sal_uInt32 a(0); a < nChildrenCount; a++)
62  {
63  createSubPrimitive3DVector(
64  rCandidate.GetViewContact(a),
65  aNewAllTarget,
66  o_pVisibleTarget ? &aNewVisibleTarget : nullptr,
67  pVisibleSdrLayerIDSet,
68  bTestSelectedVisibility);
69  }
70 
71  // create transform primitive for the created content combining content and transformtion
73  pViewContactOfE3dScene->GetE3dScene().GetTransform(),
74  aNewAllTarget));
75 
76  // add created content to all target
77  o_rAllTarget.push_back(xReference);
78 
79  // add created content to visible target if exists
80  if(o_pVisibleTarget)
81  {
82  o_pVisibleTarget->push_back(xReference);
83  }
84  }
85  }
86  else
87  {
88  // access view independent representation of rCandidate
89  const sdr::contact::ViewContactOfE3d* pViewContactOfE3d = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&rCandidate);
90 
91  if(pViewContactOfE3d)
92  {
94 
95  if(!xPrimitive3DSeq.empty())
96  {
97  // add to all target vector
98  o_rAllTarget.append(xPrimitive3DSeq);
99 
100  if(o_pVisibleTarget)
101  {
102  // test visibility. Primitive is visible when both tests are true (AND)
103  bool bVisible(true);
104 
105  if(pVisibleSdrLayerIDSet)
106  {
107  // test layer visibility
108  const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
109  const SdrLayerID aLayerID(rE3dObject.GetLayer());
110 
111  bVisible = pVisibleSdrLayerIDSet->IsSet(aLayerID);
112  }
113 
114  if(bVisible && bTestSelectedVisibility)
115  {
116  // test selected visibility (see 3D View's DrawMarkedObj implementation)
117  const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
118 
119  bVisible = rE3dObject.GetSelected();
120  }
121 
122  if (bVisible)
123  {
124  // add to visible target vector
125  o_pVisibleTarget->append(xPrimitive3DSeq);
126  }
127  }
128  }
129  }
130  }
131 }
132 
133 }
134 
135 namespace sdr { namespace contact {
136 
137 // Create an Object-Specific ViewObjectContact, set ViewContact and
138 // ObjectContact. Always needs to return something.
139 ViewObjectContact& ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
140 {
141  ViewObjectContact* pRetval = new ViewObjectContactOfE3dScene(rObjectContact, *this);
142  DBG_ASSERT(pRetval, "ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact() failed (!)");
143 
144  return *pRetval;
145 }
146 
147 ViewContactOfE3dScene::ViewContactOfE3dScene(E3dScene& rScene)
148 : ViewContactOfSdrObj(rScene),
149  maViewInformation3D(),
150  maObjectTransformation(),
151  maSdrSceneAttribute(),
152  maSdrLightingAttribute()
153 {
154 }
155 
157 {
158  basegfx::B3DHomMatrix aTransformation;
159  basegfx::B3DHomMatrix aOrientation;
160  basegfx::B3DHomMatrix aProjection;
161  basegfx::B3DHomMatrix aDeviceToView;
162 
163  // create transformation (scene as group's transformation)
164  // For historical reasons, the outmost scene's transformation is handles as part of the
165  // view transformation. This means that the BoundRect of the contained 3D Objects is
166  // without that transformation and makes it necessary to NOT add the first scene to the
167  // Primitive3DContainer of contained objects.
168  {
169  aTransformation = GetE3dScene().GetTransform();
170  }
171 
172  // create orientation (world to camera coordinate system)
173  {
174  // calculate orientation from VRP, VPN and VUV
175  const B3dCamera& rSceneCamera = GetE3dScene().GetCameraSet();
176  const basegfx::B3DPoint& aVRP(rSceneCamera.GetVRP());
177  const basegfx::B3DVector& aVPN(rSceneCamera.GetVPN());
178  const basegfx::B3DVector& aVUV(rSceneCamera.GetVUV());
179 
180  aOrientation.orientation(aVRP, aVPN, aVUV);
181  }
182 
183  // create projection (camera coordinate system to relative 2d where X,Y and Z are [0.0 .. 1.0])
184  {
185  const basegfx::B3DHomMatrix aWorldToCamera(aOrientation * aTransformation);
186  basegfx::B3DRange aCameraRange(rContentRange);
187  aCameraRange.transform(aWorldToCamera);
188 
189  // remember Z-Values, but change orientation
190  const double fMinZ(-aCameraRange.getMaxZ());
191  const double fMaxZ(-aCameraRange.getMinZ());
192 
193  // construct temporary matrix from world to device. Use unit values here to measure expansion
194  basegfx::B3DHomMatrix aWorldToDevice(aWorldToCamera);
196 
197  if(css::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
198  {
199  aWorldToDevice.frustum(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
200  }
201  else
202  {
203  aWorldToDevice.ortho(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
204  }
205 
206  // create B3DRange in device. This will create the real used ranges
207  // in camera space. Do not use the Z-Values, though.
208  basegfx::B3DRange aDeviceRange(rContentRange);
209  aDeviceRange.transform(aWorldToDevice);
210 
211  // set projection
212  if(css::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
213  {
214  aProjection.frustum(
215  aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
216  aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
217  fMinZ, fMaxZ);
218  }
219  else
220  {
221  aProjection.ortho(
222  aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
223  aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
224  fMinZ, fMaxZ);
225  }
226  }
227 
228  // create device to view transform
229  {
230  // create standard deviceToView projection for geometry
231  // input is [-1.0 .. 1.0] in X,Y and Z. bring to [0.0 .. 1.0]. Also
232  // necessary to flip Y due to screen orientation
233  // Z is not needed, but will also be brought to [0.0 .. 1.0]
234  aDeviceToView.scale(0.5, -0.5, 0.5);
235  aDeviceToView.translate(0.5, 0.5, 0.5);
236  }
237 
238  const uno::Sequence< beans::PropertyValue > aEmptyProperties;
240  aTransformation, aOrientation, aProjection,
241  aDeviceToView, 0.0, aEmptyProperties);
242 }
243 
245 {
246  // create 2d Object Transformation from relative point in 2d scene to world
247  const tools::Rectangle aRectangle(GetE3dScene().GetSnapRect());
248 
249  maObjectTransformation.set(0, 0, aRectangle.getWidth());
250  maObjectTransformation.set(1, 1, aRectangle.getHeight());
251  maObjectTransformation.set(0, 2, aRectangle.Left());
252  maObjectTransformation.set(1, 2, aRectangle.Top());
253 }
254 
256 {
257  const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
259 }
260 
262 {
263  const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
265 }
266 
268  const SdrLayerIDSet* pLayerVisibility) const
269 {
271  const sal_uInt32 nChildrenCount(GetObjectCount());
272 
273  if(nChildrenCount)
274  {
275  // create 3d scene primitive with visible content tested against rLayerVisibility
278  const bool bTestLayerVisibility(nullptr != pLayerVisibility);
279  const bool bTestSelectedVisibility(GetE3dScene().GetDrawOnlySelected());
280  const bool bTestVisibility(bTestLayerVisibility || bTestSelectedVisibility);
281 
282  // add children recursively. Do NOT start with (*this), this would create
283  // a 3D transformPrimitive for the start scene. While this is theoretically not
284  // a bad thing, for historical reasons the transformation of the outmost scene
285  // is seen as part of the ViewTransformation (see text in createViewInformation3D)
286  for(sal_uInt32 a(0); a < nChildrenCount; a++)
287  {
288  createSubPrimitive3DVector(
289  GetViewContact(a),
290  aAllSequence,
291  bTestLayerVisibility ? &aVisibleSequence : nullptr,
292  bTestLayerVisibility ? pLayerVisibility : nullptr,
293  bTestSelectedVisibility);
294  }
295 
296  const size_t nAllSize(!aAllSequence.empty() ? aAllSequence.size() : 0);
297  const size_t nVisibleSize(!aVisibleSequence.empty() ? aVisibleSequence.size() : 0);
298 
299  if((bTestVisibility && nVisibleSize) || nAllSize)
300  {
301  // for getting the 3D range using getB3DRangeFromPrimitive3DContainer a ViewInformation3D
302  // needs to be given for evtl. decompositions. At the same time createViewInformation3D
303  // currently is based on creating the target-ViewInformation3D using a given range. To
304  // get the true range, use a neutral ViewInformation3D here. This leaves all matrices
305  // on identity and the time on 0.0.
306  const uno::Sequence< beans::PropertyValue > aEmptyProperties;
307  const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
308  const basegfx::B3DRange aContentRange(aAllSequence.getB3DRange(aNeutralViewInformation3D));
309 
310  // create 2d primitive 3dscene with generated sub-list from collector
313  bTestVisibility ? aVisibleSequence : aAllSequence,
317  getViewInformation3D(aContentRange)));
318 
319  xRetval = drawinglayer::primitive2d::Primitive2DContainer{ xReference };
320  }
321  }
322 
323  // always append an invisible outline for the cases where no visible content exists
324  xRetval.push_back(
327 
328  return xRetval;
329 }
330 
332 {
334 
335  if(GetObjectCount())
336  {
337  // create a default ScenePrimitive2D (without visibility test of members)
338  xRetval = createScenePrimitive2DSequence(nullptr);
339  }
340 
341  return xRetval;
342 }
343 
345 {
346  // call parent
348 
349  // mark locally cached values as invalid
354 }
355 
357 {
359  {
360  // this version will create the content range on demand locally and thus is less
361  // performant than the other one. Since the information is buffered the planned
362  // behaviour is that the version with the given range is used initially.
363  basegfx::B3DRange aContentRange(getAllContentRange3D());
364 
365  if(aContentRange.isEmpty())
366  {
367  // empty scene, no 3d action should be necessary. Prepare some
368  // fallback size
369  OSL_FAIL("No need to get ViewInformation3D from an empty scene (!)");
370  aContentRange.expand(basegfx::B3DPoint(-100.0, -100.0, -100.0));
371  aContentRange.expand(basegfx::B3DPoint( 100.0, 100.0, 100.0));
372  }
373 
374  const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(aContentRange);
375  }
376 
377  return maViewInformation3D;
378 }
379 
381 {
383  {
384  const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(rContentRange);
385  }
386 
387  return maViewInformation3D;
388 }
389 
391 {
393  {
394  const_cast < ViewContactOfE3dScene* >(this)->createObjectTransformation();
395  }
396 
397  return maObjectTransformation;
398 }
399 
401 {
403  {
404  const_cast < ViewContactOfE3dScene* >(this)->createSdrSceneAttribute();
405  }
406 
407  return maSdrSceneAttribute;
408 }
409 
411 {
413  {
414  const_cast < ViewContactOfE3dScene* >(this)->createSdrLightingAttribute();
415  }
416 
417  return maSdrLightingAttribute;
418 }
419 
421 {
422  drawinglayer::primitive3d::Primitive3DContainer aAllPrimitive3DContainer;
423  const sal_uInt32 nChildrenCount(GetObjectCount());
424 
425  // add children recursively. Do NOT start with (*this), this would create
426  // a 3D transformPrimitive for the start scene. While this is theoretically not
427  // a bad thing, for historical reasons the transformation of the outmost scene
428  // is seen as part of the ViewTransformation (see text in createViewInformation3D)
429  for(sal_uInt32 a(0); a < nChildrenCount; a++)
430  {
431  createSubPrimitive3DVector(GetViewContact(a), aAllPrimitive3DContainer, nullptr, nullptr, false);
432  }
433 
434  return aAllPrimitive3DContainer;
435 }
436 
438 {
440  basegfx::B3DRange aAllContentRange3D;
441 
442  if(!xAllSequence.empty())
443  {
444  // for getting the 3D range using getB3DRangeFromPrimitive3DContainer a ViewInformation3D
445  // needs to be given for evtl. decompositions. Use a neutral ViewInformation3D here. This
446  // leaves all matrices on identity and the time on 0.0.
447  const uno::Sequence< beans::PropertyValue > aEmptyProperties;
448  const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
449 
450  aAllContentRange3D = xAllSequence.getB3DRange(aNeutralViewInformation3D);
451  }
452 
453  return aAllContentRange3D;
454 }
455 
456 }}
457 
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long getHeight() const
const drawinglayer::geometry::ViewInformation3D & getViewInformation3D() const
void append(const Primitive3DContainer &rSource)
bool bVisible
void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
const basegfx::B3DVector & GetVPN() const
const basegfx::B3DPoint & GetVRP() const
long getWidth() const
virtual drawinglayer::primitive2d::Primitive2DContainer createViewIndependentPrimitive2DSequence() const override
double getMinZ() const
const basegfx::B3DVector & GetVUV() const
bool isEmpty() const
drawinglayer::primitive3d::Primitive3DContainer getViewIndependentPrimitive3DContainer() const
const basegfx::B3DHomMatrix & GetTransform() const
Definition: obj3d.hxx:111
virtual ViewContact & GetViewContact(sal_uInt32 nIndex) const override
drawinglayer::primitive3d::Primitive3DContainer getAllPrimitive3DContainer() const
void scale(double fX, double fY, double fZ)
double getMaxZ() const
const E3dObject & GetE3dObject() const
double getMinX() const
const drawinglayer::attribute::SdrSceneAttribute & getSdrSceneAttribute() const
long Top() const
void frustum(double fLeft=-1.0, double fRight=1.0, double fBottom=-1.0, double fTop=1.0, double fNear=0.001, double fFar=1.0)
basegfx::B3DRange getB3DRange(const geometry::ViewInformation3D &aViewInformation) const
drawinglayer::attribute::SdrLightingAttribute maSdrLightingAttribute
bool GetSelected() const
Definition: obj3d.hxx:135
#define DBG_ASSERT(sCon, aError)
uno_Any a
void expand(const B3DTuple &rTuple)
double getMinY() const
bool isIdentity() const
css::uno::Reference< css::graphic::XPrimitive3D > Primitive3DReference
drawinglayer::primitive2d::Primitive2DContainer createScenePrimitive2DSequence(const SdrLayerIDSet *pLayerVisibility) const
drawinglayer::attribute::SdrSceneAttribute maSdrSceneAttribute
BASEGFX_DLLPUBLIC void transform(const B3DHomMatrix &rMatrix)
virtual SdrLayerID GetLayer() const
Definition: svdobj.cxx:604
void ortho(double fLeft=-1.0, double fRight=1.0, double fBottom=-1.0, double fTop=1.0, double fNear=0.0, double fFar=1.0)
void translate(double fX, double fY, double fZ)
drawinglayer::geometry::ViewInformation3D maViewInformation3D
bool IsSet(SdrLayerID a) const
Definition: svdsob.hxx:66
virtual sal_uInt32 GetObjectCount() const
void createViewInformation3D(const ::basegfx::B3DRange &rContentRange)
attribute::SdrSceneAttribute createNewSdrSceneAttribute(const SfxItemSet &rSet)
const basegfx::B2DHomMatrix & getObjectTransformation() const
virtual sal_uInt32 GetObjectCount() const override
const SfxItemSet & GetMergedItemSet() const
Definition: svdobj.cxx:1911
Primitive2DReference createHiddenGeometryPrimitives2D(const basegfx::B2DHomMatrix &rMatrix)
const drawinglayer::attribute::SdrLightingAttribute & getSdrLightingAttribute() const
css::uno::Reference< css::graphic::XPrimitive2D > Primitive2DReference
css::drawing::ProjectionMode getProjectionMode() const
long Left() const
virtual ViewContact & GetViewContact(sal_uInt32 nIndex) const
double getMaxX() const
double getMaxY() const
void orientation(const B3DPoint &rVRP=B3DPoint(0.0, 0.0, 1.0), B3DVector aVPN=B3DVector(0.0, 0.0, 1.0), B3DVector aVUV=B3DVector(0.0, 1.0, 0.0))
basegfx::B3DRange getAllContentRange3D() const
B3dCamera & GetCameraSet()
Definition: scene3d.hxx:148
attribute::SdrLightingAttribute createNewSdrLightingAttribute(const SfxItemSet &rSet)