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