xref: /AOO41X/main/svx/source/engine3d/scene3d.cxx (revision 707fc0d4d52eb4f69d89a98ffec6918ca5de6326)
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