/src/libreoffice/svx/source/engine3d/scene3d.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 | | #include <sal/config.h> |
21 | | |
22 | | #include <cstdlib> |
23 | | |
24 | | #include <svx/strings.hrc> |
25 | | #include <svx/dialmgr.hxx> |
26 | | #include <svx/svditer.hxx> |
27 | | |
28 | | #include <svx/svdobjkind.hxx> |
29 | | #include <svx/svdpage.hxx> |
30 | | #include <svx/scene3d.hxx> |
31 | | #include <svx/svdtrans.hxx> |
32 | | #include <sdr/properties/e3dsceneproperties.hxx> |
33 | | #include <svx/sdr/contact/viewcontactofe3dscene.hxx> |
34 | | #include <svx/svddrag.hxx> |
35 | | #include "helperminimaldepth3d.hxx" |
36 | | #include <algorithm> |
37 | | #include <drawinglayer/geometry/viewinformation3d.hxx> |
38 | | #include <basegfx/polygon/b2dpolypolygontools.hxx> |
39 | | #include <svx/e3dsceneupdater.hxx> |
40 | | #include <svx/svdmodel.hxx> |
41 | | #include <osl/diagnose.h> |
42 | | |
43 | | namespace { |
44 | | |
45 | | class ImpRemap3DDepth |
46 | | { |
47 | | sal_uInt32 mnOrdNum; |
48 | | double mfMinimalDepth; |
49 | | |
50 | | // bit field |
51 | | bool mbIsScene : 1; |
52 | | |
53 | | public: |
54 | | ImpRemap3DDepth(sal_uInt32 nOrdNum, double fMinimalDepth); |
55 | | explicit ImpRemap3DDepth(sal_uInt32 nOrdNum); |
56 | | |
57 | | // for ::std::sort |
58 | | bool operator<(const ImpRemap3DDepth& rComp) const; |
59 | | |
60 | 0 | sal_uInt32 GetOrdNum() const { return mnOrdNum; } |
61 | 0 | bool IsScene() const { return mbIsScene; } |
62 | | }; |
63 | | |
64 | | } |
65 | | |
66 | | ImpRemap3DDepth::ImpRemap3DDepth(sal_uInt32 nOrdNum, double fMinimalDepth) |
67 | 0 | : mnOrdNum(nOrdNum), |
68 | 0 | mfMinimalDepth(fMinimalDepth), |
69 | 0 | mbIsScene(false) |
70 | 0 | { |
71 | 0 | } |
72 | | |
73 | | ImpRemap3DDepth::ImpRemap3DDepth(sal_uInt32 nOrdNum) |
74 | 0 | : mnOrdNum(nOrdNum), |
75 | 0 | mfMinimalDepth(0.0), |
76 | 0 | mbIsScene(true) |
77 | 0 | { |
78 | 0 | } |
79 | | |
80 | | bool ImpRemap3DDepth::operator<(const ImpRemap3DDepth& rComp) const |
81 | 0 | { |
82 | 0 | if(IsScene()) |
83 | 0 | { |
84 | 0 | return false; |
85 | 0 | } |
86 | 0 | else |
87 | 0 | { |
88 | 0 | if(rComp.IsScene()) |
89 | 0 | { |
90 | 0 | return true; |
91 | 0 | } |
92 | 0 | else |
93 | 0 | { |
94 | 0 | return mfMinimalDepth < rComp.mfMinimalDepth; |
95 | 0 | } |
96 | 0 | } |
97 | 0 | } |
98 | | |
99 | | class Imp3DDepthRemapper |
100 | | { |
101 | | std::vector< ImpRemap3DDepth > maVector; |
102 | | |
103 | | public: |
104 | | explicit Imp3DDepthRemapper(E3dScene const & rScene); |
105 | | |
106 | | sal_uInt32 RemapOrdNum(sal_uInt32 nOrdNum) const; |
107 | | }; |
108 | | |
109 | | Imp3DDepthRemapper::Imp3DDepthRemapper(E3dScene const & rScene) |
110 | 0 | { |
111 | | // only called when rScene.GetSubList() and nObjCount > 1 |
112 | 0 | SdrObjList* pList = rScene.GetSubList(); |
113 | 0 | const size_t nObjCount(pList->GetObjCount()); |
114 | |
|
115 | 0 | for(size_t a = 0; a < nObjCount; ++a) |
116 | 0 | { |
117 | 0 | SdrObject* pCandidate = pList->GetObj(a); |
118 | |
|
119 | 0 | if(pCandidate) |
120 | 0 | { |
121 | 0 | if(auto pCompoundObj = dynamic_cast< const E3dCompoundObject*>(pCandidate)) |
122 | 0 | { |
123 | | // single 3d object, calc depth |
124 | 0 | const double fMinimalDepth(getMinimalDepthInViewCoordinates(*pCompoundObj)); |
125 | 0 | ImpRemap3DDepth aEntry(a, fMinimalDepth); |
126 | 0 | maVector.push_back(aEntry); |
127 | 0 | } |
128 | 0 | else |
129 | 0 | { |
130 | | // scene, use standard entry for scene |
131 | 0 | ImpRemap3DDepth aEntry(a); |
132 | 0 | maVector.push_back(aEntry); |
133 | 0 | } |
134 | 0 | } |
135 | 0 | } |
136 | | |
137 | | // now, we need to sort the maVector by its members minimal depth. The |
138 | | // smaller, the nearer to the viewer. |
139 | 0 | ::std::sort(maVector.begin(), maVector.end()); |
140 | 0 | } |
141 | | |
142 | | sal_uInt32 Imp3DDepthRemapper::RemapOrdNum(sal_uInt32 nOrdNum) const |
143 | 0 | { |
144 | 0 | if(nOrdNum < maVector.size()) |
145 | 0 | { |
146 | 0 | nOrdNum = maVector[(maVector.size() - 1) - nOrdNum].GetOrdNum(); |
147 | 0 | } |
148 | |
|
149 | 0 | return nOrdNum; |
150 | 0 | } |
151 | | |
152 | | |
153 | | // BaseProperties section |
154 | | |
155 | | std::unique_ptr<sdr::properties::BaseProperties> E3dScene::CreateObjectSpecificProperties() |
156 | 3.50k | { |
157 | 3.50k | return std::make_unique<sdr::properties::E3dSceneProperties>(*this); |
158 | 3.50k | } |
159 | | |
160 | | |
161 | | // DrawContact section |
162 | | |
163 | | std::unique_ptr<sdr::contact::ViewContact> E3dScene::CreateObjectSpecificViewContact() |
164 | 3.50k | { |
165 | 3.50k | return std::make_unique<sdr::contact::ViewContactOfE3dScene>(*this); |
166 | 3.50k | } |
167 | | |
168 | | |
169 | | E3dScene::E3dScene(SdrModel& rSdrModel) |
170 | 3.50k | : E3dObject(rSdrModel), |
171 | 3.50k | m_aCamera(basegfx::B3DPoint(0.0, 0.0, 4.0), basegfx::B3DPoint()), |
172 | 3.50k | m_bDrawOnlySelected(false), |
173 | 3.50k | mbSkipSettingDirty(false) |
174 | 3.50k | { |
175 | | // Set defaults |
176 | 3.50k | SetDefaultAttributes(); |
177 | 3.50k | } |
178 | | |
179 | | E3dScene::E3dScene(SdrModel& rSdrModel, E3dScene const & rSource) |
180 | 0 | : E3dObject(rSdrModel, rSource), |
181 | 0 | m_aCamera(basegfx::B3DPoint(0.0, 0.0, 4.0), basegfx::B3DPoint()), |
182 | 0 | m_bDrawOnlySelected(false), |
183 | 0 | mbSkipSettingDirty(false) |
184 | 0 | { |
185 | | // Set defaults |
186 | 0 | SetDefaultAttributes(); |
187 | | |
188 | | // copy child SdrObjects |
189 | 0 | if (rSource.GetSubList()) |
190 | 0 | { |
191 | 0 | CopyObjects(*rSource.GetSubList()); |
192 | | |
193 | | // tdf#116979: needed here, we need bSnapRectDirty to be true |
194 | | // which it is after using SdrObject::operator= (see above), |
195 | | // but set to false again using CopyObjects |
196 | 0 | SetBoundAndSnapRectsDirty(); |
197 | 0 | } |
198 | | |
199 | | // copy local data |
200 | 0 | m_aCamera = rSource.m_aCamera; |
201 | 0 | m_aCameraSet = rSource.m_aCameraSet; |
202 | 0 | static_cast<sdr::properties::E3dSceneProperties&>(GetProperties()).SetSceneItemsFromCamera(); |
203 | 0 | InvalidateBoundVolume(); |
204 | 0 | RebuildLists(); |
205 | 0 | ImpCleanup3DDepthMapper(); |
206 | 0 | GetViewContact().ActionChanged(); |
207 | 0 | } |
208 | | |
209 | | void E3dScene::SetDefaultAttributes() |
210 | 3.50k | { |
211 | | // Set defaults |
212 | 3.50k | m_aCamera.SetViewWindow(-2, -2, 4, 4); |
213 | 3.50k | m_aCameraSet.SetDeviceRectangle(-2, 2, -2, 2); |
214 | 3.50k | m_aCamera.SetDeviceWindow(tools::Rectangle(0, 0, 10, 10)); |
215 | 3.50k | tools::Rectangle aRect(0, 0, 10, 10); |
216 | 3.50k | m_aCameraSet.SetViewportRectangle(aRect); |
217 | | |
218 | | // set defaults for Camera from ItemPool |
219 | 3.50k | m_aCamera.SetProjection(GetPerspective()); |
220 | 3.50k | basegfx::B3DPoint aActualPosition(m_aCamera.GetPosition()); |
221 | 3.50k | double fNew = GetDistance(); |
222 | | |
223 | 3.50k | if(fabs(fNew - aActualPosition.getZ()) > 1.0) |
224 | 3.50k | { |
225 | 3.50k | m_aCamera.SetPosition( basegfx::B3DPoint( aActualPosition.getX(), aActualPosition.getY(), fNew) ); |
226 | 3.50k | } |
227 | | |
228 | 3.50k | fNew = GetFocalLength() / 100.0; |
229 | 3.50k | m_aCamera.SetFocalLength(fNew); |
230 | 3.50k | } |
231 | | |
232 | | E3dScene::~E3dScene() |
233 | 3.50k | { |
234 | 3.50k | ImpCleanup3DDepthMapper(); |
235 | 3.50k | } |
236 | | |
237 | | SdrPage* E3dScene::getSdrPageFromSdrObjList() const |
238 | 59.1k | { |
239 | 59.1k | return getSdrPageFromSdrObject(); |
240 | 59.1k | } |
241 | | |
242 | | SdrObject* E3dScene::getSdrObjectFromSdrObjList() const |
243 | 129k | { |
244 | 129k | return const_cast< E3dScene* >(this); |
245 | 129k | } |
246 | | |
247 | | SdrObjList* E3dScene::getChildrenOfSdrObject() const |
248 | 3.50k | { |
249 | 3.50k | return const_cast< E3dScene* >(this); |
250 | 3.50k | } |
251 | | |
252 | | basegfx::B2DPolyPolygon E3dScene::TakeXorPoly() const |
253 | 0 | { |
254 | 0 | const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(GetViewContact()); |
255 | 0 | const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D()); |
256 | 0 | const basegfx::B3DPolyPolygon aCubePolyPolygon(CreateWireframe()); |
257 | |
|
258 | 0 | basegfx::B2DPolyPolygon aRetval(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(aCubePolyPolygon, |
259 | 0 | aViewInfo3D.getObjectToView())); |
260 | 0 | aRetval.transform(rVCScene.getObjectTransformation()); |
261 | |
|
262 | 0 | return aRetval; |
263 | 0 | } |
264 | | |
265 | | void E3dScene::ImpCleanup3DDepthMapper() |
266 | 248k | { |
267 | 248k | mp3DDepthRemapper.reset(); |
268 | 248k | } |
269 | | |
270 | | sal_uInt32 E3dScene::RemapOrdNum(sal_uInt32 nNewOrdNum) const |
271 | 0 | { |
272 | 0 | if(!mp3DDepthRemapper) |
273 | 0 | { |
274 | 0 | const size_t nObjCount(GetSubList() ? GetSubList()->GetObjCount() : 0); |
275 | |
|
276 | 0 | if(nObjCount > 1) |
277 | 0 | { |
278 | 0 | mp3DDepthRemapper.reset(new Imp3DDepthRemapper(*this)); |
279 | 0 | } |
280 | 0 | } |
281 | |
|
282 | 0 | if(mp3DDepthRemapper) |
283 | 0 | { |
284 | 0 | return mp3DDepthRemapper->RemapOrdNum(nNewOrdNum); |
285 | 0 | } |
286 | | |
287 | 0 | return nNewOrdNum; |
288 | 0 | } |
289 | | |
290 | | SdrObjKind E3dScene::GetObjIdentifier() const |
291 | 29.2k | { |
292 | 29.2k | return SdrObjKind::E3D_Scene; |
293 | 29.2k | } |
294 | | |
295 | | void E3dScene::SetBoundRectDirty() |
296 | 364k | { |
297 | 364k | E3dScene* pScene(getRootE3dSceneFromE3dObject()); |
298 | | |
299 | 364k | if(pScene == this) |
300 | 364k | { |
301 | | // avoid resetting aOutRect which in case of a 3D scene used as 2d object |
302 | | // is model data,not re-creatable view data |
303 | 364k | } |
304 | 0 | else |
305 | 0 | { |
306 | | // if not the outmost scene it is used as group in 3d, call parent |
307 | 0 | E3dObject::SetBoundRectDirty(); |
308 | 0 | } |
309 | 364k | } |
310 | | |
311 | | void E3dScene::NbcSetSnapRect(const tools::Rectangle& rRect) |
312 | 7.01k | { |
313 | 7.01k | SetBoundAndSnapRectsDirty(); |
314 | 7.01k | E3dObject::NbcSetSnapRect(rRect); |
315 | 7.01k | m_aCamera.SetDeviceWindow(rRect); |
316 | 7.01k | m_aCameraSet.SetViewportRectangle(rRect); |
317 | | |
318 | 7.01k | ImpCleanup3DDepthMapper(); |
319 | 7.01k | } |
320 | | |
321 | | void E3dScene::NbcMove(const Size& rSize) |
322 | 0 | { |
323 | 0 | tools::Rectangle aNewSnapRect = GetSnapRect(); |
324 | 0 | aNewSnapRect.Move(rSize); |
325 | 0 | NbcSetSnapRect(aNewSnapRect); |
326 | 0 | } |
327 | | |
328 | | void E3dScene::NbcResize(const Point& rRef, double rXFact, double rYFact) |
329 | 0 | { |
330 | 0 | tools::Rectangle aNewSnapRect = GetSnapRect(); |
331 | 0 | ResizeRect(aNewSnapRect, rRef, rXFact, rYFact); |
332 | 0 | NbcSetSnapRect(aNewSnapRect); |
333 | 0 | } |
334 | | |
335 | | // Set new camera, and thus mark the scene and if possible the bound volume |
336 | | // as changed |
337 | | |
338 | | void E3dScene::SetCamera(const Camera3D& rNewCamera) |
339 | 7.01k | { |
340 | 7.01k | m_aCamera = rNewCamera; |
341 | 7.01k | static_cast<sdr::properties::E3dSceneProperties&>(GetProperties()).SetSceneItemsFromCamera(); |
342 | | |
343 | 7.01k | SetBoundAndSnapRectsDirty(); |
344 | | |
345 | | // Turn off ratio |
346 | 7.01k | GetCameraSet().SetRatio(0.0); |
347 | | |
348 | | // Set Imaging geometry |
349 | 7.01k | basegfx::B3DPoint aVRP(m_aCamera.GetViewPoint()); |
350 | 7.01k | basegfx::B3DVector aVPN(aVRP - m_aCamera.GetVRP()); |
351 | 7.01k | basegfx::B3DVector aVUV(m_aCamera.GetVUV()); |
352 | | |
353 | | // use SetViewportValues() to set VRP, VPN and VUV as vectors, too. |
354 | | // Else these values would not be exported/imported correctly. |
355 | 7.01k | GetCameraSet().SetViewportValues(aVRP, aVPN, aVUV); |
356 | | |
357 | | // Set perspective |
358 | 7.01k | GetCameraSet().SetPerspective(m_aCamera.GetProjection() == ProjectionType::Perspective); |
359 | 7.01k | GetCameraSet().SetViewportRectangle(m_aCamera.GetDeviceWindow()); |
360 | | |
361 | 7.01k | ImpCleanup3DDepthMapper(); |
362 | 7.01k | } |
363 | | |
364 | | // Inform parent of changes of a child |
365 | | |
366 | | void E3dScene::StructureChanged() |
367 | 231k | { |
368 | 231k | E3dObject::StructureChanged(); |
369 | | |
370 | 231k | E3dScene* pScene(getRootE3dSceneFromE3dObject()); |
371 | | |
372 | 231k | if(nullptr != pScene && !pScene->mbSkipSettingDirty) |
373 | 231k | { |
374 | | // Only set dirty from the root object, since setting dirty is recursive |
375 | | // and we only want to walk the tree once. |
376 | 231k | if(getParentE3dSceneFromE3dObject() == nullptr) |
377 | 231k | SetBoundAndSnapRectsDirty(); |
378 | 231k | } |
379 | | |
380 | 231k | ImpCleanup3DDepthMapper(); |
381 | 231k | } |
382 | | |
383 | | // Determine the overall scene object |
384 | | |
385 | | E3dScene* E3dScene::getRootE3dSceneFromE3dObject() const |
386 | 599k | { |
387 | 599k | E3dScene* pParent(getParentE3dSceneFromE3dObject()); |
388 | | |
389 | 599k | if(nullptr != pParent) |
390 | 0 | { |
391 | 0 | return pParent->getRootE3dSceneFromE3dObject(); |
392 | 0 | } |
393 | | |
394 | 599k | return const_cast< E3dScene* >(this); |
395 | 599k | } |
396 | | |
397 | | void E3dScene::removeAllNonSelectedObjects() |
398 | 0 | { |
399 | 0 | E3DModifySceneSnapRectUpdater aUpdater(this); |
400 | |
|
401 | 0 | size_t a = 0; |
402 | 0 | while (a < GetObjCount()) |
403 | 0 | { |
404 | 0 | SdrObject* pObj = GetObj(a); |
405 | |
|
406 | 0 | if(pObj) |
407 | 0 | { |
408 | 0 | bool bRemoveObject(false); |
409 | |
|
410 | 0 | if(E3dScene* pScene = DynCastE3dScene(pObj)) |
411 | 0 | { |
412 | | // iterate over this sub-scene |
413 | 0 | pScene->removeAllNonSelectedObjects(); |
414 | | |
415 | | // check object count. Empty scenes can be deleted |
416 | 0 | const size_t nObjCount(pScene->GetSubList() ? pScene->GetSubList()->GetObjCount() : 0); |
417 | |
|
418 | 0 | if(!nObjCount) |
419 | 0 | { |
420 | | // all objects removed, scene can be removed, too |
421 | 0 | bRemoveObject = true; |
422 | 0 | } |
423 | 0 | } |
424 | 0 | else if(auto pCompound = dynamic_cast<E3dCompoundObject*>(pObj)) |
425 | 0 | { |
426 | 0 | if(!pCompound->GetSelected()) |
427 | 0 | { |
428 | 0 | bRemoveObject = true; |
429 | 0 | } |
430 | 0 | } |
431 | |
|
432 | 0 | if(bRemoveObject) |
433 | 0 | { |
434 | 0 | NbcRemoveObject(pObj->GetOrdNum()); |
435 | 0 | continue; |
436 | 0 | } |
437 | 0 | } |
438 | 0 | ++a; |
439 | 0 | } |
440 | 0 | } |
441 | | |
442 | | rtl::Reference<SdrObject> E3dScene::implCloneSdrObject(SdrModel& rTargetModel) const |
443 | 0 | { |
444 | 0 | return new E3dScene(rTargetModel, *this); |
445 | 0 | } |
446 | | |
447 | | void E3dScene::SuspendReportingDirtyRects() |
448 | 0 | { |
449 | 0 | E3dScene* pScene(getRootE3dSceneFromE3dObject()); |
450 | |
|
451 | 0 | if(nullptr != pScene) |
452 | 0 | { |
453 | 0 | pScene->mbSkipSettingDirty = true; |
454 | 0 | } |
455 | 0 | } |
456 | | |
457 | | void E3dScene::ResumeReportingDirtyRects() |
458 | 0 | { |
459 | 0 | E3dScene* pScene(getRootE3dSceneFromE3dObject()); |
460 | |
|
461 | 0 | if(nullptr != pScene) |
462 | 0 | { |
463 | 0 | pScene->mbSkipSettingDirty = false; |
464 | 0 | } |
465 | 0 | } |
466 | | |
467 | | void E3dScene::SetAllSceneRectsDirty() |
468 | 0 | { |
469 | 0 | E3dScene* pScene(getRootE3dSceneFromE3dObject()); |
470 | |
|
471 | 0 | if(nullptr != pScene) |
472 | 0 | { |
473 | 0 | pScene->SetBoundAndSnapRectsDirty(); |
474 | 0 | } |
475 | 0 | } |
476 | | |
477 | | // Rebuild Light- and label- object lists rebuild (after loading, allocation) |
478 | | |
479 | | void E3dScene::RebuildLists() |
480 | 0 | { |
481 | | // first delete |
482 | 0 | const SdrLayerID nCurrLayerID(GetLayer()); |
483 | 0 | SdrObjListIter a3DIterator(GetSubList(), SdrIterMode::Flat); |
484 | | |
485 | | // then examine all the objects in the scene |
486 | 0 | while(a3DIterator.IsMore()) |
487 | 0 | { |
488 | 0 | E3dObject* p3DObj(static_cast< E3dObject* >(a3DIterator.Next())); |
489 | 0 | p3DObj->NbcSetLayer(nCurrLayerID); |
490 | 0 | } |
491 | |
|
492 | 0 | ImpCleanup3DDepthMapper(); |
493 | 0 | } |
494 | | |
495 | | std::unique_ptr<SdrObjGeoData> E3dScene::NewGeoData() const |
496 | 0 | { |
497 | 0 | return std::make_unique<E3DSceneGeoData>(); |
498 | 0 | } |
499 | | |
500 | | void E3dScene::SaveGeoData(SdrObjGeoData& rGeo) const |
501 | 0 | { |
502 | 0 | E3dObject::SaveGeoData (rGeo); |
503 | |
|
504 | 0 | static_cast<E3DSceneGeoData &>(rGeo).aCamera = m_aCamera; |
505 | 0 | } |
506 | | |
507 | | void E3dScene::RestoreGeoData(const SdrObjGeoData& rGeo) |
508 | 0 | { |
509 | | // #i94832# removed E3DModifySceneSnapRectUpdater here. |
510 | | // It should not be needed, is already part of E3dObject::RestoreGeoData |
511 | 0 | E3dObject::RestoreGeoData (rGeo); |
512 | 0 | SetCamera (static_cast<const E3DSceneGeoData &>(rGeo).aCamera); |
513 | 0 | } |
514 | | |
515 | | // Something was changed in the style sheet, so change scene |
516 | | |
517 | | void E3dScene::Notify(SfxBroadcaster &rBC, const SfxHint &rHint) |
518 | 0 | { |
519 | 0 | SetBoundAndSnapRectsDirty(); |
520 | 0 | E3dObject::Notify(rBC, rHint); |
521 | 0 | } |
522 | | |
523 | | void E3dScene::RotateScene (const Point& rRef, double sn, double cs) |
524 | 0 | { |
525 | 0 | Point NewCenter; |
526 | |
|
527 | 0 | auto const& rRectangle = getOutRectangle(); |
528 | 0 | Point Center = rRectangle.Center(); |
529 | | |
530 | | // Only the center is moved. The corners are moved by NbcMove. For the |
531 | | // rotation a cartesian coordinate system is used in which the pivot |
532 | | // point is the origin, and the y-axis increases upward, the X-axis to |
533 | | // the right. This must be especially noted for the Y-values. |
534 | | // (When considering a flat piece of paper the Y-axis pointing downwards |
535 | 0 | Center.setX(Center.X() - rRef.X()); |
536 | 0 | Center.setY(rRef.Y() - Center.Y()); |
537 | | // A few special cases has to be dealt with first (n * 90 degrees n integer) |
538 | 0 | if (sn==1.0 && cs==0.0) { // 90deg |
539 | 0 | NewCenter.setX( -Center.Y() ); |
540 | 0 | NewCenter.setY( -Center.X() ); |
541 | 0 | } else if (sn==0.0 && cs==-1.0) { // 180deg |
542 | 0 | NewCenter.setX( -Center.X() ); |
543 | 0 | NewCenter.setY( -Center.Y() ); |
544 | 0 | } else if (sn==-1.0 && cs==0.0) { // 270deg |
545 | 0 | NewCenter.setX( Center.Y() ); |
546 | 0 | NewCenter.setY( -Center.X() ); |
547 | 0 | } |
548 | 0 | else // Here it is rotated to any angle in the mathematically |
549 | | // positive direction! |
550 | 0 | { // xnew = x * cos(alpha) - y * sin(alpha) |
551 | | // ynew = x * sin(alpha) + y * cos(alpha) |
552 | | // Bottom Right is not rotated: the pages of aOutRect must |
553 | | // remain parallel to the coordinate axes. |
554 | 0 | NewCenter.setX( static_cast<tools::Long>(Center.X() * cs - Center.Y() * sn) ); |
555 | 0 | NewCenter.setY( static_cast<tools::Long>(Center.X() * sn + Center.Y() * cs) ); |
556 | 0 | } |
557 | |
|
558 | 0 | Size Differenz; |
559 | 0 | Point DiffPoint = NewCenter - Center; |
560 | 0 | Differenz.setWidth( DiffPoint.X() ); |
561 | 0 | Differenz.setHeight( -DiffPoint.Y() ); // Note that the Y-axis is counted ad positive downward. |
562 | 0 | NbcMove (Differenz); // Actually executes the coordinate transformation. |
563 | 0 | } |
564 | | |
565 | | OUString E3dScene::TakeObjNameSingul() const |
566 | 0 | { |
567 | 0 | OUString sName(SvxResId(STR_ObjNameSingulScene3d)); |
568 | |
|
569 | 0 | OUString aName(GetName()); |
570 | 0 | if (!aName.isEmpty()) |
571 | 0 | sName += " '" + aName + "'"; |
572 | 0 | return sName; |
573 | 0 | } |
574 | | |
575 | | OUString E3dScene::TakeObjNamePlural() const |
576 | 0 | { |
577 | 0 | return SvxResId(STR_ObjNamePluralScene3d); |
578 | 0 | } |
579 | | |
580 | | // The NbcRotate routine overrides the one of the SdrObject. The idea is |
581 | | // to be able to rotate the scene relative to the position of the scene |
582 | | // and then the objects in the scene |
583 | | |
584 | | void E3dScene::NbcSetTransform(const basegfx::B3DHomMatrix& rMatrix) |
585 | 3.50k | { |
586 | 3.50k | if(maTransformation != rMatrix) |
587 | 3.50k | { |
588 | | // call parent |
589 | 3.50k | E3dObject::NbcSetTransform(rMatrix); |
590 | 3.50k | } |
591 | 3.50k | } |
592 | | |
593 | | void E3dScene::SetTransform(const basegfx::B3DHomMatrix& rMatrix) |
594 | 0 | { |
595 | 0 | if(rMatrix != maTransformation) |
596 | 0 | { |
597 | | // call parent |
598 | 0 | E3dObject::SetTransform(rMatrix); |
599 | 0 | } |
600 | 0 | } |
601 | | |
602 | | void E3dScene::NbcRotate(const Point& rRef, Degree100 nAngle, double sn, double cs) |
603 | 0 | { |
604 | | // So currently the gluepoints are defined relative to the scene aOutRect. |
605 | | // Before turning the gluepoints are defined relative to the page. They |
606 | | // take no part in the rotation of the scene. To ensure this, there is the |
607 | | // SetGlueReallyAbsolute(sal_True); |
608 | | |
609 | | // So that was the scene, now the objects used in the scene |
610 | | // 3D objects, if there is only one it can still have multiple surfaces but |
611 | | // the surfaces do not have to be connected. This allows you to access child |
612 | | // objects. So going through the entire list and rotate around the Z axis |
613 | | // through the enter of aOutRect's (Steiner's theorem), so RotateZ |
614 | |
|
615 | 0 | RotateScene (rRef, sn, cs); // Rotates the scene |
616 | 0 | double fAngleInRad = toRadians(nAngle); |
617 | |
|
618 | 0 | basegfx::B3DHomMatrix aRotation; |
619 | 0 | aRotation.rotate(0.0, 0.0, fAngleInRad); |
620 | 0 | NbcSetTransform(aRotation * GetTransform()); |
621 | |
|
622 | 0 | SetBoundAndSnapRectsDirty(); // This forces a recalculation of all BoundRects |
623 | 0 | NbcRotateGluePoints(rRef,nAngle,sn,cs); // Rotate the gluepoints (who still |
624 | | // have coordinates relative to the |
625 | | // original page) |
626 | 0 | SetGlueReallyAbsolute(false); // from now they are again relative to BoundRect (that is defined as aOutRect) |
627 | 0 | SetBoundAndSnapRectsDirty(); |
628 | 0 | } |
629 | | |
630 | | void E3dScene::RecalcSnapRect() |
631 | 3.50k | { |
632 | 3.50k | E3dScene* pScene(getRootE3dSceneFromE3dObject()); |
633 | | |
634 | 3.50k | if(pScene == this) |
635 | 3.50k | { |
636 | | // The Scene is used as a 2D-Object, take the SnapRect from the |
637 | | // 2D Display settings |
638 | 3.50k | maSnapRect = pScene->m_aCamera.GetDeviceWindow(); |
639 | 3.50k | } |
640 | 0 | else |
641 | 0 | { |
642 | | // The Scene itself is a member of another scene, get the SnapRect |
643 | | // as a composite object |
644 | | // call parent |
645 | 0 | E3dObject::RecalcSnapRect(); |
646 | |
|
647 | 0 | for (const rtl::Reference<SdrObject>& pObj : *this) |
648 | 0 | { |
649 | 0 | E3dObject* pCandidate(DynCastE3dObject(pObj.get())); |
650 | |
|
651 | 0 | if(pCandidate) |
652 | 0 | { |
653 | 0 | maSnapRect.Union(pCandidate->GetSnapRect()); |
654 | 0 | } |
655 | 0 | } |
656 | 0 | } |
657 | 3.50k | } |
658 | | |
659 | | bool E3dScene::IsBreakObjPossible() |
660 | 0 | { |
661 | | // Break scene, if all members are able to break |
662 | 0 | SdrObjListIter a3DIterator(GetSubList(), SdrIterMode::DeepWithGroups); |
663 | |
|
664 | 0 | while ( a3DIterator.IsMore() ) |
665 | 0 | { |
666 | 0 | E3dObject* pObj = static_cast<E3dObject*>(a3DIterator.Next()); |
667 | 0 | if(!pObj->IsBreakObjPossible()) |
668 | 0 | return false; |
669 | 0 | } |
670 | | |
671 | 0 | return true; |
672 | 0 | } |
673 | | |
674 | | basegfx::B2DPolyPolygon E3dScene::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const |
675 | 0 | { |
676 | 0 | return TakeXorPoly(); |
677 | 0 | } |
678 | | |
679 | | bool E3dScene::BegCreate(SdrDragStat& rStat) |
680 | 0 | { |
681 | 0 | rStat.SetOrtho4Possible(); |
682 | 0 | tools::Rectangle aRect1(rStat.GetStart(), rStat.GetNow()); |
683 | 0 | aRect1.Normalize(); |
684 | 0 | rStat.SetActionRect(aRect1); |
685 | 0 | NbcSetSnapRect(aRect1); |
686 | 0 | return true; |
687 | 0 | } |
688 | | |
689 | | bool E3dScene::MovCreate(SdrDragStat& rStat) |
690 | 0 | { |
691 | 0 | tools::Rectangle aRect1; |
692 | 0 | rStat.TakeCreateRect(aRect1); |
693 | 0 | aRect1.Normalize(); |
694 | 0 | rStat.SetActionRect(aRect1); |
695 | 0 | NbcSetSnapRect(aRect1); |
696 | 0 | SetBoundRectDirty(); |
697 | 0 | m_bSnapRectDirty=true; |
698 | 0 | return true; |
699 | 0 | } |
700 | | |
701 | | bool E3dScene::EndCreate(SdrDragStat& rStat, SdrCreateCmd eCmd) |
702 | 0 | { |
703 | 0 | tools::Rectangle aRect1; |
704 | 0 | rStat.TakeCreateRect(aRect1); |
705 | 0 | aRect1.Normalize(); |
706 | 0 | NbcSetSnapRect(aRect1); |
707 | 0 | SetBoundAndSnapRectsDirty(); |
708 | 0 | return (eCmd==SdrCreateCmd::ForceEnd || rStat.GetPointCount()>=2); |
709 | 0 | } |
710 | | |
711 | | bool E3dScene::BckCreate(SdrDragStat& /*rStat*/) |
712 | 0 | { |
713 | 0 | return false; |
714 | 0 | } |
715 | | |
716 | | void E3dScene::BrkCreate(SdrDragStat& /*rStat*/) |
717 | 0 | { |
718 | 0 | } |
719 | | |
720 | | void E3dScene::SetSelected(bool bNew) |
721 | 0 | { |
722 | | // call parent |
723 | 0 | E3dObject::SetSelected(bNew); |
724 | |
|
725 | 0 | for (const rtl::Reference<SdrObject>& pObj : *this) |
726 | 0 | { |
727 | 0 | E3dObject* pCandidate(DynCastE3dObject(pObj.get())); |
728 | |
|
729 | 0 | if(pCandidate) |
730 | 0 | { |
731 | 0 | pCandidate->SetSelected(bNew); |
732 | 0 | } |
733 | 0 | } |
734 | 0 | } |
735 | | |
736 | | void E3dScene::NbcInsertObject(SdrObject* pObj, size_t nPos) |
737 | 13.8k | { |
738 | | // Is it even a 3D object? |
739 | 13.8k | if(DynCastE3dObject(pObj)) |
740 | 13.8k | { |
741 | | // Normal 3D object, insert means call parent |
742 | 13.8k | SdrObjList::NbcInsertObject(pObj, nPos); |
743 | | |
744 | | // local needed stuff |
745 | 13.8k | InvalidateBoundVolume(); |
746 | 13.8k | StructureChanged(); |
747 | 13.8k | } |
748 | 0 | else |
749 | 0 | { |
750 | | // No 3D object, inserted a page in place in a scene ... |
751 | 0 | if (SdrPage* pPage = getSdrObjectFromSdrObjList()->getSdrPageFromSdrObject()) |
752 | 0 | pPage->InsertObject(pObj, nPos); |
753 | 0 | } |
754 | 13.8k | } |
755 | | |
756 | | void E3dScene::InsertObject(SdrObject* pObj, size_t nPos) |
757 | 13.8k | { |
758 | | // Is it even a 3D object? |
759 | 13.8k | if(DynCastE3dObject(pObj)) |
760 | 13.8k | { |
761 | | // call parent |
762 | 13.8k | SdrObjList::InsertObject(pObj, nPos); |
763 | | |
764 | | // local needed stuff |
765 | 13.8k | InvalidateBoundVolume(); |
766 | 13.8k | StructureChanged(); |
767 | 13.8k | } |
768 | 0 | else |
769 | 0 | { |
770 | | // No 3D object, inserted a page in place in a scene ... |
771 | 0 | if (SdrPage* pPage = getSdrObjectFromSdrObjList()->getSdrPageFromSdrObject()) |
772 | 0 | pPage->InsertObject(pObj, nPos); |
773 | 0 | } |
774 | 13.8k | } |
775 | | |
776 | | rtl::Reference<SdrObject> E3dScene::NbcRemoveObject(size_t nObjNum) |
777 | 0 | { |
778 | | // call parent |
779 | 0 | rtl::Reference<SdrObject> pRetval = SdrObjList::NbcRemoveObject(nObjNum); |
780 | |
|
781 | 0 | InvalidateBoundVolume(); |
782 | 0 | StructureChanged(); |
783 | |
|
784 | 0 | return pRetval; |
785 | 0 | } |
786 | | |
787 | | rtl::Reference<SdrObject> E3dScene::RemoveObject(size_t nObjNum) |
788 | 1.11k | { |
789 | | // call parent |
790 | 1.11k | rtl::Reference<SdrObject> pRetval(SdrObjList::RemoveObject(nObjNum)); |
791 | | |
792 | 1.11k | InvalidateBoundVolume(); |
793 | 1.11k | StructureChanged(); |
794 | | |
795 | 1.11k | return pRetval; |
796 | 1.11k | } |
797 | | |
798 | | void E3dScene::SetBoundAndSnapRectsDirty(bool bNotMyself, bool bRecursive) |
799 | 364k | { |
800 | | // call parent |
801 | 364k | E3dObject::SetBoundAndSnapRectsDirty(bNotMyself, bRecursive); |
802 | | |
803 | 364k | for (const rtl::Reference<SdrObject>& pObj : *this) |
804 | 2.37M | { |
805 | 2.37M | E3dObject* pCandidate = DynCastE3dObject(pObj.get()); |
806 | | |
807 | 2.37M | if(pCandidate) |
808 | 2.37M | { |
809 | 2.37M | pCandidate->SetBoundAndSnapRectsDirty(bNotMyself, false); |
810 | 2.37M | } |
811 | 2.37M | } |
812 | 364k | } |
813 | | |
814 | | void E3dScene::NbcSetLayer(SdrLayerID nLayer) |
815 | 0 | { |
816 | | // call parent |
817 | 0 | E3dObject::NbcSetLayer(nLayer); |
818 | |
|
819 | 0 | for (const rtl::Reference<SdrObject>& pObj : *this) |
820 | 0 | { |
821 | 0 | E3dObject* pCandidate = DynCastE3dObject(pObj.get()); |
822 | |
|
823 | 0 | if(pCandidate) |
824 | 0 | { |
825 | 0 | pCandidate->NbcSetLayer(nLayer); |
826 | 0 | } |
827 | 0 | } |
828 | 0 | } |
829 | | |
830 | | void E3dScene::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage) |
831 | 0 | { |
832 | 0 | if(pOldPage == pNewPage) |
833 | 0 | return; |
834 | | |
835 | | // call parent |
836 | 0 | E3dObject::handlePageChange(pOldPage, pNewPage); |
837 | |
|
838 | 0 | for (const rtl::Reference<SdrObject>& pObj : *this) |
839 | 0 | { |
840 | 0 | E3dObject* pCandidate = DynCastE3dObject(pObj.get()); |
841 | |
|
842 | 0 | if(pCandidate) |
843 | 0 | { |
844 | 0 | pCandidate->handlePageChange(pOldPage, pNewPage); |
845 | 0 | } |
846 | 0 | else |
847 | 0 | { |
848 | 0 | OSL_ENSURE(false, "E3dScene::handlePageChange invalid object list (!)"); |
849 | 0 | } |
850 | 0 | } |
851 | 0 | } |
852 | | |
853 | | SdrObjList* E3dScene::GetSubList() const |
854 | 3.50k | { |
855 | 3.50k | return const_cast< E3dScene* >(this); |
856 | 3.50k | } |
857 | | |
858 | | basegfx::B3DRange E3dScene::RecalcBoundVolume() const |
859 | 0 | { |
860 | 0 | basegfx::B3DRange aRetval; |
861 | |
|
862 | 0 | for (const rtl::Reference<SdrObject>& pObj : *this) |
863 | 0 | { |
864 | 0 | const E3dObject* p3DObject = DynCastE3dObject(pObj.get()); |
865 | |
|
866 | 0 | if(p3DObject) |
867 | 0 | { |
868 | 0 | basegfx::B3DRange aLocalRange(p3DObject->GetBoundVolume()); |
869 | 0 | aLocalRange.transform(p3DObject->GetTransform()); |
870 | 0 | aRetval.expand(aLocalRange); |
871 | 0 | } |
872 | 0 | } |
873 | |
|
874 | 0 | return aRetval; |
875 | 0 | } |
876 | | |
877 | | void E3dScene::SetTransformChanged() |
878 | 3.50k | { |
879 | | // call parent |
880 | 3.50k | E3dObject::SetTransformChanged(); |
881 | | |
882 | 3.50k | for (const rtl::Reference<SdrObject>& pObj : *this) |
883 | 13.8k | { |
884 | 13.8k | E3dObject* pCandidate = DynCastE3dObject(pObj.get()); |
885 | | |
886 | 13.8k | if(pCandidate) |
887 | 13.8k | { |
888 | 13.8k | pCandidate->SetTransformChanged(); |
889 | 13.8k | } |
890 | 13.8k | } |
891 | 3.50k | } |
892 | | |
893 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |