xref: /aoo41x/main/svx/source/engine3d/scene3d.cxx (revision f6e50924)
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 
27 #include "svx/svdstr.hrc"
28 #include "svx/svdglob.hxx"
29 #include "svx/svditer.hxx"
30 
31 #if defined( UNX ) || defined( ICC )
32 #include <stdlib.h>
33 #endif
34 #include "svx/globl3d.hxx"
35 #include <svx/svdpage.hxx>
36 #include <svl/style.hxx>
37 #include <svx/scene3d.hxx>
38 #include <svx/e3dundo.hxx>
39 #include <svx/svdtrans.hxx>
40 #include <svx/svxids.hrc>
41 #include <editeng/colritem.hxx>
42 #include <svx/e3ditem.hxx>
43 #include <svx/xlntrit.hxx>
44 #include <svx/xfltrit.hxx>
45 #include <svx/svx3ditems.hxx>
46 #include <svl/whiter.hxx>
47 #include <svx/xflftrit.hxx>
48 #include <svx/sdr/properties/e3dsceneproperties.hxx>
49 #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
50 #include <svx/svddrag.hxx>
51 #include <helperminimaldepth3d.hxx>
52 #include <algorithm>
53 #include <drawinglayer/geometry/viewinformation3d.hxx>
54 #include <basegfx/polygon/b2dpolypolygontools.hxx>
55 #include <svx/e3dsceneupdater.hxx>
56 
57 #define ITEMVALUE(ItemSet,Id,Cast)	((const Cast&)(ItemSet).Get(Id)).GetValue()
58 
59 //////////////////////////////////////////////////////////////////////////////
60 // #110988#
61 
62 class ImpRemap3DDepth
63 {
64 	sal_uInt32					mnOrdNum;
65 	double						mfMinimalDepth;
66 
67 	// bitfield
68 	unsigned					mbIsScene : 1;
69 
70 public:
71 	ImpRemap3DDepth(sal_uInt32 nOrdNum, double fMinimalDepth);
72 	ImpRemap3DDepth(sal_uInt32 nOrdNum);
73 	~ImpRemap3DDepth();
74 
75 	// for ::std::sort
76 	bool operator<(const ImpRemap3DDepth& rComp) const;
77 
78 	sal_uInt32 GetOrdNum() const { return mnOrdNum; }
79 	sal_Bool IsScene() const { return mbIsScene; }
80 };
81 
82 ImpRemap3DDepth::ImpRemap3DDepth(sal_uInt32 nOrdNum, double fMinimalDepth)
83 :	mnOrdNum(nOrdNum),
84 	mfMinimalDepth(fMinimalDepth),
85 	mbIsScene(sal_False)
86 {
87 }
88 
89 ImpRemap3DDepth::ImpRemap3DDepth(sal_uInt32 nOrdNum)
90 :	mnOrdNum(nOrdNum),
91 	mbIsScene(sal_True)
92 {
93 }
94 
95 ImpRemap3DDepth::~ImpRemap3DDepth()
96 {
97 }
98 
99 bool ImpRemap3DDepth::operator<(const ImpRemap3DDepth& rComp) const
100 {
101 	if(IsScene())
102 	{
103 		return sal_False;
104 	}
105 	else
106 	{
107 		if(rComp.IsScene())
108 		{
109 			return sal_True;
110 		}
111 		else
112 		{
113 			return mfMinimalDepth < rComp.mfMinimalDepth;
114 		}
115 	}
116 }
117 
118 // typedefs for a vector of ImpRemap3DDepths
119 typedef ::std::vector< ImpRemap3DDepth > ImpRemap3DDepthVector;
120 
121 //////////////////////////////////////////////////////////////////////////////
122 // #110988#
123 
124 class Imp3DDepthRemapper
125 {
126 	ImpRemap3DDepthVector		maVector;
127 
128 public:
129 	Imp3DDepthRemapper(E3dScene& rScene);
130 	~Imp3DDepthRemapper();
131 
132 	sal_uInt32 RemapOrdNum(sal_uInt32 nOrdNum) const;
133 };
134 
135 Imp3DDepthRemapper::Imp3DDepthRemapper(E3dScene& rScene)
136 {
137 	// only called when rScene.GetSubList() and nObjCount > 1L
138 	SdrObjList* pList = rScene.GetSubList();
139 	const sal_uInt32 nObjCount(pList->GetObjCount());
140 
141 	for(sal_uInt32 a(0L); a < nObjCount; a++)
142 	{
143 		SdrObject* pCandidate = pList->GetObj(a);
144 
145 		if(pCandidate)
146 		{
147 			if(pCandidate->ISA(E3dCompoundObject))
148 			{
149 				// single 3d object, calc depth
150                 const double fMinimalDepth(getMinimalDepthInViewCoordinates(static_cast< const E3dCompoundObject& >(*pCandidate)));
151 				ImpRemap3DDepth aEntry(a, fMinimalDepth);
152 				maVector.push_back(aEntry);
153 			}
154 			else
155 			{
156 				// scene, use standard entry for scene
157 				ImpRemap3DDepth aEntry(a);
158 				maVector.push_back(aEntry);
159 			}
160 		}
161 	}
162 
163 	// now, we need to sort the maVector by it's members minimal depth. The
164 	// smaller, the nearer to the viewer.
165 	::std::sort(maVector.begin(), maVector.end());
166 }
167 
168 Imp3DDepthRemapper::~Imp3DDepthRemapper()
169 {
170 }
171 
172 sal_uInt32 Imp3DDepthRemapper::RemapOrdNum(sal_uInt32 nOrdNum) const
173 {
174 	if(nOrdNum < maVector.size())
175 	{
176 		nOrdNum = maVector[(maVector.size() - 1) - nOrdNum].GetOrdNum();
177 	}
178 
179 	return nOrdNum;
180 }
181 
182 //////////////////////////////////////////////////////////////////////////////
183 // BaseProperties section
184 
185 sdr::properties::BaseProperties* E3dScene::CreateObjectSpecificProperties()
186 {
187 	return new sdr::properties::E3dSceneProperties(*this);
188 }
189 
190 //////////////////////////////////////////////////////////////////////////////
191 // #110094# DrawContact section
192 
193 sdr::contact::ViewContact* E3dScene::CreateObjectSpecificViewContact()
194 {
195 	return new sdr::contact::ViewContactOfE3dScene(*this);
196 }
197 
198 ////////////////////////////////////////////////////////////////////////////////////////////////////
199 
200 TYPEINIT1(E3dScene, E3dObject);
201 
202 /*************************************************************************
203 |*
204 |* E3dScene-Konstruktor
205 |*
206 \************************************************************************/
207 
208 E3dScene::E3dScene()
209 :	E3dObject(),
210 	aCamera(basegfx::B3DPoint(0.0, 0.0, 4.0), basegfx::B3DPoint()),
211 	mp3DDepthRemapper(0L),
212 	bDrawOnlySelected(false)
213 {
214 	// Defaults setzen
215 	E3dDefaultAttributes aDefault;
216 	SetDefaultAttributes(aDefault);
217 }
218 
219 E3dScene::E3dScene(E3dDefaultAttributes& rDefault)
220 :	E3dObject(),
221 	aCamera(basegfx::B3DPoint(0.0, 0.0, 4.0), basegfx::B3DPoint()),
222 	mp3DDepthRemapper(0L),
223 	bDrawOnlySelected(false)
224 {
225 	// Defaults setzen
226 	SetDefaultAttributes(rDefault);
227 }
228 
229 void E3dScene::SetDefaultAttributes(E3dDefaultAttributes& /*rDefault*/)
230 {
231 	// Fuer OS/2 die FP-Exceptions abschalten
232 #if defined(OS2)
233 #define SC_FPEXCEPTIONS_ON()	_control87( MCW_EM, 0 )
234 #define SC_FPEXCEPTIONS_OFF()	_control87( MCW_EM, MCW_EM )
235 	SC_FPEXCEPTIONS_OFF();
236 #endif
237 
238 	// Fuer WIN95/NT die FP-Exceptions abschalten
239 #if defined(WNT)
240 #define SC_FPEXCEPTIONS_ON()	_control87( _MCW_EM, 0 )
241 #define SC_FPEXCEPTIONS_OFF()	_control87( _MCW_EM, _MCW_EM )
242 	SC_FPEXCEPTIONS_OFF();
243 #endif
244 
245 	// Defaults setzen
246 	aCamera.SetViewWindow(-2, -2, 4, 4);
247 	aCameraSet.SetDeviceRectangle(-2, 2, -2, 2);
248 	aCamera.SetDeviceWindow(Rectangle(0, 0, 10, 10));
249 	Rectangle aRect(0, 0, 10, 10);
250 	aCameraSet.SetViewportRectangle(aRect);
251 
252 	// set defaults for Camera from ItemPool
253 	aCamera.SetProjection(GetPerspective());
254 	basegfx::B3DPoint aActualPosition(aCamera.GetPosition());
255 	double fNew = GetDistance();
256 
257 	if(fabs(fNew - aActualPosition.getZ()) > 1.0)
258 	{
259 		aCamera.SetPosition( basegfx::B3DPoint( aActualPosition.getX(), aActualPosition.getY(), fNew) );
260 	}
261 
262 	fNew = GetFocalLength() / 100.0;
263 	aCamera.SetFocalLength(fNew);
264 }
265 
266 /*************************************************************************
267 |*
268 |* Destruktor
269 |*
270 \************************************************************************/
271 
272 E3dScene::~E3dScene()
273 {
274 	// #110988#
275 	ImpCleanup3DDepthMapper();
276 }
277 
278 basegfx::B2DPolyPolygon E3dScene::TakeXorPoly() const
279 {
280 	const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(GetViewContact());
281 	const drawinglayer::geometry::ViewInformation3D aViewInfo3D(rVCScene.getViewInformation3D());
282 	const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe());
283 
284 	basegfx::B2DPolyPolygon aRetval(basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
285 		aViewInfo3D.getObjectToView()));
286 	aRetval.transform(rVCScene.getObjectTransformation());
287 
288 	return aRetval;
289 }
290 
291 // #110988#
292 void E3dScene::ImpCleanup3DDepthMapper()
293 {
294 	if(mp3DDepthRemapper)
295 	{
296 		delete mp3DDepthRemapper;
297 		mp3DDepthRemapper = 0L;
298 	}
299 }
300 
301 // #110988#
302 sal_uInt32 E3dScene::RemapOrdNum(sal_uInt32 nNewOrdNum) const
303 {
304 	if(!mp3DDepthRemapper)
305 	{
306 		const sal_uInt32 nObjCount(GetSubList() ? GetSubList()->GetObjCount() : 0L);
307 
308 		if(nObjCount > 1L)
309 		{
310 			((E3dScene*)this)->mp3DDepthRemapper = new Imp3DDepthRemapper((E3dScene&)(*this));
311 		}
312 	}
313 
314 	if(mp3DDepthRemapper)
315 	{
316 		return mp3DDepthRemapper->RemapOrdNum(nNewOrdNum);
317 	}
318 
319 	return nNewOrdNum;
320 }
321 
322 /*************************************************************************
323 |*
324 |* Identifier zurueckgeben
325 |*
326 \************************************************************************/
327 
328 sal_uInt16 E3dScene::GetObjIdentifier() const
329 {
330 	return E3D_SCENE_ID;
331 }
332 
333 void E3dScene::SetBoundRectDirty()
334 {
335 	E3dScene* pScene = GetScene();
336 
337 	if(pScene == this)
338 	{
339 	    // avoid resetting aOutRect which in case of a 3D scene used as 2d object
340 		// is model data,not re-creatable view data
341 	}
342 	else
343 	{
344 		// if not the outmost scene it is used as group in 3d, call parent
345 		E3dObject::SetBoundRectDirty();
346 	}
347 }
348 
349 /*************************************************************************
350 |*
351 |* SetSnapRect
352 |*
353 \************************************************************************/
354 
355 void E3dScene::NbcSetSnapRect(const Rectangle& rRect)
356 {
357 	SetRectsDirty();
358 	E3dObject::NbcSetSnapRect(rRect);
359 	aCamera.SetDeviceWindow(rRect);
360 	aCameraSet.SetViewportRectangle((Rectangle&)rRect);
361 
362 	// #110988#
363 	ImpCleanup3DDepthMapper();
364 }
365 
366 /*************************************************************************
367 |*
368 |* Objekt verschieben
369 |*
370 \************************************************************************/
371 
372 void E3dScene::NbcMove(const Size& rSize)
373 {
374 	Rectangle aNewSnapRect = GetSnapRect();
375 	MoveRect(aNewSnapRect, rSize);
376 	NbcSetSnapRect(aNewSnapRect);
377 }
378 
379 /*************************************************************************
380 |*
381 |* Objekt Resizen
382 |*
383 \************************************************************************/
384 
385 void E3dScene::NbcResize(const Point& rRef, const Fraction& rXFact,
386 											const Fraction& rYFact)
387 {
388 	Rectangle aNewSnapRect = GetSnapRect();
389 	ResizeRect(aNewSnapRect, rRef, rXFact, rYFact);
390 	NbcSetSnapRect(aNewSnapRect);
391 }
392 
393 /*************************************************************************
394 |*
395 |* Neue Kamera setzen, und dabei die Szene und ggf. das BoundVolume
396 |* als geaendert markieren
397 |*
398 \************************************************************************/
399 
400 void E3dScene::SetCamera(const Camera3D& rNewCamera)
401 {
402 	// Alte Kamera setzen
403 	aCamera = rNewCamera;
404 	((sdr::properties::E3dSceneProperties&)GetProperties()).SetSceneItemsFromCamera();
405 
406 	SetRectsDirty();
407 
408 	// Neue Kamera aus alter fuellen
409 	Camera3D& rCam = (Camera3D&)GetCamera();
410 
411 	// Ratio abschalten
412 	if(rCam.GetAspectMapping() == AS_NO_MAPPING)
413 		GetCameraSet().SetRatio(0.0);
414 
415 	// Abbildungsgeometrie setzen
416 	basegfx::B3DPoint aVRP(rCam.GetViewPoint());
417 	basegfx::B3DVector aVPN(aVRP - rCam.GetVRP());
418 	basegfx::B3DVector aVUV(rCam.GetVUV());
419 
420 	// #91047# use SetViewportValues() to set VRP, VPN and VUV as vectors, too.
421 	// Else these values would not be exported/imported correctly.
422 	GetCameraSet().SetViewportValues(aVRP, aVPN, aVUV);
423 
424 	// Perspektive setzen
425 	GetCameraSet().SetPerspective(rCam.GetProjection() == PR_PERSPECTIVE);
426 	GetCameraSet().SetViewportRectangle((Rectangle&)rCam.GetDeviceWindow());
427 
428 	// #110988#
429 	ImpCleanup3DDepthMapper();
430 }
431 
432 /*************************************************************************
433 |*
434 |* 3D-Objekt einfuegen
435 |*
436 \************************************************************************/
437 
438 void E3dScene::NewObjectInserted(const E3dObject* p3DObj)
439 {
440 	E3dObject::NewObjectInserted(p3DObj);
441 
442 	if ( p3DObj == this )
443 		return;
444 
445 	// #110988#
446 	ImpCleanup3DDepthMapper();
447 }
448 
449 /*************************************************************************
450 |*
451 |* Parent ueber Aenderung eines Childs informieren
452 |*
453 \************************************************************************/
454 
455 void E3dScene::StructureChanged()
456 {
457 	E3dObject::StructureChanged();
458 	SetRectsDirty();
459 
460 	// #110988#
461 	ImpCleanup3DDepthMapper();
462 }
463 
464 /*************************************************************************
465 |*
466 |* Uebergeordnetes Szenenobjekt bestimmen
467 |*
468 \************************************************************************/
469 
470 E3dScene* E3dScene::GetScene() const
471 {
472 	if(GetParentObj())
473 		return GetParentObj()->GetScene();
474 	else
475 		return (E3dScene*)this;
476 }
477 
478 void E3dScene::removeAllNonSelectedObjects()
479 {
480 	E3DModifySceneSnapRectUpdater aUpdater(this);
481 
482     for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
483     {
484 		SdrObject* pObj = maSubList.GetObj(a);
485 
486         if(pObj)
487 		{
488             bool bRemoveObject(false);
489 
490             if(pObj->ISA(E3dScene))
491             {
492                 E3dScene* pScene = (E3dScene*)pObj;
493 
494                 // iterate over this sub-scene
495                 pScene->removeAllNonSelectedObjects();
496 
497                 // check object count. Empty scenes can be deleted
498                 const sal_uInt32 nObjCount(pScene->GetSubList() ? pScene->GetSubList()->GetObjCount() : 0);
499 
500                 if(!nObjCount)
501 			    {
502                     // all objects removed, scene can be removed, too
503                     bRemoveObject = true;
504 			    }
505 			}
506             else if(pObj->ISA(E3dCompoundObject))
507 			{
508                 E3dCompoundObject* pCompound = (E3dCompoundObject*)pObj;
509 
510 			    if(!pCompound->GetSelected())
511 				{
512                     bRemoveObject = true;
513 				}
514 			}
515 
516             if(bRemoveObject)
517 			{
518 			    maSubList.NbcRemoveObject(pObj->GetOrdNum());
519 			    a--;
520                 SdrObject::Free(pObj);
521             }
522         }
523     }
524 }
525 
526 /*************************************************************************
527 |*
528 |* Zuweisungsoperator
529 |*
530 \************************************************************************/
531 
532 void E3dScene::operator=(const SdrObject& rObj)
533 {
534 	E3dObject::operator=(rObj);
535 
536 	const E3dScene& r3DObj = (const E3dScene&) rObj;
537 	aCamera			 = r3DObj.aCamera;
538 
539 	// neu ab 377:
540 	aCameraSet = r3DObj.aCameraSet;
541 	((sdr::properties::E3dSceneProperties&)GetProperties()).SetSceneItemsFromCamera();
542 
543     // SetSnapRect(r3DObj.GetSnapRect());
544 	InvalidateBoundVolume();
545 	RebuildLists();
546 	SetRectsDirty();
547 
548 	// #110988#
549 	ImpCleanup3DDepthMapper();
550 
551     // #i101941#
552     // After a Scene as model object is cloned, the used
553     // ViewContactOfE3dScene is created and partially used
554     // to calculate Bound/SnapRects, but - since quite some
555     // values are buffered at the VC - not really well
556     // initialized. It would be possible to always watch for
557     // preconditions of buffered data, but this would be expensive
558     // and would create a lot of short living data structures.
559     // It is currently better to flush that data, e.g. by using
560     // ActionChanged at the VC which will for this class
561     // flush that cached data and initalize it's valid reconstruction
562     GetViewContact().ActionChanged();
563 }
564 
565 /*************************************************************************
566 |*
567 |* Licht- und Labelobjektlisten neu aufbauen (nach Laden, Zuweisung)
568 |*
569 \************************************************************************/
570 
571 void E3dScene::RebuildLists()
572 {
573 	// zuerst loeschen
574 	SdrLayerID nCurrLayerID = GetLayer();
575 
576 	SdrObjListIter a3DIterator(maSubList, IM_FLAT);
577 
578 	// dann alle Objekte in der Szene pruefen
579 	while ( a3DIterator.IsMore() )
580 	{
581 		E3dObject* p3DObj = (E3dObject*) a3DIterator.Next();
582 		p3DObj->NbcSetLayer(nCurrLayerID);
583 		NewObjectInserted(p3DObj);
584 	}
585 }
586 
587 /*************************************************************************
588 |*
589 |* erstelle neues GeoData-Objekt
590 |*
591 \************************************************************************/
592 
593 SdrObjGeoData *E3dScene::NewGeoData() const
594 {
595 	return new E3DSceneGeoData;
596 }
597 
598 /*************************************************************************
599 |*
600 |* uebergebe aktuelle werte an das GeoData-Objekt
601 |*
602 \************************************************************************/
603 
604 void E3dScene::SaveGeoData(SdrObjGeoData& rGeo) const
605 {
606 	E3dObject::SaveGeoData (rGeo);
607 
608 	((E3DSceneGeoData &) rGeo).aCamera = aCamera;
609 }
610 
611 /*************************************************************************
612 |*
613 |* uebernehme werte aus dem GeoData-Objekt
614 |*
615 \************************************************************************/
616 
617 void E3dScene::RestGeoData(const SdrObjGeoData& rGeo)
618 {
619 	// #i94832# removed E3DModifySceneSnapRectUpdater here.
620     // It should not be needed, is already part of E3dObject::RestGeoData
621 	E3dObject::RestGeoData (rGeo);
622 	SetCamera (((E3DSceneGeoData &) rGeo).aCamera);
623 }
624 
625 /*************************************************************************
626 |*
627 |* Am StyleSheet wurde etwas geaendert, also Scene aendern
628 |*
629 \************************************************************************/
630 
631 void E3dScene::Notify(SfxBroadcaster &rBC, const SfxHint  &rHint)
632 {
633 	SetRectsDirty();
634 	E3dObject::Notify(rBC, rHint);
635 }
636 
637 /*************************************************************************
638 |*
639 \************************************************************************/
640 
641 void E3dScene::RotateScene (const Point& rRef, long /*nWink*/, double sn, double cs)
642 {
643 	Point UpperLeft, LowerRight, Center, NewCenter;
644 
645 	UpperLeft = aOutRect.TopLeft();
646 	LowerRight = aOutRect.BottomRight();
647 
648 	long dxOutRectHalf = labs(UpperLeft.X() - LowerRight.X());
649 	dxOutRectHalf /= 2;
650 	long dyOutRectHalf = labs(UpperLeft.Y() - LowerRight.Y());
651 	dyOutRectHalf /= 2;
652 
653 	Rectangle RectQuelle(aOutRect), RectZiel(aOutRect);
654 
655 	   // Nur der Mittelpunkt wird bewegt. Die Ecken werden von NbcMove bewegt.
656 	   // Fuer das Drehen wird von mir ein kartesisches Koordinatensystem verwendet in dem der Drehpunkt
657 	   // der Nullpunkt ist und die Y- Achse nach oben ansteigt, die X-Achse nach rechts.
658 	   // Dies muss bei den Y-Werten beachtet werden. (Auf dem Blatt zeigt die Y-Achse nach unten
659 	Center.X() = (UpperLeft.X() + dxOutRectHalf) - rRef.X();
660 	Center.Y() = -((UpperLeft.Y() + dyOutRectHalf) - rRef.Y());
661 				  // Ein paar Spezialfaelle zuerst abhandeln (n*90 Grad n ganzzahlig)
662     if (sn==1.0 && cs==0.0) { // 90deg
663 		NewCenter.X() = -Center.Y();
664 		NewCenter.Y() = -Center.X();
665     } else if (sn==0.0 && cs==-1.0) { // 180deg
666 		NewCenter.X() = -Center.X();
667 		NewCenter.Y() = -Center.Y();
668     } else if (sn==-1.0 && cs==0.0) { // 270deg
669 		NewCenter.X() =  Center.Y();
670 		NewCenter.Y() = -Center.X();
671 	}
672 	else          // Hier wird um einen beliebigen Winkel in mathematisch positiver Richtung gedreht!
673 	{             // xneu = x * cos(alpha) - y * sin(alpha)
674 				  // yneu = x * sin(alpha) + y * cos(alpha)
675 				  // Unten Rechts wird nicht gedreht: die Seiten von RectQuelle muessen parallel
676 				  // zu den Koordinatenachsen bleiben.
677 		NewCenter.X() = (long) (Center.X() * cs - Center.Y() * sn);
678 		NewCenter.Y() = (long) (Center.X() * sn + Center.Y() * cs);
679 	}
680 
681 	Size Differenz;
682 	Point DiffPoint = (NewCenter - Center);
683 	Differenz.Width() = DiffPoint.X();
684 	Differenz.Height() = -DiffPoint.Y();  // Man beachte dass die Y-Achse nach unten positiv gezaehlt wird.
685 	NbcMove (Differenz);  // fuehrt die eigentliche Koordinatentransformation durch.
686 }
687 
688 /*************************************************************************
689 |*
690 |* Get the name of the object (singular)
691 |*
692 \************************************************************************/
693 
694 void E3dScene::TakeObjNameSingul(XubString& rName) const
695 {
696 	rName=ImpGetResStr(STR_ObjNameSingulScene3d);
697 
698 	String aName( GetName() );
699 	if(aName.Len())
700 	{
701 		rName += sal_Unicode(' ');
702 		rName += sal_Unicode('\'');
703 		rName += aName;
704 		rName += sal_Unicode('\'');
705 	}
706 }
707 
708 /*************************************************************************
709 |*
710 |* Get the name of the object (plural)
711 |*
712 \************************************************************************/
713 
714 void E3dScene::TakeObjNamePlural(XubString& rName) const
715 {
716 	rName=ImpGetResStr(STR_ObjNamePluralScene3d);
717 }
718 
719 /*************************************************************************
720 |*
721 |* Die NbcRotate-Routine ueberlaedt die des SdrObject. Die Idee ist die Scene
722 |* drehen zu koennen und relativ zur Lage der Scene dann auch die Objekte
723 |* in der Scene
724 |*
725 \************************************************************************/
726 
727 void E3dScene::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix)
728 {
729     if(maTransformation != rMatrix)
730     {
731 		// call parent
732 		E3dObject::NbcSetTransform(rMatrix);
733 	}
734 }
735 
736 void E3dScene::SetTransform(const basegfx::B3DHomMatrix& rMatrix)
737 {
738     if(rMatrix != maTransformation)
739     {
740 		// call parent
741 		E3dObject::SetTransform(rMatrix);
742 	}
743 }
744 
745 void E3dScene::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
746 {
747 	// Also derzeit sind die Klebepunkte relativ zum aOutRect der Szene definiert. Vor dem Drehen
748 	// werden die Klebepunkte relativ zur Seite definiert. Sie nehmen an der Drehung der Szene noch nicht Teil
749 	// dafuer gibt es den
750 	SetGlueReallyAbsolute(sal_True);
751 
752 	// So dass war die Szene, ab jetzt kommen die Objekte in der Szene
753     // 3D-Objekte gibt es nur ein einziges das kann zwar mehrere Flaechen haben aber die Flaechen
754 	// muessen ja nicht zusammenhaengend sein
755 	// es ermoeglicht den Zugriff auf Kindobjekte
756 	// Ich gehe also die gesamte Liste durch und rotiere um die Z-Achse die durch den
757 	// Mittelpunkt von aOutRect geht (Satz von Steiner), also RotateZ
758 
759 	RotateScene (rRef, nWink, sn, cs);  // Rotiert die Szene
760 	double fWinkelInRad = nWink/100 * F_PI180;
761 
762 	basegfx::B3DHomMatrix aRotation;
763 	aRotation.rotate(0.0, 0.0, fWinkelInRad);
764 	NbcSetTransform(aRotation * GetTransform());
765 
766 	SetRectsDirty();    // Veranlasst eine Neuberechnung aller BoundRects
767 	NbcRotateGluePoints(rRef,nWink,sn,cs);  // Rotiert die Klebepunkte (die haben noch Koordinaten relativ
768 											// zum Urpsung des Blattes
769 	SetGlueReallyAbsolute(sal_False);  // ab jetzt sind sie wieder relativ zum BoundRect (also dem aOutRect definiert)
770 	SetRectsDirty();
771 }
772 
773 /*************************************************************************
774 |*
775 |* SnapRect berechnen
776 |*
777 \************************************************************************/
778 
779 void E3dScene::RecalcSnapRect()
780 {
781 	E3dScene* pScene = GetScene();
782 
783 	if(pScene == this)
784 	{
785 		// Szene wird als 2D-Objekt benutzt, nimm SnapRect aus der
786 		// 2D Bildschrimdarstellung
787 		Camera3D& rCam = (Camera3D&)pScene->GetCamera();
788 		maSnapRect = rCam.GetDeviceWindow();
789 	}
790 	else
791 	{
792 		// Szene ist selbst Mitglied einer anderen Szene, hole das
793 		// SnapRect als zusammengesetztes Objekt
794 		E3dObject::RecalcSnapRect();
795 	}
796 }
797 
798 /*************************************************************************
799 |*
800 |* Aufbrechen
801 |*
802 \************************************************************************/
803 
804 sal_Bool E3dScene::IsBreakObjPossible()
805 {
806 	// Szene ist aufzubrechen, wenn alle Mitglieder aufzubrechen sind
807 	SdrObjListIter a3DIterator(maSubList, IM_DEEPWITHGROUPS);
808 
809 	while ( a3DIterator.IsMore() )
810 	{
811 		E3dObject* pObj = (E3dObject*) a3DIterator.Next();
812 		DBG_ASSERT(pObj->ISA(E3dObject), "AW: In Szenen sind nur 3D-Objekte erlaubt!");
813 		if(!pObj->IsBreakObjPossible())
814 			return sal_False;
815 	}
816 
817 	return sal_True;
818 }
819 
820 basegfx::B3DVector E3dScene::GetShadowPlaneDirection() const
821 {
822 	double fWink = (double)GetShadowSlant() * F_PI180;
823 	basegfx::B3DVector aShadowPlaneDir(0.0, sin(fWink), cos(fWink));
824 	aShadowPlaneDir.normalize();
825 	return aShadowPlaneDir;
826 }
827 
828 void E3dScene::SetShadowPlaneDirection(const basegfx::B3DVector& rVec)
829 {
830 	sal_uInt16 nSceneShadowSlant = (sal_uInt16)((atan2(rVec.getY(), rVec.getZ()) / F_PI180) + 0.5);
831 	GetProperties().SetObjectItemDirect(Svx3DShadowSlantItem(nSceneShadowSlant));
832 }
833 
834 basegfx::B2DPolyPolygon E3dScene::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
835 {
836 	return TakeXorPoly();
837 }
838 
839 FASTBOOL E3dScene::BegCreate(SdrDragStat& rStat)
840 {
841 	rStat.SetOrtho4Possible();
842 	Rectangle aRect1(rStat.GetStart(), rStat.GetNow());
843 	aRect1.Justify();
844 	rStat.SetActionRect(aRect1);
845 	NbcSetSnapRect(aRect1);
846 	return sal_True;
847 }
848 
849 FASTBOOL E3dScene::MovCreate(SdrDragStat& rStat)
850 {
851 	Rectangle aRect1;
852 	rStat.TakeCreateRect(aRect1);
853 	aRect1.Justify();
854 	rStat.SetActionRect(aRect1);
855 	NbcSetSnapRect(aRect1);
856 	SetBoundRectDirty();
857 	bSnapRectDirty=sal_True;
858 	return sal_True;
859 }
860 
861 FASTBOOL E3dScene::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd)
862 {
863 	Rectangle aRect1;
864 	rStat.TakeCreateRect(aRect1);
865 	aRect1.Justify();
866 	NbcSetSnapRect(aRect1);
867 	SetRectsDirty();
868 	return (eCmd==SDRCREATE_FORCEEND || rStat.GetPointAnz()>=2);
869 }
870 
871 FASTBOOL E3dScene::BckCreate(SdrDragStat& /*rStat*/)
872 {
873 	return sal_False;
874 }
875 
876 void E3dScene::BrkCreate(SdrDragStat& /*rStat*/)
877 {
878 }
879 
880 // eof
881