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