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