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