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