Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 :
21 : #include "svx/svdstr.hrc"
22 : #include "svx/svdglob.hxx"
23 : #include <svx/svdview.hxx>
24 : #include <svx/svdattr.hxx>
25 : #include <svx/svdpage.hxx>
26 : #include <svx/svdmodel.hxx>
27 : #include "svx/svditer.hxx"
28 : #include "svx/globl3d.hxx"
29 : #include <svx/camera3d.hxx>
30 : #include <svx/scene3d.hxx>
31 : #include <svx/polysc3d.hxx>
32 : #include <svx/cube3d.hxx>
33 : #include <svx/lathe3d.hxx>
34 : #include <svx/sphere3d.hxx>
35 : #include <svx/extrud3d.hxx>
36 : #include <svx/obj3d.hxx>
37 : #include <svx/xtable.hxx>
38 : #include <svx/xflclit.hxx>
39 : #include <vcl/svapp.hxx>
40 : #include <vcl/settings.hxx>
41 : #include <svx/xlnclit.hxx>
42 : #include <svl/metitem.hxx>
43 : #include <svx/xfillit.hxx>
44 : #include <svx/xlnwtit.hxx>
45 : #include <vcl/virdev.hxx>
46 : #include <tools/poly.hxx>
47 : #include <tools/b3dtrans.hxx>
48 : #include <svx/svxids.hrc>
49 : #include <editeng/colritem.hxx>
50 : #include <svx/e3ditem.hxx>
51 : #include <svx/xlntrit.hxx>
52 : #include <svx/xfltrit.hxx>
53 : #include <svx/svdpagv.hxx>
54 : #include <vcl/gradient.hxx>
55 : #include <vcl/metaact.hxx>
56 : #include <svx/svx3ditems.hxx>
57 : #include <svl/whiter.hxx>
58 : #include <svtools/colorcfg.hxx>
59 : #include <editeng/eeitem.hxx>
60 : #include <svx/xgrscit.hxx>
61 : #include <svx/sdr/properties/e3dproperties.hxx>
62 : #include <svx/sdr/properties/e3dcompoundproperties.hxx>
63 : #include <basegfx/polygon/b3dpolypolygontools.hxx>
64 : #include <basegfx/point/b3dpoint.hxx>
65 : #include <basegfx/vector/b3dvector.hxx>
66 : #include <svx/xlndsit.hxx>
67 : #include <basegfx/matrix/b3dhommatrix.hxx>
68 : #include <basegfx/polygon/b3dpolygon.hxx>
69 : #include <basegfx/matrix/b2dhommatrix.hxx>
70 : #include <basegfx/polygon/b2dpolypolygontools.hxx>
71 : #include <basegfx/polygon/b3dpolygontools.hxx>
72 : #include <svx/helperhittest3d.hxx>
73 : #include <svx/sdr/contact/viewcontactofe3d.hxx>
74 : #include <drawinglayer/geometry/viewinformation3d.hxx>
75 : #include <com/sun/star/uno/Sequence.h>
76 : #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
77 : #include <svx/e3dsceneupdater.hxx>
78 :
79 :
80 :
81 : using namespace com::sun::star;
82 :
83 :
84 : // List for 3D-Objects
85 :
86 0 : TYPEINIT1(E3dObjList, SdrObjList);
87 :
88 0 : E3dObjList::E3dObjList(SdrModel* pNewModel, SdrPage* pNewPage, E3dObjList* pNewUpList)
89 0 : : SdrObjList(pNewModel, pNewPage, pNewUpList)
90 : {
91 0 : }
92 :
93 0 : E3dObjList::E3dObjList(const E3dObjList& rSrcList)
94 0 : : SdrObjList(rSrcList)
95 : {
96 0 : }
97 :
98 0 : E3dObjList::~E3dObjList()
99 : {
100 0 : }
101 :
102 0 : void E3dObjList::NbcInsertObject(SdrObject* pObj, sal_uIntPtr nPos, const SdrInsertReason* pReason)
103 : {
104 : // Get owner
105 : DBG_ASSERT(GetOwnerObj()->ISA(E3dObject), "Insert 3D object in parent != 3DObject");
106 :
107 : // Is it even a 3D object?
108 0 : if(pObj && pObj->ISA(E3dObject))
109 : {
110 : // Normal 3D object, insert means
111 : // call parent
112 0 : SdrObjList::NbcInsertObject(pObj, nPos, pReason);
113 : }
114 : else
115 : {
116 : // No 3D object, inserted a page in place in a scene ...
117 0 : GetOwnerObj()->GetPage()->InsertObject(pObj, nPos);
118 : }
119 0 : }
120 :
121 0 : void E3dObjList::InsertObject(SdrObject* pObj, sal_uIntPtr nPos, const SdrInsertReason* pReason)
122 : {
123 : OSL_ENSURE(GetOwnerObj()->ISA(E3dObject), "Insert 3D object in non-3D Parent");
124 :
125 : // call parent
126 0 : SdrObjList::InsertObject(pObj, nPos, pReason);
127 :
128 0 : E3dScene* pScene = ((E3dObject*)GetOwnerObj())->GetScene();
129 0 : if(pScene)
130 : {
131 0 : pScene->Cleanup3DDepthMapper();
132 : }
133 0 : }
134 :
135 0 : SdrObject* E3dObjList::NbcRemoveObject(sal_uIntPtr nObjNum)
136 : {
137 : DBG_ASSERT(GetOwnerObj()->ISA(E3dObject), "Remove 3D object from Parent != 3DObject");
138 :
139 : // call parent
140 0 : SdrObject* pRetval = SdrObjList::NbcRemoveObject(nObjNum);
141 :
142 0 : E3dScene* pScene = ((E3dObject*)GetOwnerObj())->GetScene();
143 0 : if(pScene)
144 : {
145 0 : pScene->Cleanup3DDepthMapper();
146 : }
147 :
148 0 : return pRetval;
149 : }
150 :
151 0 : SdrObject* E3dObjList::RemoveObject(sal_uIntPtr nObjNum)
152 : {
153 : OSL_ENSURE(GetOwnerObj()->ISA(E3dObject), "3D object is removed from non-3D Parent");
154 :
155 : // call parent
156 0 : SdrObject* pRetval = SdrObjList::RemoveObject(nObjNum);
157 :
158 0 : E3dScene* pScene = ((E3dObject*)GetOwnerObj())->GetScene();
159 0 : if(pScene)
160 : {
161 0 : pScene->Cleanup3DDepthMapper();
162 : }
163 :
164 0 : return pRetval;
165 : }
166 :
167 :
168 :
169 0 : sdr::properties::BaseProperties* E3dObject::CreateObjectSpecificProperties()
170 : {
171 0 : return new sdr::properties::E3dProperties(*this);
172 : }
173 :
174 :
175 :
176 0 : TYPEINIT1(E3dObject, SdrAttrObj);
177 :
178 0 : E3dObject::E3dObject()
179 : : maSubList(),
180 : maLocalBoundVol(),
181 : maTransformation(),
182 : maFullTransform(),
183 : mbTfHasChanged(true),
184 0 : mbIsSelected(false)
185 : {
186 0 : bIs3DObj = true;
187 0 : maSubList.SetOwnerObj(this);
188 0 : maSubList.SetListKind(SDROBJLIST_GROUPOBJ);
189 0 : bClosedObj = true;
190 0 : }
191 :
192 0 : E3dObject::~E3dObject()
193 : {
194 0 : }
195 :
196 0 : void E3dObject::SetSelected(bool bNew)
197 : {
198 0 : if((bool)mbIsSelected != bNew)
199 : {
200 0 : mbIsSelected = bNew;
201 : }
202 :
203 0 : for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
204 : {
205 0 : E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
206 :
207 0 : if(pCandidate)
208 : {
209 0 : pCandidate->SetSelected(bNew);
210 : }
211 : }
212 0 : }
213 :
214 : // Break, default implementations
215 :
216 0 : bool E3dObject::IsBreakObjPossible()
217 : {
218 0 : return false;
219 : }
220 :
221 0 : SdrAttrObj* E3dObject::GetBreakObj()
222 : {
223 0 : return 0L;
224 : }
225 :
226 : // SetRectsDirty must be done through the local SdrSubList
227 :
228 0 : void E3dObject::SetRectsDirty(bool bNotMyself)
229 : {
230 : // call parent
231 0 : SdrAttrObj::SetRectsDirty(bNotMyself);
232 :
233 0 : for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
234 : {
235 0 : E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
236 :
237 0 : if(pCandidate)
238 : {
239 0 : pCandidate->SetRectsDirty(bNotMyself);
240 : }
241 : }
242 0 : }
243 :
244 0 : sal_uInt32 E3dObject::GetObjInventor() const
245 : {
246 0 : return E3dInventor;
247 : }
248 :
249 0 : sal_uInt16 E3dObject::GetObjIdentifier() const
250 : {
251 0 : return E3D_OBJECT_ID;
252 : }
253 :
254 : // Determine the capabilities of the object
255 :
256 0 : void E3dObject::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
257 : {
258 0 : rInfo.bResizeFreeAllowed = true;
259 0 : rInfo.bResizePropAllowed = true;
260 0 : rInfo.bRotateFreeAllowed = true;
261 0 : rInfo.bRotate90Allowed = true;
262 0 : rInfo.bMirrorFreeAllowed = false;
263 0 : rInfo.bMirror45Allowed = false;
264 0 : rInfo.bMirror90Allowed = false;
265 0 : rInfo.bShearAllowed = false;
266 0 : rInfo.bEdgeRadiusAllowed = false;
267 0 : rInfo.bCanConvToPath = false;
268 :
269 : // no transparence for 3d objects
270 0 : rInfo.bTransparenceAllowed = false;
271 :
272 : // gradient depends on fillstyle
273 : // BM *** check if SetItem is NULL ***
274 0 : XFillStyle eFillStyle = ((XFillStyleItem&)(GetMergedItem(XATTR_FILLSTYLE))).GetValue();
275 0 : rInfo.bGradientAllowed = (eFillStyle == XFILL_GRADIENT);
276 :
277 : // Convert 3D objects in a group of polygons:
278 : // At first not only possible, because the creation of a group of
279 : // 2D polygons would be required which need to be sorted by depth,
280 : // ie at intersections be cut relative to each other. Also the texture
281 : // coorinates were an unsolved problem.
282 0 : rInfo.bCanConvToPoly = false;
283 0 : rInfo.bCanConvToContour = false;
284 0 : rInfo.bCanConvToPathLineToArea = false;
285 0 : rInfo.bCanConvToPolyLineToArea = false;
286 0 : }
287 :
288 0 : void E3dObject::NbcSetLayer(SdrLayerID nLayer)
289 : {
290 0 : SdrAttrObj::NbcSetLayer(nLayer);
291 :
292 0 : for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
293 : {
294 0 : E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
295 :
296 0 : if(pCandidate)
297 : {
298 0 : pCandidate->NbcSetLayer(nLayer);
299 : }
300 : }
301 0 : }
302 :
303 : // Set ObjList also on SubList
304 :
305 0 : void E3dObject::SetObjList(SdrObjList* pNewObjList)
306 : {
307 0 : SdrObject::SetObjList(pNewObjList);
308 0 : maSubList.SetUpList(pNewObjList);
309 0 : }
310 :
311 0 : void E3dObject::SetPage(SdrPage* pNewPage)
312 : {
313 0 : SdrAttrObj::SetPage(pNewPage);
314 0 : maSubList.SetPage(pNewPage);
315 0 : }
316 :
317 0 : void E3dObject::SetModel(SdrModel* pNewModel)
318 : {
319 0 : SdrAttrObj::SetModel(pNewModel);
320 0 : maSubList.SetModel(pNewModel);
321 0 : }
322 :
323 : // resize object, used from old 2d interfaces, e.g. in Move/Scale dialog (F4)
324 :
325 0 : void E3dObject::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
326 : {
327 : // Movement in X, Y in the eye coordinate system
328 0 : E3dScene* pScene = GetScene();
329 :
330 0 : if(pScene)
331 : {
332 : // transform pos from 2D world to 3D eye
333 0 : const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
334 0 : const drawinglayer::geometry::ViewInformation3D aViewInfo3D(rVCScene.getViewInformation3D());
335 0 : basegfx::B2DPoint aScaleCenter2D((double)rRef.X(), (double)rRef.Y());
336 0 : basegfx::B2DHomMatrix aInverseSceneTransform(rVCScene.getObjectTransformation());
337 :
338 0 : aInverseSceneTransform.invert();
339 0 : aScaleCenter2D = aInverseSceneTransform * aScaleCenter2D;
340 :
341 0 : basegfx::B3DPoint aScaleCenter3D(aScaleCenter2D.getX(), aScaleCenter2D.getY(), 0.5);
342 0 : basegfx::B3DHomMatrix aInverseViewToEye(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection());
343 :
344 0 : aInverseViewToEye.invert();
345 0 : aScaleCenter3D = aInverseViewToEye * aScaleCenter3D;
346 :
347 : // Get scale factors
348 0 : double fScaleX(xFact);
349 0 : double fScaleY(yFact);
350 :
351 : // build transform
352 0 : basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
353 0 : aInverseOrientation.invert();
354 0 : basegfx::B3DHomMatrix mFullTransform(GetFullTransform());
355 0 : basegfx::B3DHomMatrix mTrans(mFullTransform);
356 :
357 0 : mTrans *= aViewInfo3D.getOrientation();
358 0 : mTrans.translate(-aScaleCenter3D.getX(), -aScaleCenter3D.getY(), -aScaleCenter3D.getZ());
359 0 : mTrans.scale(fScaleX, fScaleY, 1.0);
360 0 : mTrans.translate(aScaleCenter3D.getX(), aScaleCenter3D.getY(), aScaleCenter3D.getZ());
361 0 : mTrans *= aInverseOrientation;
362 0 : mFullTransform.invert();
363 0 : mTrans *= mFullTransform;
364 :
365 : // Apply
366 0 : basegfx::B3DHomMatrix mObjTrans(GetTransform());
367 0 : mObjTrans *= mTrans;
368 :
369 0 : E3DModifySceneSnapRectUpdater aUpdater(this);
370 0 : SetTransform(mObjTrans);
371 : }
372 0 : }
373 :
374 :
375 : // Move object in 2D is needed when using cursor keys
376 :
377 0 : void E3dObject::NbcMove(const Size& rSize)
378 : {
379 : // Movement in X, Y in the eye coordinate system
380 0 : E3dScene* pScene = GetScene();
381 :
382 0 : if(pScene)
383 : {
384 : //Dimensions of the scene in 3D and 2D for comparison
385 0 : Rectangle aRect = pScene->GetSnapRect();
386 :
387 0 : basegfx::B3DHomMatrix mInvDispTransform;
388 0 : if(GetParentObj())
389 : {
390 0 : mInvDispTransform = GetParentObj()->GetFullTransform();
391 0 : mInvDispTransform.invert();
392 : }
393 :
394 : // BoundVolume from 3d world to 3d eye
395 0 : const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pScene->GetViewContact());
396 0 : const drawinglayer::geometry::ViewInformation3D aViewInfo3D(rVCScene.getViewInformation3D());
397 0 : basegfx::B3DRange aEyeVol(pScene->GetBoundVolume());
398 0 : aEyeVol.transform(aViewInfo3D.getOrientation());
399 :
400 : // build relative movement vector in eye coordinates
401 : basegfx::B3DPoint aMove(
402 0 : (double)rSize.Width() * aEyeVol.getWidth() / (double)aRect.GetWidth(),
403 0 : (double)-rSize.Height() * aEyeVol.getHeight() / (double)aRect.GetHeight(),
404 0 : 0.0);
405 0 : basegfx::B3DPoint aPos(0.0, 0.0, 0.0);
406 :
407 : // movement vector to local coordinates of objects' parent
408 0 : basegfx::B3DHomMatrix aInverseOrientation(aViewInfo3D.getOrientation());
409 0 : aInverseOrientation.invert();
410 0 : basegfx::B3DHomMatrix aCompleteTrans(mInvDispTransform * aInverseOrientation);
411 :
412 0 : aMove = aCompleteTrans * aMove;
413 0 : aPos = aCompleteTrans * aPos;
414 :
415 : // build transformation and apply
416 0 : basegfx::B3DHomMatrix aTranslate;
417 0 : aTranslate.translate(aMove.getX() - aPos.getX(), aMove.getY() - aPos.getY(), aMove.getZ() - aPos.getZ());
418 :
419 0 : E3DModifySceneSnapRectUpdater aUpdater(pScene);
420 0 : SetTransform(aTranslate * GetTransform());
421 : }
422 0 : }
423 :
424 : // Return the sublist, but only if it contains objects!
425 :
426 0 : SdrObjList* E3dObject::GetSubList() const
427 : {
428 0 : return &(const_cast< E3dObjList& >(maSubList));
429 : }
430 :
431 0 : void E3dObject::RecalcSnapRect()
432 : {
433 0 : maSnapRect = Rectangle();
434 :
435 0 : for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
436 : {
437 0 : E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
438 :
439 0 : if(pCandidate)
440 : {
441 0 : maSnapRect.Union(pCandidate->GetSnapRect());
442 : }
443 : }
444 0 : }
445 :
446 : // Inform the parent about insertion of a 3D object, so that the parent is able
447 : // treat the particualar objects in a special way (eg Light / Label in E3dScene)
448 :
449 0 : void E3dObject::NewObjectInserted(const E3dObject* p3DObj)
450 : {
451 0 : if(GetParentObj())
452 0 : GetParentObj()->NewObjectInserted(p3DObj);
453 0 : }
454 :
455 : // Inform parent of changes in the structure (eg by transformation), in this
456 : // process the object in which the change has occurred is returned.
457 :
458 0 : void E3dObject::StructureChanged()
459 : {
460 0 : if ( GetParentObj() )
461 : {
462 0 : GetParentObj()->InvalidateBoundVolume();
463 0 : GetParentObj()->StructureChanged();
464 : }
465 0 : }
466 :
467 0 : void E3dObject::Insert3DObj(E3dObject* p3DObj)
468 : {
469 : DBG_ASSERT(p3DObj, "Insert3DObj with NULL-pointer!");
470 0 : SdrPage* pPg = pPage;
471 0 : maSubList.InsertObject(p3DObj);
472 0 : pPage = pPg;
473 0 : InvalidateBoundVolume();
474 0 : NewObjectInserted(p3DObj);
475 0 : StructureChanged();
476 0 : }
477 :
478 0 : void E3dObject::Remove3DObj(E3dObject* p3DObj)
479 : {
480 : DBG_ASSERT(p3DObj, "Remove3DObj with NULL-pointer!");
481 :
482 0 : if(p3DObj->GetParentObj() == this)
483 : {
484 0 : SdrPage* pPg = pPage;
485 0 : maSubList.RemoveObject(p3DObj->GetOrdNum());
486 0 : pPage = pPg;
487 :
488 0 : InvalidateBoundVolume();
489 0 : StructureChanged();
490 : }
491 0 : }
492 :
493 0 : E3dObject* E3dObject::GetParentObj() const
494 : {
495 0 : E3dObject* pRetval = NULL;
496 :
497 0 : if(GetObjList()
498 0 : && GetObjList()->GetOwnerObj()
499 0 : && GetObjList()->GetOwnerObj()->ISA(E3dObject))
500 0 : pRetval = ((E3dObject*)GetObjList()->GetOwnerObj());
501 0 : return pRetval;
502 : }
503 :
504 : // Determine the top-level scene object
505 :
506 0 : E3dScene* E3dObject::GetScene() const
507 : {
508 0 : if(GetParentObj())
509 0 : return GetParentObj()->GetScene();
510 0 : return NULL;
511 : }
512 :
513 : // Calculate enclosed volume, including all child objects
514 :
515 0 : basegfx::B3DRange E3dObject::RecalcBoundVolume() const
516 : {
517 0 : basegfx::B3DRange aRetval;
518 0 : const sal_uInt32 nObjCnt(maSubList.GetObjCount());
519 :
520 0 : if(nObjCnt)
521 : {
522 0 : for(sal_uInt32 a(0); a < nObjCnt; a++)
523 : {
524 0 : const E3dObject* p3DObject = dynamic_cast< const E3dObject* >(maSubList.GetObj(a));
525 :
526 0 : if(p3DObject)
527 : {
528 0 : basegfx::B3DRange aLocalRange(p3DObject->GetBoundVolume());
529 0 : aLocalRange.transform(p3DObject->GetTransform());
530 0 : aRetval.expand(aLocalRange);
531 : }
532 : }
533 : }
534 : else
535 : {
536 : // single 3D object
537 0 : const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
538 :
539 0 : if(pVCOfE3D)
540 : {
541 : // BoundVolume is without 3D object transformation, use correct sequence
542 0 : const drawinglayer::primitive3d::Primitive3DSequence xLocalSequence(pVCOfE3D->getVIP3DSWithoutObjectTransform());
543 :
544 0 : if(xLocalSequence.hasElements())
545 : {
546 0 : const uno::Sequence< beans::PropertyValue > aEmptyParameters;
547 0 : const drawinglayer::geometry::ViewInformation3D aLocalViewInformation3D(aEmptyParameters);
548 :
549 : aRetval = drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(
550 0 : xLocalSequence, aLocalViewInformation3D);
551 0 : }
552 : }
553 : }
554 :
555 0 : return aRetval;
556 : }
557 :
558 : // Get enclosed volume and possibly recalculate it
559 :
560 0 : const basegfx::B3DRange& E3dObject::GetBoundVolume() const
561 : {
562 0 : if(maLocalBoundVol.isEmpty())
563 : {
564 0 : const_cast< E3dObject* >(this)->maLocalBoundVol = RecalcBoundVolume();
565 : }
566 :
567 0 : return maLocalBoundVol;
568 : }
569 :
570 0 : void E3dObject::InvalidateBoundVolume()
571 : {
572 0 : maLocalBoundVol.reset();
573 0 : }
574 :
575 : // Pass on the changes of the BoundVolumes to all child objects
576 :
577 0 : void E3dObject::SetBoundVolInvalid()
578 : {
579 0 : InvalidateBoundVolume();
580 :
581 0 : for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
582 : {
583 0 : E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
584 :
585 0 : if(pCandidate)
586 : {
587 0 : pCandidate->SetBoundVolInvalid();
588 : }
589 : }
590 0 : }
591 :
592 : // Pass on the changes in transformation to all child objects
593 :
594 0 : void E3dObject::SetTransformChanged()
595 : {
596 0 : InvalidateBoundVolume();
597 0 : mbTfHasChanged = true;
598 :
599 0 : for(sal_uInt32 a(0); a < maSubList.GetObjCount(); a++)
600 : {
601 0 : E3dObject* pCandidate = dynamic_cast< E3dObject* >(maSubList.GetObj(a));
602 :
603 0 : if(pCandidate)
604 : {
605 0 : pCandidate->SetTransformChanged();
606 : }
607 : }
608 0 : }
609 :
610 : // Define the hierarchical transformation over all Parents, store in
611 : // maFullTransform and return them
612 :
613 0 : const basegfx::B3DHomMatrix& E3dObject::GetFullTransform() const
614 : {
615 0 : if(mbTfHasChanged)
616 : {
617 0 : basegfx::B3DHomMatrix aNewFullTransformation(maTransformation);
618 :
619 0 : if ( GetParentObj() )
620 : {
621 0 : aNewFullTransformation = GetParentObj()->GetFullTransform() * aNewFullTransformation;
622 : }
623 :
624 0 : const_cast< E3dObject* >(this)->maFullTransform = aNewFullTransformation;
625 0 : const_cast< E3dObject* >(this)->mbTfHasChanged = false;
626 : }
627 :
628 0 : return maFullTransform;
629 : }
630 :
631 0 : const basegfx::B3DHomMatrix& E3dObject::GetTransform() const
632 : {
633 0 : return maTransformation;
634 : }
635 :
636 0 : void E3dObject::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix)
637 : {
638 0 : if(maTransformation != rMatrix)
639 : {
640 0 : maTransformation = rMatrix;
641 0 : SetTransformChanged();
642 0 : StructureChanged();
643 : }
644 0 : }
645 :
646 : // Set transformation matrix with repaint broadcast
647 :
648 0 : void E3dObject::SetTransform(const basegfx::B3DHomMatrix& rMatrix)
649 : {
650 0 : if(rMatrix != maTransformation)
651 : {
652 0 : NbcSetTransform(rMatrix);
653 0 : SetChanged();
654 0 : BroadcastObjectChange();
655 0 : if (pUserCall != NULL) pUserCall->Changed(*this, SDRUSERCALL_RESIZE, Rectangle());
656 : }
657 0 : }
658 :
659 0 : basegfx::B3DPolyPolygon E3dObject::CreateWireframe() const
660 : {
661 0 : const basegfx::B3DRange aBoundVolume(GetBoundVolume());
662 0 : return basegfx::tools::createCubePolyPolygonFromB3DRange(aBoundVolume);
663 : }
664 :
665 : // Get the name of the object (singular)
666 :
667 0 : OUString E3dObject::TakeObjNameSingul() const
668 : {
669 0 : OUStringBuffer sName(ImpGetResStr(STR_ObjNameSingulObj3d));
670 :
671 0 : OUString aName(GetName());
672 0 : if (!aName.isEmpty())
673 : {
674 0 : sName.append(' ');
675 0 : sName.append('\'');
676 0 : sName.append(aName);
677 0 : sName.append('\'');
678 : }
679 0 : return sName.makeStringAndClear();
680 : }
681 :
682 : // Get the name of the object (plural)
683 :
684 0 : OUString E3dObject::TakeObjNamePlural() const
685 : {
686 0 : return ImpGetResStr(STR_ObjNamePluralObj3d);
687 : }
688 :
689 0 : E3dObject* E3dObject::Clone() const
690 : {
691 0 : return CloneHelper< E3dObject >();
692 : }
693 :
694 0 : E3dObject& E3dObject::operator=(const E3dObject& rObj)
695 : {
696 0 : if( this == &rObj )
697 0 : return *this;
698 0 : SdrObject::operator=(rObj);
699 :
700 0 : const E3dObject& r3DObj = (const E3dObject&) rObj;
701 0 : if (r3DObj.GetSubList())
702 : {
703 0 : maSubList.CopyObjects(*r3DObj.GetSubList());
704 : }
705 :
706 : // BoundVol can be copied since also the children are copied
707 0 : maLocalBoundVol = r3DObj.maLocalBoundVol;
708 0 : maTransformation = r3DObj.maTransformation;
709 :
710 : // Because the parent may have changed, definitely redefine the total
711 : // transformation next time
712 0 : SetTransformChanged();
713 :
714 : // Copy selection status
715 0 : mbIsSelected = r3DObj.mbIsSelected;
716 0 : return *this;
717 : }
718 :
719 0 : SdrObjGeoData *E3dObject::NewGeoData() const
720 : {
721 0 : return new E3DObjGeoData;
722 : }
723 :
724 0 : void E3dObject::SaveGeoData(SdrObjGeoData& rGeo) const
725 : {
726 0 : SdrAttrObj::SaveGeoData (rGeo);
727 :
728 0 : ((E3DObjGeoData &) rGeo).maLocalBoundVol = maLocalBoundVol;
729 0 : ((E3DObjGeoData &) rGeo).maTransformation = maTransformation;
730 0 : }
731 :
732 0 : void E3dObject::RestGeoData(const SdrObjGeoData& rGeo)
733 : {
734 0 : maLocalBoundVol = ((E3DObjGeoData &) rGeo).maLocalBoundVol;
735 0 : E3DModifySceneSnapRectUpdater aUpdater(this);
736 0 : NbcSetTransform(((E3DObjGeoData &) rGeo).maTransformation);
737 0 : SdrAttrObj::RestGeoData (rGeo);
738 0 : }
739 :
740 : // 2D-rotation of a 3D-body, normally this is done by the scene itself.
741 : // This is however a correct implementation, because everything that has
742 : // happened is a rotation around the axis perpendicular to the screen and that
743 : // is regardless of how the scene has been rotated up until now.
744 :
745 0 : void E3dObject::NbcRotate(const Point& rRef, long nWink, double sn, double cs)
746 : {
747 : // So currently the glue points are defined relative to the scene aOutRect.
748 : // Before turning the glue points are defined relative to the page. They
749 : // take no part in the rotation of the scene. To ensure this, there is the
750 : // SetGlueReallyAbsolute(sal_True);
751 :
752 0 : double fWinkelInRad = nWink/100 * F_PI180;
753 :
754 0 : basegfx::B3DHomMatrix aRotateZ;
755 0 : aRotateZ.rotate(0.0, 0.0, fWinkelInRad);
756 0 : NbcSetTransform(aRotateZ * GetTransform());
757 :
758 0 : SetRectsDirty(); // This forces a recalculation of all BoundRects
759 0 : NbcRotateGluePoints(rRef,nWink,sn,cs); // Rotate the glue points (who still
760 : // have coordinates relative to the
761 : // original page)
762 0 : SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect)
763 0 : }
764 :
765 : /*************************************************************************/
766 :
767 :
768 :
769 0 : sdr::properties::BaseProperties* E3dCompoundObject::CreateObjectSpecificProperties()
770 : {
771 0 : return new sdr::properties::E3dCompoundProperties(*this);
772 : }
773 :
774 :
775 :
776 0 : TYPEINIT1(E3dCompoundObject, E3dObject);
777 :
778 0 : E3dCompoundObject::E3dCompoundObject()
779 : : E3dObject(),
780 : aMaterialAmbientColor(),
781 : bCreateNormals(false),
782 0 : bCreateTexture(false)
783 : {
784 : // Set defaults
785 0 : E3dDefaultAttributes aDefault;
786 0 : SetDefaultAttributes(aDefault);
787 0 : }
788 :
789 0 : E3dCompoundObject::E3dCompoundObject(E3dDefaultAttributes& rDefault)
790 : : E3dObject(),
791 : aMaterialAmbientColor(),
792 : bCreateNormals(false),
793 0 : bCreateTexture(false)
794 : {
795 : // Set defaults
796 0 : SetDefaultAttributes(rDefault);
797 0 : }
798 :
799 0 : void E3dCompoundObject::SetDefaultAttributes(E3dDefaultAttributes& rDefault)
800 : {
801 : // Set defaults
802 0 : aMaterialAmbientColor = rDefault.GetDefaultAmbientColor();
803 :
804 0 : bCreateNormals = rDefault.GetDefaultCreateNormals();
805 0 : bCreateTexture = rDefault.GetDefaultCreateTexture();
806 0 : }
807 :
808 0 : E3dCompoundObject::~E3dCompoundObject ()
809 : {
810 0 : }
811 :
812 0 : basegfx::B2DPolyPolygon E3dCompoundObject::TakeXorPoly() const
813 : {
814 0 : basegfx::B2DPolyPolygon aRetval;
815 0 : const uno::Sequence< beans::PropertyValue > aEmptyParameters;
816 0 : drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
817 0 : E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
818 :
819 0 : if(pRootScene)
820 : {
821 0 : const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
822 0 : const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe());
823 0 : aRetval = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon,
824 0 : aViewInfo3D.getObjectToView() * GetTransform());
825 0 : aRetval.transform(rVCScene.getObjectTransformation());
826 : }
827 :
828 0 : return aRetval;
829 : }
830 :
831 0 : sal_uInt32 E3dCompoundObject::GetHdlCount() const
832 : {
833 : // 8 corners + 1 E3dVolumeMarker (= Wireframe representation)
834 0 : return 9L;
835 : }
836 :
837 0 : void E3dCompoundObject::AddToHdlList(SdrHdlList& rHdlList) const
838 : {
839 0 : const uno::Sequence< beans::PropertyValue > aEmptyParameters;
840 0 : drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
841 0 : E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
842 :
843 0 : if(pRootScene)
844 : {
845 0 : const basegfx::B3DRange aBoundVolume(GetBoundVolume());
846 :
847 0 : if(!aBoundVolume.isEmpty())
848 : {
849 0 : const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
850 :
851 0 : for(sal_uInt32 a(0); a < 8; a++)
852 : {
853 0 : basegfx::B3DPoint aPos3D;
854 :
855 0 : switch(a)
856 : {
857 0 : case 0 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
858 0 : case 1 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
859 0 : case 2 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
860 0 : case 3 : aPos3D.setX(aBoundVolume.getMinX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
861 0 : case 4 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
862 0 : case 5 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMinY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
863 0 : case 6 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMinZ()); break;
864 0 : case 7 : aPos3D.setX(aBoundVolume.getMaxX()); aPos3D.setY(aBoundVolume.getMaxY()); aPos3D.setZ(aBoundVolume.getMaxZ()); break;
865 : }
866 :
867 : // to 3d view coor
868 0 : aPos3D *= aViewInfo3D.getObjectToView() * GetTransform();
869 :
870 : // create 2d relative scene
871 0 : basegfx::B2DPoint aPos2D(aPos3D.getX(), aPos3D.getY());
872 :
873 : // to 2d world coor
874 0 : aPos2D *= rVCScene.getObjectTransformation();
875 :
876 0 : rHdlList.AddHdl(new SdrHdl(Point(basegfx::fround(aPos2D.getX()), basegfx::fround(aPos2D.getY())), HDL_BWGT));
877 0 : }
878 : }
879 : }
880 :
881 0 : const basegfx::B2DPolyPolygon aPolyPolygon(TakeXorPoly());
882 :
883 0 : if(aPolyPolygon.count())
884 : {
885 0 : E3dVolumeMarker* pVolMarker = new E3dVolumeMarker(aPolyPolygon);
886 0 : rHdlList.AddHdl(pVolMarker);
887 0 : }
888 0 : }
889 :
890 0 : sal_uInt16 E3dCompoundObject::GetObjIdentifier() const
891 : {
892 0 : return E3D_COMPOUNDOBJ_ID;
893 : }
894 :
895 0 : void E3dCompoundObject::RecalcSnapRect()
896 : {
897 0 : const uno::Sequence< beans::PropertyValue > aEmptyParameters;
898 0 : drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
899 0 : E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
900 0 : maSnapRect = Rectangle();
901 :
902 0 : if(pRootScene)
903 : {
904 : // get VC of 3D candidate
905 0 : const sdr::contact::ViewContactOfE3d* pVCOfE3D = dynamic_cast< const sdr::contact::ViewContactOfE3d* >(&GetViewContact());
906 :
907 0 : if(pVCOfE3D)
908 : {
909 : // get 3D primitive sequence
910 0 : const drawinglayer::primitive3d::Primitive3DSequence xLocalSequence(pVCOfE3D->getViewIndependentPrimitive3DSequence());
911 :
912 0 : if(xLocalSequence.hasElements())
913 : {
914 : // get BoundVolume
915 : basegfx::B3DRange aBoundVolume(drawinglayer::primitive3d::getB3DRangeFromPrimitive3DSequence(
916 0 : xLocalSequence, aViewInfo3D));
917 :
918 : // transform bound volume to relative scene coordinates
919 0 : aBoundVolume.transform(aViewInfo3D.getObjectToView());
920 :
921 : // build 2d relative scene range
922 : basegfx::B2DRange aSnapRange(
923 : aBoundVolume.getMinX(), aBoundVolume.getMinY(),
924 0 : aBoundVolume.getMaxX(), aBoundVolume.getMaxY());
925 :
926 : // transform to 2D world coordiantes
927 0 : const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
928 0 : aSnapRange.transform(rVCScene.getObjectTransformation());
929 :
930 : // snap to integer
931 : maSnapRect = Rectangle(
932 0 : sal_Int32(floor(aSnapRange.getMinX())), sal_Int32(floor(aSnapRange.getMinY())),
933 0 : sal_Int32(ceil(aSnapRange.getMaxX())), sal_Int32(ceil(aSnapRange.getMaxY())));
934 0 : }
935 : }
936 0 : }
937 0 : }
938 :
939 0 : E3dCompoundObject* E3dCompoundObject::Clone() const
940 : {
941 0 : return CloneHelper< E3dCompoundObject >();
942 : }
943 :
944 : // convert given basegfx::B3DPolyPolygon to screen coor
945 :
946 0 : basegfx::B2DPolyPolygon E3dCompoundObject::TransformToScreenCoor(const basegfx::B3DPolyPolygon& rCandidate)
947 : {
948 0 : const uno::Sequence< beans::PropertyValue > aEmptyParameters;
949 0 : drawinglayer::geometry::ViewInformation3D aViewInfo3D(aEmptyParameters);
950 0 : E3dScene* pRootScene = fillViewInformation3DForCompoundObject(aViewInfo3D, *this);
951 0 : basegfx::B2DPolyPolygon aRetval;
952 :
953 0 : if(pRootScene)
954 : {
955 0 : aRetval = basegfx::tools::createB2DPolyPolygonFromB3DPolyPolygon(rCandidate,
956 0 : aViewInfo3D.getObjectToView() * GetTransform());
957 0 : const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(pRootScene->GetViewContact());
958 0 : aRetval.transform(rVCScene.getObjectTransformation());
959 : }
960 :
961 0 : return aRetval;
962 : }
963 :
964 0 : bool E3dCompoundObject::IsAOrdNumRemapCandidate(E3dScene*& prScene) const
965 : {
966 0 : if(GetObjList()
967 0 : && GetObjList()->GetOwnerObj()
968 0 : && GetObjList()->GetOwnerObj()->ISA(E3dScene))
969 : {
970 0 : prScene = (E3dScene*)GetObjList()->GetOwnerObj();
971 0 : return true;
972 : }
973 :
974 0 : return false;
975 : }
976 :
977 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|