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 <vcl/wrkwin.hxx>
22 : #include <svx/svdogrp.hxx>
23 : #include <svx/svdopath.hxx>
24 : #include <tools/shl.hxx>
25 : #include "svx/svditer.hxx"
26 : #include <svx/svdpool.hxx>
27 : #include <svx/svdorect.hxx>
28 : #include <svx/svdmodel.hxx>
29 : #include <svx/svdpagv.hxx>
30 : #include <svx/svxids.hrc>
31 : #include <editeng/colritem.hxx>
32 : #include <svx/xtable.hxx>
33 : #include <svx/svdview.hxx>
34 : #include <svx/dialogs.hrc>
35 : #include <svx/dialmgr.hxx>
36 : #include "svx/globl3d.hxx"
37 : #include <svx/obj3d.hxx>
38 : #include <svx/lathe3d.hxx>
39 : #include <svx/sphere3d.hxx>
40 : #include <svx/extrud3d.hxx>
41 : #include <svx/cube3d.hxx>
42 : #include <svx/polysc3d.hxx>
43 : #include "dragmt3d.hxx"
44 : #include <svx/view3d.hxx>
45 : #include <svx/svdundo.hxx>
46 : #include <svx/xflclit.hxx>
47 : #include <svx/xlnclit.hxx>
48 : #include <svx/svdograf.hxx>
49 : #include <svx/xbtmpit.hxx>
50 : #include <svx/xflbmtit.hxx>
51 : #include <basegfx/range/b2drange.hxx>
52 : #include <basegfx/polygon/b2dpolygontools.hxx>
53 : #include <basegfx/polygon/b2dpolypolygontools.hxx>
54 : #include <svx/xlnwtit.hxx>
55 : #include <svx/sdr/overlay/overlaypolypolygon.hxx>
56 : #include <svx/sdr/overlay/overlaymanager.hxx>
57 : #include <svx/sdrpaintwindow.hxx>
58 : #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
59 : #include <drawinglayer/geometry/viewinformation3d.hxx>
60 : #include <svx/sdrpagewindow.hxx>
61 : #include <svx/sdr/contact/displayinfo.hxx>
62 : #include <svx/sdr/contact/objectcontact.hxx>
63 : #include <svx/sdr/contact/viewobjectcontact.hxx>
64 : #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
65 : #include <svx/sdr/overlay/overlayprimitive2dsequenceobject.hxx>
66 : #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
67 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
68 : #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
69 :
70 : #define ITEMVALUE(ItemSet,Id,Cast) ((const Cast&)(ItemSet).Get(Id)).GetValue()
71 :
72 0 : TYPEINIT1(E3dView, SdrView);
73 :
74 : //////////////////////////////////////////////////////////////////////////////
75 : // Migrate Marking
76 :
77 : class Impl3DMirrorConstructOverlay
78 : {
79 : // The OverlayObjects
80 : ::sdr::overlay::OverlayObjectList maObjects;
81 :
82 : // the view
83 : const E3dView& mrView;
84 :
85 : // the object count
86 : sal_uInt32 mnCount;
87 :
88 : // the unmirrored polygons
89 : basegfx::B2DPolyPolygon* mpPolygons;
90 :
91 : // the overlay geometry from selected objects
92 : drawinglayer::primitive2d::Primitive2DSequence maFullOverlay;
93 :
94 : public:
95 : Impl3DMirrorConstructOverlay(const E3dView& rView);
96 : ~Impl3DMirrorConstructOverlay();
97 :
98 : void SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB);
99 : };
100 :
101 0 : Impl3DMirrorConstructOverlay::Impl3DMirrorConstructOverlay(const E3dView& rView)
102 : : maObjects(),
103 : mrView(rView),
104 0 : mnCount(rView.GetMarkedObjectCount()),
105 : mpPolygons(0),
106 0 : maFullOverlay()
107 : {
108 0 : if(mnCount)
109 : {
110 0 : if(mrView.IsSolidDragging())
111 : {
112 0 : SdrPageView* pPV = rView.GetSdrPageView();
113 :
114 0 : if(pPV && pPV->PageWindowCount())
115 : {
116 0 : sdr::contact::ObjectContact& rOC = pPV->GetPageWindow(0)->GetObjectContact();
117 0 : sdr::contact::DisplayInfo aDisplayInfo;
118 :
119 : // Do not use the last ViewPort set at the OC at the last ProcessDisplay()
120 0 : rOC.resetViewPort();
121 :
122 0 : for(sal_uInt32 a(0);a < mnCount;a++)
123 : {
124 0 : SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
125 :
126 0 : if(pObject)
127 : {
128 0 : sdr::contact::ViewContact& rVC = pObject->GetViewContact();
129 0 : sdr::contact::ViewObjectContact& rVOC = rVC.GetViewObjectContact(rOC);
130 :
131 0 : const drawinglayer::primitive2d::Primitive2DSequence aNewSequence(rVOC.getPrimitive2DSequenceHierarchy(aDisplayInfo));
132 0 : drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(maFullOverlay, aNewSequence);
133 : }
134 0 : }
135 : }
136 : }
137 : else
138 : {
139 0 : mpPolygons = new basegfx::B2DPolyPolygon[mnCount];
140 :
141 0 : for(sal_uInt32 a(0); a < mnCount; a++)
142 : {
143 0 : SdrObject* pObject = mrView.GetMarkedObjectByIndex(a);
144 0 : mpPolygons[mnCount - (a + 1)] = pObject->TakeXorPoly();
145 : }
146 : }
147 : }
148 0 : }
149 :
150 0 : Impl3DMirrorConstructOverlay::~Impl3DMirrorConstructOverlay()
151 : {
152 : // The OverlayObjects are cleared using the destructor of OverlayObjectList.
153 : // That destructor calls clear() at the list which removes all objects from the
154 : // OverlayManager and deletes them.
155 0 : if(!mrView.IsSolidDragging())
156 : {
157 0 : delete[] mpPolygons;
158 : }
159 0 : }
160 :
161 0 : void Impl3DMirrorConstructOverlay::SetMirrorAxis(Point aMirrorAxisA, Point aMirrorAxisB)
162 : {
163 : // get rid of old overlay objects
164 0 : maObjects.clear();
165 :
166 : // create new ones
167 0 : for(sal_uInt32 a(0); a < mrView.PaintWindowCount(); a++)
168 : {
169 0 : SdrPaintWindow* pCandidate = mrView.GetPaintWindow(a);
170 0 : rtl::Reference< ::sdr::overlay::OverlayManager > xTargetOverlay = pCandidate->GetOverlayManager();
171 :
172 0 : if(xTargetOverlay.is())
173 : {
174 : // buld transfoprmation: translate and rotate so that given edge is
175 : // on x axis, them mirror in y and translate back
176 0 : const basegfx::B2DVector aEdge(aMirrorAxisB.X() - aMirrorAxisA.X(), aMirrorAxisB.Y() - aMirrorAxisA.Y());
177 : basegfx::B2DHomMatrix aMatrixTransform(basegfx::tools::createTranslateB2DHomMatrix(
178 0 : -aMirrorAxisA.X(), -aMirrorAxisA.Y()));
179 0 : aMatrixTransform.rotate(-atan2(aEdge.getY(), aEdge.getX()));
180 0 : aMatrixTransform.scale(1.0, -1.0);
181 0 : aMatrixTransform.rotate(atan2(aEdge.getY(), aEdge.getX()));
182 0 : aMatrixTransform.translate(aMirrorAxisA.X(), aMirrorAxisA.Y());
183 :
184 0 : if(mrView.IsSolidDragging())
185 : {
186 0 : if(maFullOverlay.hasElements())
187 : {
188 0 : drawinglayer::primitive2d::Primitive2DSequence aContent(maFullOverlay);
189 :
190 0 : if(!aMatrixTransform.isIdentity())
191 : {
192 : // embed in transformation group
193 0 : drawinglayer::primitive2d::Primitive2DReference aTransformPrimitive2D(new drawinglayer::primitive2d::TransformPrimitive2D(aMatrixTransform, aContent));
194 0 : aContent = drawinglayer::primitive2d::Primitive2DSequence(&aTransformPrimitive2D, 1);
195 : }
196 :
197 : // if we have full overlay from selected objects, embed with 50% transparence, the
198 : // transformation is added to the OverlayPrimitive2DSequenceObject
199 0 : drawinglayer::primitive2d::Primitive2DReference aUnifiedTransparencePrimitive2D(new drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(aContent, 0.5));
200 0 : aContent = drawinglayer::primitive2d::Primitive2DSequence(&aUnifiedTransparencePrimitive2D, 1);
201 :
202 0 : sdr::overlay::OverlayPrimitive2DSequenceObject* pNew = new sdr::overlay::OverlayPrimitive2DSequenceObject(aContent);
203 :
204 0 : xTargetOverlay->add(*pNew);
205 0 : maObjects.append(*pNew);
206 : }
207 : }
208 : else
209 : {
210 0 : for(sal_uInt32 b(0); b < mnCount; b++)
211 : {
212 : // apply to polygon
213 0 : basegfx::B2DPolyPolygon aPolyPolygon(mpPolygons[b]);
214 0 : aPolyPolygon.transform(aMatrixTransform);
215 :
216 0 : ::sdr::overlay::OverlayPolyPolygonStriped* pNew = new ::sdr::overlay::OverlayPolyPolygonStriped(aPolyPolygon);
217 0 : xTargetOverlay->add(*pNew);
218 0 : maObjects.append(*pNew);
219 0 : }
220 0 : }
221 : }
222 0 : }
223 0 : }
224 :
225 252 : E3dView::E3dView(SdrModel* pModel, OutputDevice* pOut) :
226 252 : SdrView(pModel, pOut)
227 : {
228 252 : InitView ();
229 252 : }
230 :
231 : // DrawMarkedObj overloaded, since possibly only a single 3D object is to be
232 : // drawn
233 :
234 13 : void E3dView::DrawMarkedObj(OutputDevice& rOut) const
235 : {
236 : // Does 3D objects exist which scenes are not selected?
237 13 : sal_Bool bSpecialHandling = sal_False;
238 13 : E3dScene *pScene = NULL;
239 :
240 13 : long nCnt = GetMarkedObjectCount();
241 26 : for(long nObjs = 0;nObjs < nCnt;nObjs++)
242 : {
243 13 : SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
244 13 : if(pObj && pObj->ISA(E3dCompoundObject))
245 : {
246 : // related scene
247 0 : pScene = ((E3dCompoundObject*)pObj)->GetScene();
248 0 : if(pScene && !IsObjMarked(pScene))
249 0 : bSpecialHandling = sal_True;
250 : }
251 : // Reset all selection flags
252 13 : if(pObj && pObj->ISA(E3dObject))
253 : {
254 0 : pScene = ((E3dObject*)pObj)->GetScene();
255 0 : if(pScene)
256 0 : pScene->SetSelected(sal_False);
257 : }
258 : }
259 :
260 13 : if(bSpecialHandling)
261 : {
262 : // Set selection flag to "not selected" for scenes related to all 3D
263 : // objects
264 : long nObjs;
265 0 : for(nObjs = 0;nObjs < nCnt;nObjs++)
266 : {
267 0 : SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
268 0 : if(pObj && pObj->ISA(E3dCompoundObject))
269 : {
270 : // relatated scene
271 0 : pScene = ((E3dCompoundObject*)pObj)->GetScene();
272 0 : if(pScene)
273 0 : pScene->SetSelected(sal_False);
274 : }
275 : }
276 :
277 0 : for(nObjs = 0;nObjs < nCnt;nObjs++)
278 : {
279 0 : SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
280 0 : if(pObj && pObj->ISA(E3dObject))
281 : {
282 : // Select object
283 0 : E3dObject* p3DObj = (E3dObject*)pObj;
284 0 : p3DObj->SetSelected(sal_True);
285 0 : pScene = p3DObj->GetScene();
286 : }
287 : }
288 :
289 0 : if(pScene)
290 : {
291 : // code from parent
292 0 : SortMarkedObjects();
293 :
294 0 : pScene->SetDrawOnlySelected(sal_True);
295 0 : pScene->SingleObjectPainter(rOut);
296 0 : pScene->SetDrawOnlySelected(sal_False);
297 : }
298 :
299 : // Reset selection flag
300 0 : for(nObjs = 0;nObjs < nCnt;nObjs++)
301 : {
302 0 : SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
303 0 : if(pObj && pObj->ISA(E3dCompoundObject))
304 : {
305 : // releated scene
306 0 : pScene = ((E3dCompoundObject*)pObj)->GetScene();
307 0 : if(pScene)
308 0 : pScene->SetSelected(sal_False);
309 : }
310 : }
311 : }
312 : else
313 : {
314 : // call parent
315 13 : SdrExchangeView::DrawMarkedObj(rOut);
316 : }
317 13 : }
318 :
319 : // Get overloaded model, since in some 3D objects an additional scene
320 : // must be pushed in
321 :
322 0 : SdrModel* E3dView::GetMarkedObjModel() const
323 : {
324 : // Does 3D objects exist which scenes are not selected?
325 0 : bool bSpecialHandling(false);
326 0 : const sal_uInt32 nCount(GetMarkedObjectCount());
327 0 : sal_uInt32 nObjs(0);
328 0 : E3dScene *pScene = 0;
329 :
330 0 : for(nObjs = 0; nObjs < nCount; nObjs++)
331 : {
332 0 : const SdrObject* pObj = GetMarkedObjectByIndex(nObjs);
333 :
334 0 : if(!bSpecialHandling && pObj && pObj->ISA(E3dCompoundObject))
335 : {
336 : // if the object is selected, but it's scene not,
337 : // we need special handling
338 0 : pScene = ((E3dCompoundObject*)pObj)->GetScene();
339 :
340 0 : if(pScene && !IsObjMarked(pScene))
341 : {
342 0 : bSpecialHandling = true;
343 : }
344 : }
345 :
346 0 : if(pObj && pObj->ISA(E3dObject))
347 : {
348 : // reset all selection flags at 3D objects
349 0 : pScene = ((E3dObject*)pObj)->GetScene();
350 :
351 0 : if(pScene)
352 : {
353 0 : pScene->SetSelected(false);
354 : }
355 : }
356 : }
357 :
358 0 : if(!bSpecialHandling)
359 : {
360 : // call parent
361 0 : return SdrView::GetMarkedObjModel();
362 : }
363 :
364 0 : SdrModel* pNewModel = 0;
365 0 : Rectangle aSelectedSnapRect;
366 :
367 : // set 3d selection flags at all directly selected objects
368 : // and collect SnapRect of selected objects
369 0 : for(nObjs = 0; nObjs < nCount; nObjs++)
370 : {
371 0 : SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
372 :
373 0 : if(pObj && pObj->ISA(E3dCompoundObject))
374 : {
375 : // mark object, but not scenes
376 0 : E3dCompoundObject* p3DObj = (E3dCompoundObject*)pObj;
377 0 : p3DObj->SetSelected(true);
378 0 : aSelectedSnapRect.Union(p3DObj->GetSnapRect());
379 : }
380 : }
381 :
382 : // create new mark list which contains all indirectly selected3d
383 : // scenes as selected objects
384 0 : SdrMarkList aOldML(GetMarkedObjectList());
385 0 : SdrMarkList aNewML;
386 0 : SdrMarkList& rCurrentMarkList = ((E3dView*)this)->GetMarkedObjectListWriteAccess();
387 0 : rCurrentMarkList = aNewML;
388 :
389 0 : for(nObjs = 0; nObjs < nCount; nObjs++)
390 : {
391 0 : SdrObject *pObj = aOldML.GetMark(nObjs)->GetMarkedSdrObj();
392 :
393 0 : if(pObj && pObj->ISA(E3dObject))
394 : {
395 0 : pScene = ((E3dObject*)pObj)->GetScene();
396 :
397 0 : if(pScene && !IsObjMarked(pScene) && GetSdrPageView())
398 : {
399 0 : ((E3dView*)this)->MarkObj(pScene, GetSdrPageView(), sal_False, sal_True);
400 : }
401 : }
402 : }
403 :
404 : // call parent. This will copy all scenes and the selection flags at the 3d objectss. So
405 : // it will be possible to delete all non-selected 3d objects from the cloned 3d scenes
406 0 : pNewModel = SdrView::GetMarkedObjModel();
407 :
408 0 : if(pNewModel)
409 : {
410 0 : for(sal_uInt16 nPg(0); nPg < pNewModel->GetPageCount(); nPg++)
411 : {
412 0 : const SdrPage* pSrcPg=pNewModel->GetPage(nPg);
413 0 : const sal_uInt32 nObAnz(pSrcPg->GetObjCount());
414 :
415 0 : for(sal_uInt32 nOb(0); nOb < nObAnz; nOb++)
416 : {
417 0 : const SdrObject* pSrcOb=pSrcPg->GetObj(nOb);
418 :
419 0 : if(pSrcOb->ISA(E3dScene))
420 : {
421 0 : pScene = (E3dScene*)pSrcOb;
422 :
423 : // delete all not intentionally cloned 3d objects
424 0 : pScene->removeAllNonSelectedObjects();
425 :
426 : // reset select flags and set SnapRect of all selected objects
427 0 : pScene->SetSelected(false);
428 0 : pScene->SetSnapRect(aSelectedSnapRect);
429 : }
430 : }
431 : }
432 : }
433 :
434 : // restore old selection
435 0 : rCurrentMarkList = aOldML;
436 :
437 0 : return pNewModel;
438 : }
439 :
440 : // When pasting objects have to integrated if a scene is inserted, but
441 : // not the scene itself
442 :
443 0 : sal_Bool E3dView::Paste(const SdrModel& rMod, const Point& rPos, SdrObjList* pLst, sal_uInt32 nOptions)
444 : {
445 0 : sal_Bool bRetval = sal_False;
446 :
447 : // Get list
448 0 : Point aPos(rPos);
449 0 : SdrObjList* pDstList = pLst;
450 0 : ImpGetPasteObjList(aPos, pDstList);
451 :
452 0 : if(!pDstList)
453 0 : return sal_False;
454 :
455 : // Get owner of the list
456 0 : SdrObject* pOwner = pDstList->GetOwnerObj();
457 0 : if(pOwner && pOwner->ISA(E3dScene))
458 : {
459 0 : E3dScene* pDstScene = (E3dScene*)pOwner;
460 0 : BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_EXCHANGE_PASTE));
461 :
462 : // Copy all objects from E3dScenes and insert them directly
463 0 : for(sal_uInt16 nPg(0); nPg < rMod.GetPageCount(); nPg++)
464 : {
465 0 : const SdrPage* pSrcPg=rMod.GetPage(nPg);
466 0 : sal_uInt32 nObAnz(pSrcPg->GetObjCount());
467 :
468 : // calculate offset for paste
469 0 : Rectangle aR = pSrcPg->GetAllObjBoundRect();
470 0 : Point aDist(aPos - aR.Center());
471 :
472 : // Insert sub-objects for scenes
473 0 : for(sal_uInt32 nOb(0); nOb < nObAnz; nOb++)
474 : {
475 0 : const SdrObject* pSrcOb = pSrcPg->GetObj(nOb);
476 0 : if(pSrcOb->ISA(E3dScene))
477 : {
478 0 : E3dScene* pSrcScene = (E3dScene*)pSrcOb;
479 0 : ImpCloneAll3DObjectsToDestScene(pSrcScene, pDstScene, aDist);
480 : }
481 : }
482 : }
483 0 : EndUndo();
484 : }
485 : else
486 : {
487 : // call parent
488 0 : bRetval = SdrView::Paste(rMod, rPos, pLst, nOptions);
489 : }
490 :
491 0 : return bRetval;
492 : }
493 :
494 : // Service routine used from local Clone() and from SdrCreateView::EndCreateObj(...)
495 0 : sal_Bool E3dView::ImpCloneAll3DObjectsToDestScene(E3dScene* pSrcScene, E3dScene* pDstScene, Point /*aOffset*/)
496 : {
497 0 : sal_Bool bRetval(sal_False);
498 :
499 0 : if(pSrcScene && pDstScene)
500 : {
501 0 : const sdr::contact::ViewContactOfE3dScene& rVCSceneDst = static_cast< sdr::contact::ViewContactOfE3dScene& >(pDstScene->GetViewContact());
502 0 : const drawinglayer::geometry::ViewInformation3D aViewInfo3DDst(rVCSceneDst.getViewInformation3D());
503 0 : const sdr::contact::ViewContactOfE3dScene& rVCSceneSrc = static_cast< sdr::contact::ViewContactOfE3dScene& >(pSrcScene->GetViewContact());
504 0 : const drawinglayer::geometry::ViewInformation3D aViewInfo3DSrc(rVCSceneSrc.getViewInformation3D());
505 :
506 0 : for(sal_uInt32 i(0); i < pSrcScene->GetSubList()->GetObjCount(); i++)
507 : {
508 0 : E3dCompoundObject* pCompoundObj = dynamic_cast< E3dCompoundObject* >(pSrcScene->GetSubList()->GetObj(i));
509 :
510 0 : if(pCompoundObj)
511 : {
512 0 : E3dCompoundObject* pNewCompoundObj = dynamic_cast< E3dCompoundObject* >(pCompoundObj->Clone());
513 :
514 0 : if(pNewCompoundObj)
515 : {
516 : // get dest scene's current range in 3D world coordinates
517 0 : const basegfx::B3DHomMatrix aSceneToWorldTrans(pDstScene->GetFullTransform());
518 0 : basegfx::B3DRange aSceneRange(pDstScene->GetBoundVolume());
519 0 : aSceneRange.transform(aSceneToWorldTrans);
520 :
521 : // get new object's implied object transformation
522 0 : const basegfx::B3DHomMatrix aNewObjectTrans(pNewCompoundObj->GetTransform());
523 :
524 : // get new object's range in 3D world coordinates in dest scene
525 : // as if it were already added
526 0 : const basegfx::B3DHomMatrix aObjectToWorldTrans(aSceneToWorldTrans * aNewObjectTrans);
527 0 : basegfx::B3DRange aObjectRange(pNewCompoundObj->GetBoundVolume());
528 0 : aObjectRange.transform(aObjectToWorldTrans);
529 :
530 : // get scale adaption
531 0 : const basegfx::B3DVector aSceneScale(aSceneRange.getRange());
532 0 : const basegfx::B3DVector aObjectScale(aObjectRange.getRange());
533 0 : double fScale(1.0);
534 :
535 : // if new object's size in X,Y or Z is bigger that 80% of dest scene, adapt scale
536 : // to not change the scene by the inserted object
537 0 : const double fSizeFactor(0.5);
538 :
539 0 : if(aObjectScale.getX() * fScale > aSceneScale.getX() * fSizeFactor)
540 : {
541 0 : const double fObjSize(aObjectScale.getX() * fScale);
542 0 : const double fFactor((aSceneScale.getX() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
543 0 : fScale *= fFactor;
544 : }
545 :
546 0 : if(aObjectScale.getY() * fScale > aSceneScale.getY() * fSizeFactor)
547 : {
548 0 : const double fObjSize(aObjectScale.getY() * fScale);
549 0 : const double fFactor((aSceneScale.getY() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
550 0 : fScale *= fFactor;
551 : }
552 :
553 0 : if(aObjectScale.getZ() * fScale > aSceneScale.getZ() * fSizeFactor)
554 : {
555 0 : const double fObjSize(aObjectScale.getZ() * fScale);
556 0 : const double fFactor((aSceneScale.getZ() * fSizeFactor) / (basegfx::fTools::equalZero(fObjSize) ? 1.0 : fObjSize));
557 0 : fScale *= fFactor;
558 : }
559 :
560 : // get translation adaption
561 0 : const basegfx::B3DPoint aSceneCenter(aSceneRange.getCenter());
562 0 : const basegfx::B3DPoint aObjectCenter(aObjectRange.getCenter());
563 :
564 : // build full modification transform. The object's transformation
565 : // shall be modified, so start at object coordinates; transform to 3d world coor
566 0 : basegfx::B3DHomMatrix aModifyingTransform(aObjectToWorldTrans);
567 :
568 : // translate to absolute center in 3d world coor
569 0 : aModifyingTransform.translate(-aObjectCenter.getX(), -aObjectCenter.getY(), -aObjectCenter.getZ());
570 :
571 : // scale to dest size in 3d world coor
572 0 : aModifyingTransform.scale(fScale, fScale, fScale);
573 :
574 : // translate to dest scene center in 3d world coor
575 0 : aModifyingTransform.translate(aSceneCenter.getX(), aSceneCenter.getY(), aSceneCenter.getZ());
576 :
577 : // transform from 3d world to dest object coordinates
578 0 : basegfx::B3DHomMatrix aWorldToObject(aObjectToWorldTrans);
579 0 : aWorldToObject.invert();
580 0 : aModifyingTransform = aWorldToObject * aModifyingTransform;
581 :
582 : // correct implied object transform by applying changing one in object coor
583 0 : pNewCompoundObj->SetTransform(aModifyingTransform * aNewObjectTrans);
584 :
585 : // fill and insert new object
586 0 : pNewCompoundObj->SetModel(pDstScene->GetModel());
587 0 : pNewCompoundObj->SetPage(pDstScene->GetPage());
588 0 : pNewCompoundObj->NbcSetLayer(pCompoundObj->GetLayer());
589 0 : pNewCompoundObj->NbcSetStyleSheet(pCompoundObj->GetStyleSheet(), sal_True);
590 0 : pDstScene->Insert3DObj(pNewCompoundObj);
591 0 : bRetval = sal_True;
592 :
593 : // Create undo
594 0 : if( GetModel()->IsUndoEnabled() )
595 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoNewObject(*pNewCompoundObj));
596 : }
597 : }
598 0 : }
599 : }
600 :
601 0 : return bRetval;
602 : }
603 :
604 0 : sal_Bool E3dView::IsConvertTo3DObjPossible() const
605 : {
606 0 : sal_Bool bAny3D(sal_False);
607 0 : sal_Bool bGroupSelected(sal_False);
608 0 : sal_Bool bRetval(sal_True);
609 :
610 0 : for(sal_uInt32 a=0;!bAny3D && a<GetMarkedObjectCount();a++)
611 : {
612 0 : SdrObject *pObj = GetMarkedObjectByIndex(a);
613 0 : if(pObj)
614 : {
615 0 : ImpIsConvertTo3DPossible(pObj, bAny3D, bGroupSelected);
616 : }
617 : }
618 :
619 0 : bRetval = !bAny3D
620 : && (
621 0 : IsConvertToPolyObjPossible(sal_False)
622 0 : || IsConvertToPathObjPossible(sal_False)
623 0 : || IsImportMtfPossible());
624 0 : return bRetval;
625 : }
626 :
627 0 : void E3dView::ImpIsConvertTo3DPossible(SdrObject* pObj, sal_Bool& rAny3D,
628 : sal_Bool& rGroupSelected) const
629 : {
630 0 : if(pObj)
631 : {
632 0 : if(pObj->ISA(E3dObject))
633 : {
634 0 : rAny3D = sal_True;
635 : }
636 : else
637 : {
638 0 : if(pObj->IsGroupObject())
639 : {
640 0 : SdrObjListIter aIter(*pObj, IM_DEEPNOGROUPS);
641 0 : while(aIter.IsMore())
642 : {
643 0 : SdrObject* pNewObj = aIter.Next();
644 0 : ImpIsConvertTo3DPossible(pNewObj, rAny3D, rGroupSelected);
645 : }
646 0 : rGroupSelected = sal_True;
647 : }
648 : }
649 : }
650 0 : }
651 :
652 : #include <editeng/eeitem.hxx>
653 :
654 0 : void E3dView::ImpChangeSomeAttributesFor3DConversion(SdrObject* pObj)
655 : {
656 0 : if(pObj->ISA(SdrTextObj))
657 : {
658 0 : const SfxItemSet& rSet = pObj->GetMergedItemSet();
659 0 : const SvxColorItem& rTextColorItem = (const SvxColorItem&)rSet.Get(EE_CHAR_COLOR);
660 0 : if(rTextColorItem.GetValue() == RGB_Color(COL_BLACK))
661 : {
662 : //For black text objects, the color set to gray
663 0 : if(pObj->GetPage())
664 : {
665 : // if black is only default attribute from
666 : // pattern set it hard so that it is used in undo.
667 0 : pObj->SetMergedItem(SvxColorItem(RGB_Color(COL_BLACK), EE_CHAR_COLOR));
668 :
669 : // add undo now
670 0 : if( GetModel()->IsUndoEnabled() )
671 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj, false, false));
672 : }
673 :
674 0 : pObj->SetMergedItem(SvxColorItem(RGB_Color(COL_GRAY), EE_CHAR_COLOR));
675 : }
676 : }
677 0 : }
678 :
679 0 : void E3dView::ImpChangeSomeAttributesFor3DConversion2(SdrObject* pObj)
680 : {
681 0 : if(pObj->ISA(SdrPathObj))
682 : {
683 0 : const SfxItemSet& rSet = pObj->GetMergedItemSet();
684 0 : sal_Int32 nLineWidth = ((const XLineWidthItem&)(rSet.Get(XATTR_LINEWIDTH))).GetValue();
685 0 : XLineStyle eLineStyle = (XLineStyle)((const XLineStyleItem&)rSet.Get(XATTR_LINESTYLE)).GetValue();
686 0 : XFillStyle eFillStyle = ITEMVALUE(rSet, XATTR_FILLSTYLE, XFillStyleItem);
687 :
688 0 : if(((SdrPathObj*)pObj)->IsClosed()
689 : && eLineStyle == XLINE_SOLID
690 : && !nLineWidth
691 : && eFillStyle != XFILL_NONE)
692 : {
693 0 : if(pObj->GetPage() && GetModel()->IsUndoEnabled() )
694 0 : AddUndo(GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj, false, false));
695 0 : pObj->SetMergedItem(XLineStyleItem(XLINE_NONE));
696 0 : pObj->SetMergedItem(XLineWidthItem(0L));
697 : }
698 : }
699 0 : }
700 :
701 0 : void E3dView::ImpCreateSingle3DObjectFlat(E3dScene* pScene, SdrObject* pObj, sal_Bool bExtrude, double fDepth, basegfx::B2DHomMatrix& rLatheMat)
702 : {
703 : // Single PathObject, transform this
704 0 : SdrPathObj* pPath = PTR_CAST(SdrPathObj, pObj);
705 :
706 0 : if(pPath)
707 : {
708 0 : E3dDefaultAttributes aDefault = Get3DDefaultAttributes();
709 0 : if(bExtrude)
710 0 : aDefault.SetDefaultExtrudeCharacterMode(sal_True);
711 : else
712 0 : aDefault.SetDefaultLatheCharacterMode(sal_True);
713 :
714 : // Get Itemset of the original object
715 0 : SfxItemSet aSet(pObj->GetMergedItemSet());
716 :
717 0 : XFillStyle eFillStyle = ITEMVALUE(aSet, XATTR_FILLSTYLE, XFillStyleItem);
718 :
719 : // line style turned off
720 0 : aSet.Put(XLineStyleItem(XLINE_NONE));
721 :
722 : //Determining if FILL_Attribut is set.
723 0 : if(!pPath->IsClosed() || eFillStyle == XFILL_NONE)
724 : {
725 : // This SdrPathObj is not filled, leave the front and rear face out.
726 : // Moreover, a two-sided representation necessary.
727 0 : aDefault.SetDefaultExtrudeCloseFront(sal_False);
728 0 : aDefault.SetDefaultExtrudeCloseBack(sal_False);
729 :
730 0 : aSet.Put(Svx3DDoubleSidedItem(sal_True));
731 :
732 : // Set fill attribute
733 0 : aSet.Put(XFillStyleItem(XFILL_SOLID));
734 :
735 : // Fill color must be the color line, because the object was
736 : // previously just a line
737 0 : Color aColorLine = ((const XLineColorItem&)(aSet.Get(XATTR_LINECOLOR))).GetColorValue();
738 0 : aSet.Put(XFillColorItem(String(), aColorLine));
739 : }
740 :
741 : // Create a new extrude object
742 0 : E3dObject* p3DObj = NULL;
743 0 : if(bExtrude)
744 : {
745 0 : p3DObj = new E3dExtrudeObj(aDefault, pPath->GetPathPoly(), fDepth);
746 : }
747 : else
748 : {
749 0 : basegfx::B2DPolyPolygon aPolyPoly2D(pPath->GetPathPoly());
750 0 : aPolyPoly2D.transform(rLatheMat);
751 0 : p3DObj = new E3dLatheObj(aDefault, aPolyPoly2D);
752 : }
753 :
754 : // Set attribute
755 0 : if(p3DObj)
756 : {
757 0 : p3DObj->NbcSetLayer(pObj->GetLayer());
758 :
759 0 : p3DObj->SetMergedItemSet(aSet);
760 :
761 0 : p3DObj->NbcSetStyleSheet(pObj->GetStyleSheet(), sal_True);
762 :
763 : // Insert a new extrude object
764 0 : pScene->Insert3DObj(p3DObj);
765 0 : }
766 : }
767 0 : }
768 :
769 0 : void E3dView::ImpCreate3DObject(E3dScene* pScene, SdrObject* pObj, sal_Bool bExtrude, double fDepth, basegfx::B2DHomMatrix& rLatheMat)
770 : {
771 0 : if(pObj)
772 : {
773 : // change text color attribute for not so dark colors
774 0 : if(pObj->IsGroupObject())
775 : {
776 0 : SdrObjListIter aIter(*pObj, IM_DEEPWITHGROUPS);
777 0 : while(aIter.IsMore())
778 : {
779 0 : SdrObject* pGroupMember = aIter.Next();
780 0 : ImpChangeSomeAttributesFor3DConversion(pGroupMember);
781 0 : }
782 : }
783 : else
784 0 : ImpChangeSomeAttributesFor3DConversion(pObj);
785 :
786 : // convert completely to path objects
787 0 : SdrObject* pNewObj1 = pObj->ConvertToPolyObj(sal_False, sal_False);
788 :
789 0 : if(pNewObj1)
790 : {
791 : // change text color attribute for not so dark colors
792 0 : if(pNewObj1->IsGroupObject())
793 : {
794 0 : SdrObjListIter aIter(*pNewObj1, IM_DEEPWITHGROUPS);
795 0 : while(aIter.IsMore())
796 : {
797 0 : SdrObject* pGroupMember = aIter.Next();
798 0 : ImpChangeSomeAttributesFor3DConversion2(pGroupMember);
799 0 : }
800 : }
801 : else
802 0 : ImpChangeSomeAttributesFor3DConversion2(pNewObj1);
803 :
804 : // convert completely to path objects
805 0 : SdrObject* pNewObj2 = pObj->ConvertToContourObj(pNewObj1, sal_True);
806 :
807 0 : if(pNewObj2)
808 : {
809 : // add all to flat scene
810 0 : if(pNewObj2->IsGroupObject())
811 : {
812 0 : SdrObjListIter aIter(*pNewObj2, IM_DEEPWITHGROUPS);
813 0 : while(aIter.IsMore())
814 : {
815 0 : SdrObject* pGroupMember = aIter.Next();
816 0 : ImpCreateSingle3DObjectFlat(pScene, pGroupMember, bExtrude, fDepth, rLatheMat);
817 0 : }
818 : }
819 : else
820 0 : ImpCreateSingle3DObjectFlat(pScene, pNewObj2, bExtrude, fDepth, rLatheMat);
821 :
822 : // delete object in between
823 0 : if(pNewObj2 != pObj && pNewObj2 != pNewObj1 && pNewObj2)
824 0 : SdrObject::Free( pNewObj2 );
825 : }
826 :
827 : // delete object in between
828 0 : if(pNewObj1 != pObj && pNewObj1)
829 0 : SdrObject::Free( pNewObj1 );
830 : }
831 : }
832 0 : }
833 :
834 0 : void E3dView::ConvertMarkedObjTo3D(sal_Bool bExtrude, basegfx::B2DPoint aPnt1, basegfx::B2DPoint aPnt2)
835 : {
836 0 : if(AreObjectsMarked())
837 : {
838 : // Create undo
839 0 : if(bExtrude)
840 0 : BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_EXTRUDE));
841 : else
842 0 : BegUndo(SVX_RESSTR(RID_SVX_3D_UNDO_LATHE));
843 :
844 : // Create a new scene for the created 3D object
845 0 : E3dScene* pScene = new E3dPolyScene(Get3DDefaultAttributes());
846 :
847 : // Determine rectangle and possibly correct it
848 0 : Rectangle aRect = GetAllMarkedRect();
849 0 : if(aRect.GetWidth() <= 1)
850 0 : aRect.SetSize(Size(500, aRect.GetHeight()));
851 0 : if(aRect.GetHeight() <= 1)
852 0 : aRect.SetSize(Size(aRect.GetWidth(), 500));
853 :
854 : // Determine the depth relative to the size of the selection
855 0 : double fDepth = 0.0;
856 0 : double fRot3D = 0.0;
857 0 : basegfx::B2DHomMatrix aLatheMat;
858 :
859 0 : if(bExtrude)
860 : {
861 0 : double fW = (double)aRect.GetWidth();
862 0 : double fH = (double)aRect.GetHeight();
863 0 : fDepth = sqrt(fW*fW + fH*fH) / 6.0;
864 : }
865 0 : if(!bExtrude)
866 : {
867 : // Create transformation for the polygons rotating body
868 0 : if(aPnt1 != aPnt2)
869 : {
870 : // Rotation around control point #1 with set angle
871 : // for 3D coordinates
872 0 : basegfx::B2DPoint aDiff(aPnt1 - aPnt2);
873 0 : fRot3D = atan2(aDiff.getY(), aDiff.getX()) - F_PI2;
874 :
875 0 : if(basegfx::fTools::equalZero(fabs(fRot3D)))
876 0 : fRot3D = 0.0;
877 :
878 0 : if(fRot3D != 0.0)
879 : {
880 : aLatheMat = basegfx::tools::createRotateAroundPoint(aPnt2, -fRot3D)
881 0 : * aLatheMat;
882 0 : }
883 : }
884 :
885 0 : if(aPnt2.getX() != 0.0)
886 : {
887 : // Translation to Y=0 - axis
888 0 : aLatheMat.translate(-aPnt2.getX(), 0.0);
889 : }
890 : else
891 : {
892 0 : aLatheMat.translate((double)-aRect.Left(), 0.0);
893 : }
894 :
895 : // Form the inverse matrix to determine the target expansion
896 0 : basegfx::B2DHomMatrix aInvLatheMat(aLatheMat);
897 0 : aInvLatheMat.invert();
898 :
899 : // SnapRect extension enables mirroring in the axis of rotation
900 0 : for(sal_uInt32 a=0;a<GetMarkedObjectCount();a++)
901 : {
902 0 : SdrMark* pMark = GetSdrMarkByIndex(a);
903 0 : SdrObject* pObj = pMark->GetMarkedSdrObj();
904 0 : Rectangle aTurnRect = pObj->GetSnapRect();
905 0 : basegfx::B2DPoint aRot;
906 0 : Point aRotPnt;
907 :
908 0 : aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Top());
909 0 : aRot *= aLatheMat;
910 0 : aRot.setX(-aRot.getX());
911 0 : aRot *= aInvLatheMat;
912 0 : aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
913 0 : aRect.Union(Rectangle(aRotPnt, aRotPnt));
914 :
915 0 : aRot = basegfx::B2DPoint(aTurnRect.Left(), -aTurnRect.Bottom());
916 0 : aRot *= aLatheMat;
917 0 : aRot.setX(-aRot.getX());
918 0 : aRot *= aInvLatheMat;
919 0 : aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
920 0 : aRect.Union(Rectangle(aRotPnt, aRotPnt));
921 :
922 0 : aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Top());
923 0 : aRot *= aLatheMat;
924 0 : aRot.setX(-aRot.getX());
925 0 : aRot *= aInvLatheMat;
926 0 : aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
927 0 : aRect.Union(Rectangle(aRotPnt, aRotPnt));
928 :
929 0 : aRot = basegfx::B2DPoint(aTurnRect.Right(), -aTurnRect.Bottom());
930 0 : aRot *= aLatheMat;
931 0 : aRot.setX(-aRot.getX());
932 0 : aRot *= aInvLatheMat;
933 0 : aRotPnt = Point((long)(aRot.getX() + 0.5), (long)(-aRot.getY() - 0.5));
934 0 : aRect.Union(Rectangle(aRotPnt, aRotPnt));
935 0 : }
936 : }
937 :
938 : // Walk throguh the selection and convert it into 3D, complete with
939 : // Convertion to SdrPathObject, also fonts
940 0 : for(sal_uInt32 a=0;a<GetMarkedObjectCount();a++)
941 : {
942 0 : SdrMark* pMark = GetSdrMarkByIndex(a);
943 0 : SdrObject* pObj = pMark->GetMarkedSdrObj();
944 :
945 0 : ImpCreate3DObject(pScene, pObj, bExtrude, fDepth, aLatheMat);
946 : }
947 :
948 0 : if(pScene->GetSubList() && pScene->GetSubList()->GetObjCount() != 0)
949 : {
950 : // Arrange all created objects by depth
951 0 : if(bExtrude)
952 0 : DoDepthArrange(pScene, fDepth);
953 :
954 : // Center 3D objects in the middle of the overall rectangle
955 0 : basegfx::B3DPoint aCenter(pScene->GetBoundVolume().getCenter());
956 0 : basegfx::B3DHomMatrix aMatrix;
957 :
958 0 : aMatrix.translate(-aCenter.getX(), -aCenter.getY(), -aCenter.getZ());
959 0 : pScene->SetTransform(aMatrix * pScene->GetTransform());
960 :
961 : // Initialize scene
962 0 : pScene->NbcSetSnapRect(aRect);
963 0 : basegfx::B3DRange aBoundVol = pScene->GetBoundVolume();
964 0 : InitScene(pScene, (double)aRect.GetWidth(), (double)aRect.GetHeight(), aBoundVol.getDepth());
965 :
966 : // Insert scene instead of the first selected object and throw away
967 : // all the old objects
968 0 : SdrObject* pRepObj = GetMarkedObjectByIndex(0);
969 0 : SdrPageView* pPV = GetSdrPageViewOfMarkedByIndex(0);
970 0 : MarkObj(pRepObj, pPV, sal_True);
971 0 : ReplaceObjectAtView(pRepObj, *pPV, pScene, sal_False);
972 0 : DeleteMarked();
973 0 : MarkObj(pScene, pPV);
974 :
975 : // Rotate Rotation body around the axis of rotation
976 0 : basegfx::B3DHomMatrix aRotate;
977 :
978 0 : if(!bExtrude && fRot3D != 0.0)
979 : {
980 0 : aRotate.rotate(0.0, 0.0, fRot3D);
981 : }
982 :
983 : // Set default rotation
984 : {
985 0 : double XRotateDefault = 20;
986 0 : aRotate.rotate(DEG2RAD(XRotateDefault), 0.0, 0.0);
987 : }
988 :
989 0 : if(!aRotate.isIdentity())
990 : {
991 0 : pScene->SetTransform(aRotate * pScene->GetTransform());
992 : }
993 :
994 : // Invalid SnapRects of objects
995 0 : pScene->SetSnapRect(aRect);
996 : }
997 : else
998 : {
999 : // No 3D object was created, throw away everything
1000 0 : delete pScene;
1001 : }
1002 :
1003 0 : EndUndo();
1004 : }
1005 0 : }
1006 :
1007 : //Arrange all created extrude objects by depth
1008 :
1009 0 : struct E3dDepthNeighbour
1010 : {
1011 : E3dDepthNeighbour* mpNext;
1012 : E3dExtrudeObj* mpObj;
1013 : basegfx::B2DPolyPolygon maPreparedPolyPolygon;
1014 :
1015 0 : E3dDepthNeighbour()
1016 : : mpNext(0),
1017 : mpObj(0),
1018 0 : maPreparedPolyPolygon()
1019 : {
1020 0 : }
1021 : };
1022 :
1023 : struct E3dDepthLayer
1024 : {
1025 : E3dDepthLayer* mpDown;
1026 : E3dDepthNeighbour* mpNext;
1027 :
1028 0 : E3dDepthLayer()
1029 : : mpDown(0),
1030 0 : mpNext(0)
1031 : {
1032 0 : }
1033 :
1034 0 : ~E3dDepthLayer()
1035 : {
1036 0 : while(mpNext)
1037 : {
1038 0 : E3dDepthNeighbour* pSucc = mpNext->mpNext;
1039 0 : delete mpNext;
1040 0 : mpNext = pSucc;
1041 : }
1042 0 : }
1043 : };
1044 :
1045 0 : void E3dView::DoDepthArrange(E3dScene* pScene, double fDepth)
1046 : {
1047 0 : if(pScene && pScene->GetSubList() && pScene->GetSubList()->GetObjCount() > 1)
1048 : {
1049 0 : SdrObjList* pSubList = pScene->GetSubList();
1050 0 : SdrObjListIter aIter(*pSubList, IM_FLAT);
1051 0 : E3dDepthLayer* pBaseLayer = NULL;
1052 0 : E3dDepthLayer* pLayer = NULL;
1053 0 : sal_Int32 nNumLayers = 0;
1054 :
1055 0 : while(aIter.IsMore())
1056 : {
1057 0 : E3dExtrudeObj* pExtrudeObj = dynamic_cast< E3dExtrudeObj* >(aIter.Next());
1058 :
1059 0 : if(pExtrudeObj)
1060 : {
1061 : const basegfx::B2DPolyPolygon aExtrudePoly(
1062 0 : basegfx::tools::prepareForPolygonOperation(pExtrudeObj->GetExtrudePolygon()));
1063 0 : const SfxItemSet& rLocalSet = pExtrudeObj->GetMergedItemSet();
1064 0 : const XFillStyle eLocalFillStyle = ITEMVALUE(rLocalSet, XATTR_FILLSTYLE, XFillStyleItem);
1065 0 : const Color aLocalColor = ((const XFillColorItem&)(rLocalSet.Get(XATTR_FILLCOLOR))).GetColorValue();
1066 :
1067 : // sort in ExtrudeObj
1068 0 : if(pLayer)
1069 : {
1070 : // do we have overlap with an object of this layer?
1071 0 : bool bOverlap(false);
1072 0 : E3dDepthNeighbour* pAct = pLayer->mpNext;
1073 :
1074 0 : while(!bOverlap && pAct)
1075 : {
1076 : // do pAct->mpObj and pExtrudeObj overlap? Check by
1077 : // using logical AND clipping
1078 : const basegfx::B2DPolyPolygon aAndPolyPolygon(
1079 : basegfx::tools::solvePolygonOperationAnd(
1080 : aExtrudePoly,
1081 0 : pAct->maPreparedPolyPolygon));
1082 :
1083 0 : bOverlap = (0 != aAndPolyPolygon.count());
1084 :
1085 0 : if(bOverlap)
1086 : {
1087 : // second ciriteria: is another fillstyle or color used?
1088 0 : const SfxItemSet& rCompareSet = pAct->mpObj->GetMergedItemSet();
1089 :
1090 0 : XFillStyle eCompareFillStyle = ITEMVALUE(rCompareSet, XATTR_FILLSTYLE, XFillStyleItem);
1091 :
1092 0 : if(eLocalFillStyle == eCompareFillStyle)
1093 : {
1094 0 : if(eLocalFillStyle == XFILL_SOLID)
1095 : {
1096 0 : Color aCompareColor = ((const XFillColorItem&)(rCompareSet.Get(XATTR_FILLCOLOR))).GetColorValue();
1097 :
1098 0 : if(aCompareColor == aLocalColor)
1099 : {
1100 0 : bOverlap = sal_False;
1101 : }
1102 : }
1103 0 : else if(eLocalFillStyle == XFILL_NONE)
1104 : {
1105 0 : bOverlap = sal_False;
1106 : }
1107 : }
1108 : }
1109 :
1110 0 : pAct = pAct->mpNext;
1111 0 : }
1112 :
1113 0 : if(bOverlap)
1114 : {
1115 : // yes, start a new layer
1116 0 : pLayer->mpDown = new E3dDepthLayer;
1117 0 : pLayer = pLayer->mpDown;
1118 0 : nNumLayers++;
1119 0 : pLayer->mpNext = new E3dDepthNeighbour;
1120 0 : pLayer->mpNext->mpObj = pExtrudeObj;
1121 0 : pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly;
1122 : }
1123 : else
1124 : {
1125 : // no, add to current layer
1126 0 : E3dDepthNeighbour* pNewNext = new E3dDepthNeighbour;
1127 0 : pNewNext->mpObj = pExtrudeObj;
1128 0 : pNewNext->maPreparedPolyPolygon = aExtrudePoly;
1129 0 : pNewNext->mpNext = pLayer->mpNext;
1130 0 : pLayer->mpNext = pNewNext;
1131 : }
1132 : }
1133 : else
1134 : {
1135 : // first layer ever
1136 0 : pBaseLayer = new E3dDepthLayer;
1137 0 : pLayer = pBaseLayer;
1138 0 : nNumLayers++;
1139 0 : pLayer->mpNext = new E3dDepthNeighbour;
1140 0 : pLayer->mpNext->mpObj = pExtrudeObj;
1141 0 : pLayer->mpNext->maPreparedPolyPolygon = aExtrudePoly;
1142 0 : }
1143 : }
1144 : }
1145 :
1146 : // number of layers is done
1147 0 : if(nNumLayers > 1)
1148 : {
1149 : // need to be arranged
1150 0 : double fMinDepth = fDepth * 0.8;
1151 0 : double fStep = (fDepth - fMinDepth) / (double)nNumLayers;
1152 0 : pLayer = pBaseLayer;
1153 :
1154 0 : while(pLayer)
1155 : {
1156 : // move along layer
1157 0 : E3dDepthNeighbour* pAct = pLayer->mpNext;
1158 :
1159 0 : while(pAct)
1160 : {
1161 : // adapt extrude value
1162 0 : pAct->mpObj->SetMergedItem(SfxUInt32Item(SDRATTR_3DOBJ_DEPTH, sal_uInt32(fMinDepth + 0.5)));
1163 :
1164 : // next
1165 0 : pAct = pAct->mpNext;
1166 : }
1167 :
1168 : // next layer
1169 0 : pLayer = pLayer->mpDown;
1170 0 : fMinDepth += fStep;
1171 : }
1172 : }
1173 :
1174 : // cleanup
1175 0 : while(pBaseLayer)
1176 : {
1177 0 : pLayer = pBaseLayer->mpDown;
1178 0 : delete pBaseLayer;
1179 0 : pBaseLayer = pLayer;
1180 0 : }
1181 : }
1182 0 : }
1183 :
1184 : // Start drag, create for 3D objects before possibly drag method
1185 :
1186 0 : sal_Bool E3dView::BegDragObj(const Point& rPnt, OutputDevice* pOut,
1187 : SdrHdl* pHdl, short nMinMov,
1188 : SdrDragMethod* pForcedMeth)
1189 : {
1190 0 : if(Is3DRotationCreationActive() && GetMarkedObjectCount())
1191 : {
1192 : // Determine all selected polygons and return rhe mirrored helper overlay
1193 0 : mpMirrorOverlay->SetMirrorAxis(aRef1, aRef2);
1194 : }
1195 : else
1196 : {
1197 : sal_Bool bOwnActionNecessary;
1198 0 : if (pHdl == NULL)
1199 : {
1200 0 : bOwnActionNecessary = sal_True;
1201 : }
1202 0 : else if (pHdl->IsVertexHdl() || pHdl->IsCornerHdl())
1203 : {
1204 0 : bOwnActionNecessary = sal_True;
1205 : }
1206 : else
1207 : {
1208 0 : bOwnActionNecessary = sal_False;
1209 : }
1210 :
1211 0 : if(bOwnActionNecessary && GetMarkedObjectCount() >= 1)
1212 : {
1213 0 : E3dDragConstraint eConstraint = E3DDRAG_CONSTR_XYZ;
1214 0 : sal_Bool bThereAreRootScenes = sal_False;
1215 0 : sal_Bool bThereAre3DObjects = sal_False;
1216 0 : long nCnt = GetMarkedObjectCount();
1217 0 : for(long nObjs = 0;nObjs < nCnt;nObjs++)
1218 : {
1219 0 : SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
1220 0 : if(pObj)
1221 : {
1222 0 : if(pObj->ISA(E3dScene) && ((E3dScene*)pObj)->GetScene() == pObj)
1223 0 : bThereAreRootScenes = sal_True;
1224 0 : if(pObj->ISA(E3dObject))
1225 0 : bThereAre3DObjects = sal_True;
1226 : }
1227 : }
1228 0 : if( bThereAre3DObjects )
1229 : {
1230 0 : eDragHdl = ( pHdl == NULL ? HDL_MOVE : pHdl->GetKind() );
1231 0 : switch ( eDragMode )
1232 : {
1233 : case SDRDRAG_ROTATE:
1234 : case SDRDRAG_SHEAR:
1235 : {
1236 0 : switch ( eDragHdl )
1237 : {
1238 : case HDL_LEFT:
1239 : case HDL_RIGHT:
1240 : {
1241 0 : eConstraint = E3DDRAG_CONSTR_X;
1242 : }
1243 0 : break;
1244 :
1245 : case HDL_UPPER:
1246 : case HDL_LOWER:
1247 : {
1248 0 : eConstraint = E3DDRAG_CONSTR_Y;
1249 : }
1250 0 : break;
1251 :
1252 : case HDL_UPLFT:
1253 : case HDL_UPRGT:
1254 : case HDL_LWLFT:
1255 : case HDL_LWRGT:
1256 : {
1257 0 : eConstraint = E3DDRAG_CONSTR_Z;
1258 : }
1259 0 : break;
1260 0 : default: break;
1261 : }
1262 :
1263 : // do not mask the allowed rotations
1264 0 : eConstraint = E3dDragConstraint(eConstraint& eDragConstraint);
1265 0 : pForcedMeth = new E3dDragRotate(*this, GetMarkedObjectList(), eConstraint, IsSolidDragging());
1266 : }
1267 0 : break;
1268 :
1269 : case SDRDRAG_MOVE:
1270 : {
1271 0 : if(!bThereAreRootScenes)
1272 : {
1273 0 : pForcedMeth = new E3dDragMove(*this, GetMarkedObjectList(), eDragHdl, eConstraint, IsSolidDragging());
1274 : }
1275 : }
1276 0 : break;
1277 :
1278 : // later on
1279 : case SDRDRAG_MIRROR:
1280 : case SDRDRAG_CROOK:
1281 : case SDRDRAG_DISTORT:
1282 : case SDRDRAG_TRANSPARENCE:
1283 : case SDRDRAG_GRADIENT:
1284 : default:
1285 : {
1286 : }
1287 0 : break;
1288 : }
1289 : }
1290 : }
1291 : }
1292 0 : return SdrView::BegDragObj(rPnt, pOut, pHdl, nMinMov, pForcedMeth);
1293 : }
1294 :
1295 : // Set current 3D drawing object, create the scene for this
1296 :
1297 0 : E3dScene* E3dView::SetCurrent3DObj(E3dObject* p3DObj)
1298 : {
1299 : DBG_ASSERT(p3DObj != NULL, "Who puts in a NULL-pointer here");
1300 0 : E3dScene* pScene = NULL;
1301 :
1302 : // get transformed BoundVolume of the object
1303 0 : basegfx::B3DRange aVolume(p3DObj->GetBoundVolume());
1304 0 : aVolume.transform(p3DObj->GetTransform());
1305 0 : double fW(aVolume.getWidth());
1306 0 : double fH(aVolume.getHeight());
1307 :
1308 0 : Rectangle aRect(0,0, (long) fW, (long) fH);
1309 :
1310 0 : pScene = new E3dPolyScene(Get3DDefaultAttributes());
1311 :
1312 0 : InitScene(pScene, fW, fH, aVolume.getMaxZ() + ((fW + fH) / 4.0));
1313 :
1314 0 : pScene->Insert3DObj(p3DObj);
1315 0 : pScene->NbcSetSnapRect(aRect);
1316 :
1317 0 : return pScene;
1318 : }
1319 :
1320 0 : void E3dView::InitScene(E3dScene* pScene, double fW, double fH, double fCamZ)
1321 : {
1322 0 : Camera3D aCam(pScene->GetCamera());
1323 :
1324 0 : aCam.SetAutoAdjustProjection(sal_False);
1325 0 : aCam.SetViewWindow(- fW / 2, - fH / 2, fW, fH);
1326 0 : basegfx::B3DPoint aLookAt;
1327 :
1328 0 : double fDefaultCamPosZ = GetDefaultCamPosZ();
1329 0 : basegfx::B3DPoint aCamPos(0.0, 0.0, fCamZ < fDefaultCamPosZ ? fDefaultCamPosZ : fCamZ);
1330 :
1331 0 : aCam.SetPosAndLookAt(aCamPos, aLookAt);
1332 0 : aCam.SetFocalLength(GetDefaultCamFocal());
1333 0 : aCam.SetDefaults(basegfx::B3DPoint(0.0, 0.0, fDefaultCamPosZ), aLookAt, GetDefaultCamFocal());
1334 0 : pScene->SetCamera(aCam);
1335 0 : }
1336 :
1337 0 : void E3dView::Start3DCreation()
1338 : {
1339 0 : if (GetMarkedObjectCount())
1340 : {
1341 : //positioned
1342 0 : long nOutMin = 0;
1343 0 : long nOutMax = 0;
1344 0 : long nMinLen = 0;
1345 0 : long nObjDst = 0;
1346 0 : long nOutHgt = 0;
1347 0 : OutputDevice* pOut = GetFirstOutputDevice();
1348 :
1349 : // first determine representation boundaries
1350 0 : if (pOut != NULL)
1351 : {
1352 0 : nMinLen = pOut->PixelToLogic(Size(0,50)).Height();
1353 0 : nObjDst = pOut->PixelToLogic(Size(0,20)).Height();
1354 :
1355 0 : long nDst = pOut->PixelToLogic(Size(0,10)).Height();
1356 :
1357 0 : nOutMin = -pOut->GetMapMode().GetOrigin().Y();
1358 0 : nOutMax = pOut->GetOutputSize().Height() - 1 + nOutMin;
1359 0 : nOutMin += nDst;
1360 0 : nOutMax -= nDst;
1361 :
1362 0 : if (nOutMax - nOutMin < nDst)
1363 : {
1364 0 : nOutMin += nOutMax + 1;
1365 0 : nOutMin /= 2;
1366 0 : nOutMin -= (nDst + 1) / 2;
1367 0 : nOutMax = nOutMin + nDst;
1368 : }
1369 :
1370 0 : nOutHgt = nOutMax - nOutMin;
1371 :
1372 0 : long nTemp = nOutHgt / 4;
1373 0 : if (nTemp > nMinLen) nMinLen = nTemp;
1374 : }
1375 :
1376 : // and then attach the marks at the top and bottom of the object
1377 0 : basegfx::B2DRange aR;
1378 0 : for(sal_uInt32 nMark(0L); nMark < GetMarkedObjectCount(); nMark++)
1379 : {
1380 0 : SdrObject* pMark = GetMarkedObjectByIndex(nMark);
1381 0 : basegfx::B2DPolyPolygon aXPP(pMark->TakeXorPoly());
1382 0 : aR.expand(basegfx::tools::getRange(aXPP));
1383 0 : }
1384 :
1385 0 : basegfx::B2DPoint aCenter(aR.getCenter());
1386 0 : long nMarkHgt = basegfx::fround(aR.getHeight()) - 1;
1387 0 : long nHgt = nMarkHgt + nObjDst * 2;
1388 :
1389 0 : if (nHgt < nMinLen) nHgt = nMinLen;
1390 :
1391 0 : long nY1 = basegfx::fround(aCenter.getY()) - (nHgt + 1) / 2;
1392 0 : long nY2 = nY1 + nHgt;
1393 :
1394 0 : if (pOut && (nMinLen > nOutHgt)) nMinLen = nOutHgt;
1395 0 : if (pOut)
1396 : {
1397 0 : if (nY1 < nOutMin)
1398 : {
1399 0 : nY1 = nOutMin;
1400 0 : if (nY2 < nY1 + nMinLen) nY2 = nY1 + nMinLen;
1401 : }
1402 0 : if (nY2 > nOutMax)
1403 : {
1404 0 : nY2 = nOutMax;
1405 0 : if (nY1 > nY2 - nMinLen) nY1 = nY2 - nMinLen;
1406 : }
1407 : }
1408 :
1409 0 : aRef1.X() = basegfx::fround(aR.getMinX()); // Initial move axis 2/100mm to the left
1410 0 : aRef1.Y() = nY1;
1411 0 : aRef2.X() = aRef1.X();
1412 0 : aRef2.Y() = nY2;
1413 :
1414 : // Turn on marks
1415 0 : SetMarkHandles();
1416 :
1417 : //HMHif (bVis) ShowMarkHdl();
1418 0 : if (AreObjectsMarked()) MarkListHasChanged();
1419 :
1420 : // Show mirror polygon IMMEDIATELY
1421 0 : const SdrHdlList &aHdlList = GetHdlList();
1422 0 : mpMirrorOverlay = new Impl3DMirrorConstructOverlay(*this);
1423 0 : mpMirrorOverlay->SetMirrorAxis(aHdlList.GetHdl(HDL_REF1)->GetPos(), aHdlList.GetHdl(HDL_REF2)->GetPos());
1424 : }
1425 0 : }
1426 :
1427 : // what happens with a mouse movement when the object is created?
1428 :
1429 0 : void E3dView::MovAction(const Point& rPnt)
1430 : {
1431 0 : if(Is3DRotationCreationActive())
1432 : {
1433 0 : SdrHdl* pHdl = GetDragHdl();
1434 :
1435 0 : if (pHdl)
1436 : {
1437 0 : SdrHdlKind eHdlKind = pHdl->GetKind();
1438 :
1439 : // reacts only due to a mirror axis
1440 0 : if ((eHdlKind == HDL_REF1) ||
1441 : (eHdlKind == HDL_REF2) ||
1442 : (eHdlKind == HDL_MIRX))
1443 : {
1444 0 : const SdrHdlList &aHdlList = GetHdlList ();
1445 :
1446 : // delete the mirroed polygon, mirrors the original and draws
1447 : // it anew
1448 0 : SdrView::MovAction (rPnt);
1449 : mpMirrorOverlay->SetMirrorAxis(
1450 0 : aHdlList.GetHdl (HDL_REF1)->GetPos(),
1451 0 : aHdlList.GetHdl (HDL_REF2)->GetPos());
1452 : }
1453 : }
1454 : else
1455 : {
1456 0 : SdrView::MovAction (rPnt);
1457 : }
1458 : }
1459 : else
1460 : {
1461 0 : SdrView::MovAction (rPnt);
1462 : }
1463 0 : }
1464 :
1465 : // The End. Create object and any child objects through ImpCreate3DLathe.
1466 : // With the parameter value sal_True (SDefault: sal_False) is simply a
1467 : // rotation body created, without letting the user set the position of the
1468 : // axis. It is sufficient with this call, if an object is selected.
1469 : // (No initialization necessary)
1470 :
1471 0 : void E3dView::End3DCreation(sal_Bool bUseDefaultValuesForMirrorAxes)
1472 : {
1473 0 : ResetCreationActive();
1474 :
1475 0 : if(AreObjectsMarked())
1476 : {
1477 0 : if(bUseDefaultValuesForMirrorAxes)
1478 : {
1479 0 : Rectangle aRect = GetAllMarkedRect();
1480 0 : if(aRect.GetWidth() <= 1)
1481 0 : aRect.SetSize(Size(500, aRect.GetHeight()));
1482 0 : if(aRect.GetHeight() <= 1)
1483 0 : aRect.SetSize(Size(aRect.GetWidth(), 500));
1484 :
1485 0 : basegfx::B2DPoint aPnt1(aRect.Left(), -aRect.Top());
1486 0 : basegfx::B2DPoint aPnt2(aRect.Left(), -aRect.Bottom());
1487 :
1488 0 : ConvertMarkedObjTo3D(sal_False, aPnt1, aPnt2);
1489 : }
1490 : else
1491 : {
1492 : // Turn off helper overlay
1493 : // Determine from the handle positions and the displacement of
1494 : // the points
1495 0 : const SdrHdlList &aHdlList = GetHdlList();
1496 0 : Point aMirrorRef1 = aHdlList.GetHdl(HDL_REF1)->GetPos();
1497 0 : Point aMirrorRef2 = aHdlList.GetHdl(HDL_REF2)->GetPos();
1498 :
1499 0 : basegfx::B2DPoint aPnt1(aMirrorRef1.X(), -aMirrorRef1.Y());
1500 0 : basegfx::B2DPoint aPnt2(aMirrorRef2.X(), -aMirrorRef2.Y());
1501 :
1502 0 : ConvertMarkedObjTo3D(sal_False, aPnt1, aPnt2);
1503 : }
1504 : }
1505 0 : }
1506 :
1507 92 : E3dView::~E3dView ()
1508 : {
1509 92 : }
1510 :
1511 0 : void E3dView::ResetCreationActive ()
1512 : {
1513 0 : if(mpMirrorOverlay)
1514 : {
1515 0 : delete mpMirrorOverlay;
1516 0 : mpMirrorOverlay = 0L;
1517 : }
1518 0 : }
1519 :
1520 252 : void E3dView::InitView ()
1521 : {
1522 252 : eDragConstraint = E3DDRAG_CONSTR_XYZ;
1523 : fDefaultScaleX =
1524 : fDefaultScaleY =
1525 252 : fDefaultScaleZ = 1.0;
1526 : fDefaultRotateX =
1527 : fDefaultRotateY =
1528 252 : fDefaultRotateZ = 0.0;
1529 252 : fDefaultExtrusionDeepth = 1000; // old: 2000;
1530 252 : fDefaultLightIntensity = 0.8; // old: 0.6;
1531 252 : fDefaultAmbientIntensity = 0.4;
1532 252 : nHDefaultSegments = 12;
1533 252 : nVDefaultSegments = 12;
1534 252 : aDefaultLightColor = RGB_Color(COL_WHITE);
1535 252 : aDefaultAmbientColor = RGB_Color(COL_BLACK);
1536 252 : bDoubleSided = sal_False;
1537 252 : mpMirrorOverlay = 0L;
1538 252 : }
1539 :
1540 0 : sal_Bool E3dView::IsBreak3DObjPossible() const
1541 : {
1542 0 : sal_uIntPtr nCount = GetMarkedObjectCount();
1543 :
1544 0 : if (nCount > 0)
1545 : {
1546 0 : sal_uIntPtr i = 0;
1547 :
1548 0 : while (i < nCount)
1549 : {
1550 0 : SdrObject* pObj = GetMarkedObjectByIndex(i);
1551 :
1552 0 : if (pObj && pObj->ISA(E3dObject))
1553 : {
1554 0 : if(!(((E3dObject*)pObj)->IsBreakObjPossible()))
1555 0 : return sal_False;
1556 : }
1557 : else
1558 : {
1559 0 : return sal_False;
1560 : }
1561 :
1562 0 : i++;
1563 : }
1564 : }
1565 : else
1566 : {
1567 0 : return sal_False;
1568 : }
1569 :
1570 0 : return sal_True;
1571 : }
1572 :
1573 0 : void E3dView::Break3DObj()
1574 : {
1575 0 : if(IsBreak3DObjPossible())
1576 : {
1577 : // ALL selected objects are changed
1578 0 : sal_uInt32 nCount = GetMarkedObjectCount();
1579 :
1580 0 : BegUndo(String(SVX_RESSTR(RID_SVX_3D_UNDO_BREAK_LATHE)));
1581 0 : for(sal_uInt32 a=0;a<nCount;a++)
1582 : {
1583 0 : E3dObject* pObj = (E3dObject*)GetMarkedObjectByIndex(a);
1584 0 : BreakSingle3DObj(pObj);
1585 : }
1586 0 : DeleteMarked();
1587 0 : EndUndo();
1588 : }
1589 0 : }
1590 :
1591 0 : void E3dView::BreakSingle3DObj(E3dObject* pObj)
1592 : {
1593 0 : if(pObj->ISA(E3dScene))
1594 : {
1595 0 : SdrObjList* pSubList = pObj->GetSubList();
1596 0 : SdrObjListIter aIter(*pSubList, IM_FLAT);
1597 :
1598 0 : while(aIter.IsMore())
1599 : {
1600 0 : E3dObject* pSubObj = (E3dObject*)aIter.Next();
1601 0 : BreakSingle3DObj(pSubObj);
1602 0 : }
1603 : }
1604 : else
1605 : {
1606 0 : SdrAttrObj* pNewObj = pObj->GetBreakObj();
1607 0 : if(pNewObj)
1608 : {
1609 0 : InsertObjectAtView(pNewObj, *GetSdrPageView(), SDRINSERT_DONTMARK);
1610 0 : pNewObj->SetChanged();
1611 0 : pNewObj->BroadcastObjectChange();
1612 : }
1613 : }
1614 0 : }
1615 :
1616 0 : void E3dView::CheckPossibilities()
1617 : {
1618 : // call parent
1619 0 : SdrView::CheckPossibilities();
1620 :
1621 : // Set other flags
1622 0 : if(bGroupPossible || bUnGroupPossible || bGrpEnterPossible)
1623 : {
1624 0 : sal_Int32 nMarkCnt = GetMarkedObjectCount();
1625 0 : sal_Bool bCoumpound = sal_False;
1626 0 : sal_Bool b3DObject = sal_False;
1627 0 : for(sal_Int32 nObjs = 0L; (nObjs < nMarkCnt) && !bCoumpound; nObjs++)
1628 : {
1629 0 : SdrObject *pObj = GetMarkedObjectByIndex(nObjs);
1630 0 : if(pObj && pObj->ISA(E3dCompoundObject))
1631 0 : bCoumpound = sal_True;
1632 0 : if(pObj && pObj->ISA(E3dObject))
1633 0 : b3DObject = sal_True;
1634 : }
1635 :
1636 : // So far: there are two or more of any objects selected. See if
1637 : // compound objects are involved. If yes, ban grouping.
1638 0 : if(bGroupPossible && bCoumpound)
1639 0 : bGroupPossible = sal_False;
1640 :
1641 0 : if(bUnGroupPossible && b3DObject)
1642 0 : bUnGroupPossible = sal_False;
1643 :
1644 0 : if(bGrpEnterPossible && bCoumpound)
1645 0 : bGrpEnterPossible = sal_False;
1646 : }
1647 0 : }
1648 :
1649 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|