Line data Source code
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 :
20 : #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
21 : #include <svx/polysc3d.hxx>
22 : #include <svx/sdr/contact/displayinfo.hxx>
23 : #include <svx/sdr/contact/viewobjectcontact.hxx>
24 : #include <basegfx/polygon/b2dpolygontools.hxx>
25 : #include <basegfx/color/bcolor.hxx>
26 : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
27 : #include <svx/sdr/primitive2d/sdrattributecreator.hxx>
28 : #include <sdr/contact/viewobjectcontactofe3dscene.hxx>
29 : #include <basegfx/matrix/b2dhommatrix.hxx>
30 : #include <basegfx/range/b3drange.hxx>
31 : #include <drawinglayer/primitive3d/baseprimitive3d.hxx>
32 : #include <svx/sdr/contact/viewcontactofe3d.hxx>
33 : #include <drawinglayer/primitive2d/sceneprimitive2d.hxx>
34 : #include <drawinglayer/primitive3d/transformprimitive3d.hxx>
35 : #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
36 :
37 :
38 :
39 : using namespace com::sun::star;
40 :
41 :
42 :
43 : namespace
44 : {
45 : // pActiveVC is only true if ghosted is still activated and maybe needs to be switched off in this path
46 9819 : void createSubPrimitive3DVector(
47 : const sdr::contact::ViewContact& rCandidate,
48 : drawinglayer::primitive3d::Primitive3DSequence& o_rAllTarget,
49 : drawinglayer::primitive3d::Primitive3DSequence* o_pVisibleTarget,
50 : const SetOfByte* pVisibleLayerSet,
51 : const bool bTestSelectedVisibility)
52 : {
53 9819 : const sdr::contact::ViewContactOfE3dScene* pViewContactOfE3dScene = dynamic_cast< const sdr::contact::ViewContactOfE3dScene* >(&rCandidate);
54 :
55 9819 : if(pViewContactOfE3dScene)
56 : {
57 5662 : const sal_uInt32 nChildrenCount(rCandidate.GetObjectCount());
58 :
59 5662 : if(nChildrenCount)
60 : {
61 : // provide new collection sequences
62 3177 : drawinglayer::primitive3d::Primitive3DSequence aNewAllTarget;
63 6354 : drawinglayer::primitive3d::Primitive3DSequence aNewVisibleTarget;
64 :
65 : // add children recursively
66 12264 : for(sal_uInt32 a(0L); a < nChildrenCount; a++)
67 : {
68 : createSubPrimitive3DVector(
69 9087 : rCandidate.GetViewContact(a),
70 : aNewAllTarget,
71 : o_pVisibleTarget ? &aNewVisibleTarget : 0,
72 : pVisibleLayerSet,
73 18174 : bTestSelectedVisibility);
74 : }
75 :
76 : // create transform primitive for the created content combining content and transformtion
77 : const drawinglayer::primitive3d::Primitive3DReference xReference(new drawinglayer::primitive3d::TransformPrimitive3D(
78 3177 : pViewContactOfE3dScene->GetE3dScene().GetTransform(),
79 6354 : aNewAllTarget));
80 :
81 : // add created content to all target
82 3177 : drawinglayer::primitive3d::appendPrimitive3DReferenceToPrimitive3DSequence(o_rAllTarget, xReference);
83 :
84 : // add created content to visibiel target if exists
85 3177 : if(o_pVisibleTarget)
86 : {
87 18 : drawinglayer::primitive3d::appendPrimitive3DReferenceToPrimitive3DSequence(*o_pVisibleTarget, xReference);
88 3177 : }
89 : }
90 : }
91 : else
92 : {
93 : // access view independent representation of rCandidate
94 4157 : const sdr::contact::ViewContactOfE3d* pViewContactOfE3d = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&rCandidate);
95 :
96 4157 : if(pViewContactOfE3d)
97 : {
98 4157 : drawinglayer::primitive3d::Primitive3DSequence xPrimitive3DSeq(pViewContactOfE3d->getViewIndependentPrimitive3DSequence());
99 :
100 4157 : if(xPrimitive3DSeq.hasElements())
101 : {
102 : // add to all target vector
103 4157 : drawinglayer::primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(o_rAllTarget, xPrimitive3DSeq);
104 :
105 4157 : if(o_pVisibleTarget)
106 : {
107 : // test visibility. Primitive is visible when both tests are true (AND)
108 30 : bool bVisible(true);
109 :
110 30 : if(pVisibleLayerSet)
111 : {
112 : // test layer visibility
113 30 : const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
114 30 : const SdrLayerID aLayerID(rE3dObject.GetLayer());
115 :
116 30 : bVisible = pVisibleLayerSet->IsSet(aLayerID);
117 : }
118 :
119 30 : if(bVisible && bTestSelectedVisibility)
120 : {
121 : // test selected visibility (see 3D View's DrawMarkedObj implementation)
122 0 : const E3dObject& rE3dObject = pViewContactOfE3d->GetE3dObject();
123 :
124 0 : bVisible = rE3dObject.GetSelected();
125 : }
126 :
127 30 : if(bVisible && o_pVisibleTarget)
128 : {
129 : // add to visible target vector
130 30 : drawinglayer::primitive3d::appendPrimitive3DSequenceToPrimitive3DSequence(*o_pVisibleTarget, xPrimitive3DSeq);
131 : }
132 : }
133 4157 : }
134 : }
135 : }
136 9819 : }
137 : } // end of anonymous namespace
138 :
139 :
140 :
141 : namespace sdr
142 : {
143 : namespace contact
144 : {
145 : // Create a Object-Specific ViewObjectContact, set ViewContact and
146 : // ObjectContact. Always needs to return something.
147 18 : ViewObjectContact& ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
148 : {
149 18 : ViewObjectContact* pRetval = new ViewObjectContactOfE3dScene(rObjectContact, *this);
150 : DBG_ASSERT(pRetval, "ViewContactOfE3dScene::CreateObjectSpecificViewObjectContact() failed (!)");
151 :
152 18 : return *pRetval;
153 : }
154 :
155 1406 : ViewContactOfE3dScene::ViewContactOfE3dScene(E3dScene& rScene)
156 : : ViewContactOfSdrObj(rScene),
157 : maViewInformation3D(),
158 : maObjectTransformation(),
159 : maSdrSceneAttribute(),
160 1406 : maSdrLightingAttribute()
161 : {
162 1406 : }
163 :
164 400 : void ViewContactOfE3dScene::createViewInformation3D(const basegfx::B3DRange& rContentRange)
165 : {
166 400 : basegfx::B3DHomMatrix aTransformation;
167 800 : basegfx::B3DHomMatrix aOrientation;
168 800 : basegfx::B3DHomMatrix aProjection;
169 800 : basegfx::B3DHomMatrix aDeviceToView;
170 :
171 : // create transformation (scene as group's transformation)
172 : // For historical reasons, the outmost scene's transformation is handles as part of the
173 : // view transformation. This means that the BoundRect of the contained 3D Objects is
174 : // without that transformation and makes it necessary to NOT add the first scene to the
175 : // Primitive3DSequence of contained objects.
176 : {
177 400 : aTransformation = GetE3dScene().GetTransform();
178 : }
179 :
180 : // create orientation (world to camera coordinate system)
181 : {
182 : // calculate orientation from VRP, VPN and VUV
183 400 : const B3dCamera& rSceneCamera = GetE3dScene().GetCameraSet();
184 400 : const basegfx::B3DPoint aVRP(rSceneCamera.GetVRP());
185 800 : const basegfx::B3DVector aVPN(rSceneCamera.GetVRP());
186 800 : const basegfx::B3DVector aVUV(rSceneCamera.GetVUV());
187 :
188 800 : aOrientation.orientation(aVRP, aVPN, aVUV);
189 : }
190 :
191 : // create projection (camera coordinate system to relative 2d where X,Y and Z are [0.0 .. 1.0])
192 : {
193 400 : const basegfx::B3DHomMatrix aWorldToCamera(aOrientation * aTransformation);
194 400 : basegfx::B3DRange aCameraRange(rContentRange);
195 400 : aCameraRange.transform(aWorldToCamera);
196 :
197 : // remember Z-Values, but change orientation
198 400 : const double fMinZ(-aCameraRange.getMaxZ());
199 400 : const double fMaxZ(-aCameraRange.getMinZ());
200 :
201 : // construct temporary matrix from world to device. Use unit values here to measure expansion
202 800 : basegfx::B3DHomMatrix aWorldToDevice(aWorldToCamera);
203 400 : const drawinglayer::attribute::SdrSceneAttribute& rSdrSceneAttribute = getSdrSceneAttribute();
204 :
205 400 : if(::com::sun::star::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
206 : {
207 224 : aWorldToDevice.frustum(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
208 : }
209 : else
210 : {
211 176 : aWorldToDevice.ortho(-1.0, 1.0, -1.0, 1.0, fMinZ, fMaxZ);
212 : }
213 :
214 : // create B3DRange in device. This will create the real used ranges
215 : // in camera space. Do not use the Z-Values, though.
216 400 : basegfx::B3DRange aDeviceRange(rContentRange);
217 400 : aDeviceRange.transform(aWorldToDevice);
218 :
219 : // set projection
220 400 : if(::com::sun::star::drawing::ProjectionMode_PERSPECTIVE == rSdrSceneAttribute.getProjectionMode())
221 : {
222 : aProjection.frustum(
223 : aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
224 : aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
225 224 : fMinZ, fMaxZ);
226 : }
227 : else
228 : {
229 : aProjection.ortho(
230 : aDeviceRange.getMinX(), aDeviceRange.getMaxX(),
231 : aDeviceRange.getMinY(), aDeviceRange.getMaxY(),
232 176 : fMinZ, fMaxZ);
233 400 : }
234 : }
235 :
236 : // create device to view transform
237 : {
238 : // create standard deviceToView projection for geometry
239 : // input is [-1.0 .. 1.0] in X,Y and Z. bring to [0.0 .. 1.0]. Also
240 : // necessary to flip Y due to screen orientation
241 : // Z is not needed, but will also be brought to [0.0 .. 1.0]
242 400 : aDeviceToView.scale(0.5, -0.5, 0.5);
243 400 : aDeviceToView.translate(0.5, 0.5, 0.5);
244 : }
245 :
246 800 : const uno::Sequence< beans::PropertyValue > aEmptyProperties;
247 800 : maViewInformation3D = drawinglayer::geometry::ViewInformation3D(
248 : aTransformation, aOrientation, aProjection,
249 800 : aDeviceToView, 0.0, aEmptyProperties);
250 400 : }
251 :
252 400 : void ViewContactOfE3dScene::createObjectTransformation()
253 : {
254 : // create 2d Object Transformation from relative point in 2d scene to world
255 400 : Rectangle aRectangle = GetE3dScene().GetSnapRect();
256 : // Hack for calc, transform position of object according
257 : // to current zoom so as objects relative position to grid
258 : // appears stable
259 400 : aRectangle += GetE3dScene().GetGridOffset();
260 400 : maObjectTransformation.set(0, 0, aRectangle.getWidth());
261 400 : maObjectTransformation.set(1, 1, aRectangle.getHeight());
262 400 : maObjectTransformation.set(0, 2, aRectangle.Left());
263 400 : maObjectTransformation.set(1, 2, aRectangle.Top());
264 400 : }
265 :
266 400 : void ViewContactOfE3dScene::createSdrSceneAttribute()
267 : {
268 400 : const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
269 400 : maSdrSceneAttribute = drawinglayer::primitive2d::createNewSdrSceneAttribute(rItemSet);
270 400 : }
271 :
272 27 : void ViewContactOfE3dScene::createSdrLightingAttribute()
273 : {
274 27 : const SfxItemSet& rItemSet = GetE3dScene().GetMergedItemSet();
275 27 : maSdrLightingAttribute = drawinglayer::primitive2d::createNewSdrLightingAttribute(rItemSet);
276 27 : }
277 :
278 36 : drawinglayer::primitive2d::Primitive2DSequence ViewContactOfE3dScene::createScenePrimitive2DSequence(
279 : const SetOfByte* pLayerVisibility) const
280 : {
281 36 : drawinglayer::primitive2d::Primitive2DSequence xRetval;
282 36 : const sal_uInt32 nChildrenCount(GetObjectCount());
283 :
284 36 : if(nChildrenCount)
285 : {
286 : // create 3d scene primitive with visible content tested against rLayerVisibility
287 36 : drawinglayer::primitive3d::Primitive3DSequence aAllSequence;
288 72 : drawinglayer::primitive3d::Primitive3DSequence aVisibleSequence;
289 36 : const bool bTestLayerVisibility(0 != pLayerVisibility);
290 36 : const bool bTestSelectedVisibility(GetE3dScene().GetDrawOnlySelected());
291 36 : const bool bTestVisibility(bTestLayerVisibility || bTestSelectedVisibility);
292 :
293 : // add children recursively. Do NOT start with (*this), this would create
294 : // a 3D transformPrimitive for the start scene. While this is theoretically not
295 : // a bad thing, for historical reasons the transformation of the outmost scene
296 : // is seen as part of the ViewTransformation (see text in createViewInformation3D)
297 72 : for(sal_uInt32 a(0L); a < nChildrenCount; a++)
298 : {
299 : createSubPrimitive3DVector(
300 36 : GetViewContact(a),
301 : aAllSequence,
302 : bTestLayerVisibility ? &aVisibleSequence : 0,
303 : bTestLayerVisibility ? pLayerVisibility : 0,
304 72 : bTestSelectedVisibility);
305 : }
306 :
307 36 : const sal_uInt32 nAllSize(aAllSequence.hasElements() ? aAllSequence.getLength() : 0);
308 36 : const sal_uInt32 nVisibleSize(aVisibleSequence.hasElements() ? aVisibleSequence.getLength() : 0);
309 :
310 36 : if((bTestVisibility && nVisibleSize) || nAllSize)
311 : {
312 : // for getting the 3D range using getB3DRangeFromPrimitive3DSequence a ViewInformation3D
313 : // needs to be given for evtl. decompositions. At the same time createViewInformation3D
314 : // currently is based on creating the target-ViewInformation3D using a given range. To
315 : // get the true range, use a neutral ViewInformation3D here. This leaves all matrices
316 : // on identity and the time on 0.0.
317 36 : const uno::Sequence< beans::PropertyValue > aEmptyProperties;
318 72 : const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
319 : const basegfx::B3DRange aContentRange(
320 36 : drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(aAllSequence, aNeutralViewInformation3D));
321 :
322 : // create 2d primitive 3dscene with generated sub-list from collector
323 : const drawinglayer::primitive2d::Primitive2DReference xReference(
324 : new drawinglayer::primitive2d::ScenePrimitive2D(
325 : bTestVisibility ? aVisibleSequence : aAllSequence,
326 : getSdrSceneAttribute(),
327 : getSdrLightingAttribute(),
328 : getObjectTransformation(),
329 72 : getViewInformation3D(aContentRange)));
330 :
331 72 : xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1);
332 36 : }
333 : }
334 :
335 : // always append an invisible outline for the cases where no visible content exists
336 : drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(xRetval,
337 : drawinglayer::primitive2d::createHiddenGeometryPrimitives2D(
338 36 : false, getObjectTransformation()));
339 :
340 36 : return xRetval;
341 : }
342 :
343 34 : drawinglayer::primitive2d::Primitive2DSequence ViewContactOfE3dScene::createViewIndependentPrimitive2DSequence() const
344 : {
345 34 : drawinglayer::primitive2d::Primitive2DSequence xRetval;
346 :
347 34 : if(GetObjectCount())
348 : {
349 : // create a default ScenePrimitive2D (without visibility test of members)
350 34 : xRetval = createScenePrimitive2DSequence(0);
351 : }
352 :
353 34 : return xRetval;
354 : }
355 :
356 6466 : void ViewContactOfE3dScene::ActionChanged()
357 : {
358 : // call parent
359 6466 : ViewContactOfSdrObj::ActionChanged();
360 :
361 : // mark locally cached values as invalid
362 6466 : maViewInformation3D = drawinglayer::geometry::ViewInformation3D();
363 6466 : maObjectTransformation.identity();
364 6466 : maSdrSceneAttribute = drawinglayer::attribute::SdrSceneAttribute();
365 6466 : maSdrLightingAttribute = drawinglayer::attribute::SdrLightingAttribute();
366 6466 : }
367 :
368 3319 : const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D() const
369 : {
370 3319 : if(maViewInformation3D.isDefault())
371 : {
372 : // this version will create the content range on demand locally and thus is less
373 : // performant than the other one. Since the information is buffered the planned
374 : // behaviour is that the version with the given range is used initially.
375 260 : basegfx::B3DRange aContentRange(getAllContentRange3D());
376 :
377 260 : if(aContentRange.isEmpty())
378 : {
379 : // empty scene, no 3d action should be necessary. Prepare some
380 : // fallback size
381 : OSL_FAIL("No need to get ViewInformation3D from an empty scene (!)");
382 37 : aContentRange.expand(basegfx::B3DPoint(-100.0, -100.0, -100.0));
383 37 : aContentRange.expand(basegfx::B3DPoint( 100.0, 100.0, 100.0));
384 : }
385 :
386 260 : const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(aContentRange);
387 : }
388 :
389 3319 : return maViewInformation3D;
390 : }
391 :
392 254 : const drawinglayer::geometry::ViewInformation3D& ViewContactOfE3dScene::getViewInformation3D(const basegfx::B3DRange& rContentRange) const
393 : {
394 254 : if(maViewInformation3D.isDefault())
395 : {
396 140 : const_cast < ViewContactOfE3dScene* >(this)->createViewInformation3D(rContentRange);
397 : }
398 :
399 254 : return maViewInformation3D;
400 : }
401 :
402 3609 : const basegfx::B2DHomMatrix& ViewContactOfE3dScene::getObjectTransformation() const
403 : {
404 3609 : if(maObjectTransformation.isIdentity())
405 : {
406 400 : const_cast < ViewContactOfE3dScene* >(this)->createObjectTransformation();
407 : }
408 :
409 3609 : return maObjectTransformation;
410 : }
411 :
412 436 : const drawinglayer::attribute::SdrSceneAttribute& ViewContactOfE3dScene::getSdrSceneAttribute() const
413 : {
414 436 : if(maSdrSceneAttribute.isDefault())
415 : {
416 400 : const_cast < ViewContactOfE3dScene* >(this)->createSdrSceneAttribute();
417 : }
418 :
419 436 : return maSdrSceneAttribute;
420 : }
421 :
422 36 : const drawinglayer::attribute::SdrLightingAttribute& ViewContactOfE3dScene::getSdrLightingAttribute() const
423 : {
424 36 : if(maSdrLightingAttribute.isDefault())
425 : {
426 27 : const_cast < ViewContactOfE3dScene* >(this)->createSdrLightingAttribute();
427 : }
428 :
429 36 : return maSdrLightingAttribute;
430 : }
431 :
432 696 : drawinglayer::primitive3d::Primitive3DSequence ViewContactOfE3dScene::getAllPrimitive3DSequence() const
433 : {
434 696 : drawinglayer::primitive3d::Primitive3DSequence aAllPrimitive3DSequence;
435 696 : const sal_uInt32 nChildrenCount(GetObjectCount());
436 :
437 : // add children recursively. Do NOT start with (*this), this would create
438 : // a 3D transformPrimitive for the start scene. While this is theoretically not
439 : // a bad thing, for historical reasons the transformation of the outmost scene
440 : // is seen as part of the ViewTransformation (see text in createViewInformation3D)
441 1392 : for(sal_uInt32 a(0L); a < nChildrenCount; a++)
442 : {
443 696 : createSubPrimitive3DVector(GetViewContact(a), aAllPrimitive3DSequence, 0, 0, false);
444 : }
445 :
446 696 : return aAllPrimitive3DSequence;
447 : }
448 :
449 696 : basegfx::B3DRange ViewContactOfE3dScene::getAllContentRange3D() const
450 : {
451 696 : const drawinglayer::primitive3d::Primitive3DSequence xAllSequence(getAllPrimitive3DSequence());
452 696 : basegfx::B3DRange aAllContentRange3D;
453 :
454 696 : if(xAllSequence.hasElements())
455 : {
456 : // for getting the 3D range using getB3DRangeFromPrimitive3DSequence a ViewInformation3D
457 : // needs to be given for evtl. decompositions. Use a neutral ViewInformation3D here. This
458 : // leaves all matrices on identity and the time on 0.0.
459 696 : const uno::Sequence< beans::PropertyValue > aEmptyProperties;
460 1392 : const drawinglayer::geometry::ViewInformation3D aNeutralViewInformation3D(aEmptyProperties);
461 :
462 1392 : aAllContentRange3D = drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(xAllSequence, aNeutralViewInformation3D);
463 : }
464 :
465 696 : return aAllContentRange3D;
466 : }
467 : } // end of namespace contact
468 651 : } // end of namespace sdr
469 :
470 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|