Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / svx / source / sdr / contact / viewcontactofe3dscene.cxx
blobf3e2a366a0f286b00a71b3bedf8ec8a77d6a3c6c
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 .
20 #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
21 #include <svx/sdr/contact/displayinfo.hxx>
22 #include <svx/sdr/contact/viewobjectcontact.hxx>
23 #include <basegfx/polygon/b2dpolygontools.hxx>
24 #include <basegfx/color/bcolor.hxx>
25 #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
26 #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
27 #include <sdr/contact/viewobjectcontactofe3dscene.hxx>
28 #include <basegfx/matrix/b2dhommatrix.hxx>
29 #include <basegfx/range/b3drange.hxx>
30 #include <drawinglayer/primitive3d/baseprimitive3d.hxx>
31 #include <svx/sdr/contact/viewcontactofe3d.hxx>
32 #include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
33 #include <drawinglayer/primitive3d/transformprimitive3d.hxx>
34 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
36 using namespace com::sun::star;
38 namespace {
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,
43 drawinglayer::primitive3d::Primitive3DContainer& o_rAllTarget,
44 drawinglayer::primitive3d::Primitive3DContainer* o_pVisibleTarget,
45 const SdrLayerIDSet* pVisibleSdrLayerIDSet,
46 const bool bTestSelectedVisibility)
48 const sdr::contact::ViewContactOfE3dScene* pViewContactOfE3dScene = dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(&rCandidate);
50 if(pViewContactOfE3dScene)
52 const sal_uInt32 nChildrenCount(rCandidate.GetObjectCount());
54 if(nChildrenCount)
56 // provide new collection sequences
57 drawinglayer::primitive3d::Primitive3DContainer aNewAllTarget;
58 drawinglayer::primitive3d::Primitive3DContainer aNewVisibleTarget;
60 // add children recursively
61 for(sal_uInt32 a(0L); a < nChildrenCount; a++)
63 createSubPrimitive3DVector(
64 rCandidate.GetViewContact(a),
65 aNewAllTarget,
66 o_pVisibleTarget ? &aNewVisibleTarget : nullptr,
67 pVisibleSdrLayerIDSet,
68 bTestSelectedVisibility);
71 // create transform primitive for the created content combining content and transformtion
72 const drawinglayer::primitive3d::Primitive3DReference xReference(new drawinglayer::primitive3d::TransformPrimitive3D(
73 pViewContactOfE3dScene->GetE3dScene().GetTransform(),
74 aNewAllTarget));
76 // add created content to all target
77 o_rAllTarget.push_back(xReference);
79 // add created content to visible target if exists
80 if(o_pVisibleTarget)
82 o_pVisibleTarget->push_back(xReference);
86 else
88 // access view independent representation of rCandidate
89 const sdr::contact::ViewContactOfE3d* pViewContactOfE3d = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&rCandidate);
91 if(pViewContactOfE3d)
93 drawinglayer::primitive3d::Primitive3DContainer xPrimitive3DSeq(pViewContactOfE3d->getViewIndependentPrimitive3DContainer());
95 if(!xPrimitive3DSeq.empty())
97 // add to all target vector
98 o_rAllTarget.append(xPrimitive3DSeq);
100 if(o_pVisibleTarget)
102 // test visibility. Primitive is visible when both tests are true (AND)
103 bool bVisible(true);
105 if(pVisibleSdrLayerIDSet)
107 // test layer visibility
108 const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
109 const SdrLayerID aLayerID(rE3dObject.GetLayer());
111 bVisible = pVisibleSdrLayerIDSet->IsSet(aLayerID);
114 if(bVisible && bTestSelectedVisibility)
116 // test selected visibility (see 3D View's DrawMarkedObj implementation)
117 const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
119 bVisible = rE3dObject.GetSelected();
122 if(bVisible && o_pVisibleTarget)
124 // add to visible target vector
125 o_pVisibleTarget->append(xPrimitive3DSeq);
135 namespace sdr { namespace contact {
137 // Create a Object-Specific ViewObjectContact, set ViewContact and
138 // ObjectContact. Always needs to return something.
139 ViewObjectContact& ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
141 ViewObjectContact* pRetval = new ViewObjectContactOfE3dScene(rObjectContact, *this);
142 DBG_ASSERT(pRetval, "ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact() failed (!)");
144 return *pRetval;
147 ViewContactOfE3dScene::ViewContactOfE3dScene(E3dScene& rScene)
148 : ViewContactOfSdrObj(rScene),
149 maViewInformation3D(),
150 maObjectTransformation(),
151 maSdrSceneAttribute(),
152 maSdrLightingAttribute()
156 void ViewContactOfE3dScene::createViewInformation3D(const basegfx::B3DRange& rContentRange)
158 basegfx::B3DHomMatrix aTransformation;
159 basegfx::B3DHomMatrix aOrientation;
160 basegfx::B3DHomMatrix aProjection;
161 basegfx::B3DHomMatrix aDeviceToView;
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.
169 aTransformation = GetE3dScene().GetTransform();
172 // create orientation (world to camera coordinate system)
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());
180 aOrientation.orientation(aVRP, aVPN, aVUV);
183 // create projection (camera coordinate system to relative 2d where X,Y and Z are [0.0 .. 1.0])
185 const basegfx::B3DHomMatrix aWorldToCamera(aOrientation * aTransformation);
186 basegfx::B3DRange aCameraRange(rContentRange);
187 aCameraRange.transform(aWorldToCamera);
189 // remember Z-Values, but change orientation
190 const double fMinZ(-aCameraRange.getMaxZ());
191 const double fMaxZ(-aCameraRange.getMinZ());
193 // construct temporary matrix from world to device. Use unit values here to measure expansion
194 basegfx::B3DHomMatrix aWorldToDevice(aWorldToCamera);
195 const drawinglayer::attribute::SdrSceneAttribute& rSdrSceneAttribute = getSdrSceneAttribute();
197 if(css::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
199 aWorldToDevice.frustum(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
201 else
203 aWorldToDevice.ortho(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
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);
211 // set projection
212 if(css::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
214 aProjection.frustum(
215 aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
216 aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
217 fMinZ, fMaxZ);
219 else
221 aProjection.ortho(
222 aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
223 aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
224 fMinZ, fMaxZ);
228 // create device to view transform
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);
238 const uno::Sequence< beans::PropertyValue > aEmptyProperties;
239 maViewInformation3D = drawinglayer::geometry::ViewInformation3D(
240 aTransformation, aOrientation, aProjection,
241 aDeviceToView, 0.0, aEmptyProperties);
244 void ViewContactOfE3dScene::createObjectTransformation()
246 // create 2d Object Transformation from relative point in 2d scene to world
247 tools::Rectangle aRectangle = GetE3dScene().GetSnapRect();
248 // Hack for calc, transform position of object according
249 // to current zoom so as objects relative position to grid
250 // appears stable
251 aRectangle += GetE3dScene().GetGridOffset();
252 maObjectTransformation.set(0, 0, aRectangle.getWidth());
253 maObjectTransformation.set(1, 1, aRectangle.getHeight());
254 maObjectTransformation.set(0, 2, aRectangle.Left());
255 maObjectTransformation.set(1, 2, aRectangle.Top());
258 void ViewContactOfE3dScene::createSdrSceneAttribute()
260 const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
261 maSdrSceneAttribute = drawinglayer::primitive2d::createNewSdrSceneAttribute(rItemSet);
264 void ViewContactOfE3dScene::createSdrLightingAttribute()
266 const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
267 maSdrLightingAttribute = drawinglayer::primitive2d::createNewSdrLightingAttribute(rItemSet);
270 drawinglayer::primitive2d::Primitive2DContainer ViewContactOfE3dScene::createScenePrimitive2DSequence(
271 const SdrLayerIDSet* pLayerVisibility) const
273 drawinglayer::primitive2d::Primitive2DContainer xRetval;
274 const sal_uInt32 nChildrenCount(GetObjectCount());
276 if(nChildrenCount)
278 // create 3d scene primitive with visible content tested against rLayerVisibility
279 drawinglayer::primitive3d::Primitive3DContainer aAllSequence;
280 drawinglayer::primitive3d::Primitive3DContainer aVisibleSequence;
281 const bool bTestLayerVisibility(nullptr != pLayerVisibility);
282 const bool bTestSelectedVisibility(GetE3dScene().GetDrawOnlySelected());
283 const bool bTestVisibility(bTestLayerVisibility || bTestSelectedVisibility);
285 // add children recursively. Do NOT start with (*this), this would create
286 // a 3D transformPrimitive for the start scene. While this is theoretically not
287 // a bad thing, for historical reasons the transformation of the outmost scene
288 // is seen as part of the ViewTransformation (see text in createViewInformation3D)
289 for(sal_uInt32 a(0L); a < nChildrenCount; a++)
291 createSubPrimitive3DVector(
292 GetViewContact(a),
293 aAllSequence,
294 bTestLayerVisibility ? &aVisibleSequence : nullptr,
295 bTestLayerVisibility ? pLayerVisibility : nullptr,
296 bTestSelectedVisibility);
299 const size_t nAllSize(!aAllSequence.empty() ? aAllSequence.size() : 0);
300 const size_t nVisibleSize(!aVisibleSequence.empty() ? aVisibleSequence.size() : 0);
302 if((bTestVisibility && nVisibleSize) || nAllSize)
304 // for getting the 3D range using getB3DRangeFromPrimitive3DContainer a ViewInformation3D
305 // needs to be given for evtl. decompositions. At the same time createViewInformation3D
306 // currently is based on creating the target-ViewInformation3D using a given range. To
307 // get the true range, use a neutral ViewInformation3D here. This leaves all matrices
308 // on identity and the time on 0.0.
309 const uno::Sequence< beans::PropertyValue > aEmptyProperties;
310 const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
311 const basegfx::B3DRange aContentRange(aAllSequence.getB3DRange(aNeutralViewInformation3D));
313 // create 2d primitive 3dscene with generated sub-list from collector
314 const drawinglayer::primitive2d::Primitive2DReference xReference(
315 new drawinglayer::primitive2d::ScenePrimitive2D(
316 bTestVisibility ? aVisibleSequence : aAllSequence,
317 getSdrSceneAttribute(),
318 getSdrLightingAttribute(),
319 getObjectTransformation(),
320 getViewInformation3D(aContentRange)));
322 xRetval = drawinglayer::primitive2d::Primitive2DContainer{ xReference };
326 // always append an invisible outline for the cases where no visible content exists
327 xRetval.push_back(
328 drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
329 getObjectTransformation()));
331 return xRetval;
334 drawinglayer::primitive2d::Primitive2DContainer ViewContactOfE3dScene::createViewIndependentPrimitive2DSequence() const
336 drawinglayer::primitive2d::Primitive2DContainer xRetval;
338 if(GetObjectCount())
340 // create a default ScenePrimitive2D (without visibility test of members)
341 xRetval = createScenePrimitive2DSequence(nullptr);
344 return xRetval;
347 void ViewContactOfE3dScene::ActionChanged()
349 // call parent
350 ViewContactOfSdrObj::ActionChanged();
352 // mark locally cached values as invalid
353 maViewInformation3D = drawinglayer::geometry::ViewInformation3D();
354 maObjectTransformation.identity();
355 maSdrSceneAttribute = drawinglayer::attribute::SdrSceneAttribute();
356 maSdrLightingAttribute = drawinglayer::attribute::SdrLightingAttribute();
359 const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D() const
361 if(maViewInformation3D.isDefault())
363 // this version will create the content range on demand locally and thus is less
364 // performant than the other one. Since the information is buffered the planned
365 // behaviour is that the version with the given range is used initially.
366 basegfx::B3DRange aContentRange(getAllContentRange3D());
368 if(aContentRange.isEmpty())
370 // empty scene, no 3d action should be necessary. Prepare some
371 // fallback size
372 OSL_FAIL("No need to get ViewInformation3D from an empty scene (!)");
373 aContentRange.expand(basegfx::B3DPoint(-100.0, -100.0, -100.0));
374 aContentRange.expand(basegfx::B3DPoint( 100.0, 100.0, 100.0));
377 const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(aContentRange);
380 return maViewInformation3D;
383 const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D(const basegfx::B3DRange& rContentRange) const
385 if(maViewInformation3D.isDefault())
387 const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(rContentRange);
390 return maViewInformation3D;
393 const basegfx::B2DHomMatrix& ViewContactOfE3dScene::getObjectTransformation() const
395 if(maObjectTransformation.isIdentity())
397 const_cast < ViewContactOfE3dScene* >(this)->createObjectTransformation();
400 return maObjectTransformation;
403 const drawinglayer::attribute::SdrSceneAttribute& ViewContactOfE3dScene::getSdrSceneAttribute() const
405 if(maSdrSceneAttribute.isDefault())
407 const_cast < ViewContactOfE3dScene* >(this)->createSdrSceneAttribute();
410 return maSdrSceneAttribute;
413 const drawinglayer::attribute::SdrLightingAttribute& ViewContactOfE3dScene::getSdrLightingAttribute() const
415 if(maSdrLightingAttribute.isDefault())
417 const_cast < ViewContactOfE3dScene* >(this)->createSdrLightingAttribute();
420 return maSdrLightingAttribute;
423 drawinglayer::primitive3d::Primitive3DContainer ViewContactOfE3dScene::getAllPrimitive3DContainer() const
425 drawinglayer::primitive3d::Primitive3DContainer aAllPrimitive3DContainer;
426 const sal_uInt32 nChildrenCount(GetObjectCount());
428 // add children recursively. Do NOT start with (*this), this would create
429 // a 3D transformPrimitive for the start scene. While this is theoretically not
430 // a bad thing, for historical reasons the transformation of the outmost scene
431 // is seen as part of the ViewTransformation (see text in createViewInformation3D)
432 for(sal_uInt32 a(0L); a < nChildrenCount; a++)
434 createSubPrimitive3DVector(GetViewContact(a), aAllPrimitive3DContainer, nullptr, nullptr, false);
437 return aAllPrimitive3DContainer;
440 basegfx::B3DRange ViewContactOfE3dScene::getAllContentRange3D() const
442 const drawinglayer::primitive3d::Primitive3DContainer xAllSequence(getAllPrimitive3DContainer());
443 basegfx::B3DRange aAllContentRange3D;
445 if(!xAllSequence.empty())
447 // for getting the 3D range using getB3DRangeFromPrimitive3DContainer a ViewInformation3D
448 // needs to be given for evtl. decompositions. Use a neutral ViewInformation3D here. This
449 // leaves all matrices on identity and the time on 0.0.
450 const uno::Sequence< beans::PropertyValue > aEmptyProperties;
451 const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
453 aAllContentRange3D = xAllSequence.getB3DRange(aNeutralViewInformation3D);
456 return aAllContentRange3D;
461 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */