Coverage Report

Created: 2026-10-14 09:33

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */