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