1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <fucon3d.hxx>
21 #include <vcl/waitobj.hxx>
23 #include <svx/svxids.hrc>
24 #include <sfx2/dispatch.hxx>
25 #include <sfx2/viewfrm.hxx>
26 #include <tools/poly.hxx>
28 #include <svx/scene3d.hxx>
29 #include <svx/sphere3d.hxx>
30 #include <svx/cube3d.hxx>
31 #include <svx/lathe3d.hxx>
32 #include <svx/camera3d.hxx>
38 #include <ViewShell.hxx>
39 #include <drawdoc.hxx>
40 #include <ViewShellBase.hxx>
41 #include <ToolBarManager.hxx>
42 #include <svx/svx3ditems.hxx>
44 #include <basegfx/polygon/b2dpolygontools.hxx>
46 using namespace com::sun::star
;
51 FuConstruct3dObject::FuConstruct3dObject (
57 : FuConstruct(pViewSh
, pWin
, pView
, pDoc
, rReq
)
61 rtl::Reference
<FuPoor
> FuConstruct3dObject::Create( ViewShell
* pViewSh
, ::sd::Window
* pWin
, ::sd::View
* pView
, SdDrawDocument
* pDoc
, SfxRequest
& rReq
, bool bPermanent
)
63 FuConstruct3dObject
* pFunc
;
64 rtl::Reference
<FuPoor
> xFunc( pFunc
= new FuConstruct3dObject( pViewSh
, pWin
, pView
, pDoc
, rReq
) );
65 xFunc
->DoExecute(rReq
);
66 pFunc
->SetPermanent(bPermanent
);
70 void FuConstruct3dObject::DoExecute( SfxRequest
& rReq
)
72 FuConstruct::DoExecute( rReq
);
73 mpViewShell
->GetViewShellBase().GetToolBarManager()->SetToolBar(
74 ToolBarManager::ToolBarGroup::Function
,
75 ToolBarManager::msDrawingObjectToolBar
);
78 E3dCompoundObject
* FuConstruct3dObject::ImpCreateBasic3DShape()
80 E3dCompoundObject
* p3DObj
= nullptr;
87 p3DObj
= new E3dCubeObj(
88 mpView
->getSdrModelFromSdrView(),
89 mpView
->Get3DDefaultAttributes(),
90 ::basegfx::B3DPoint(-2500, -2500, -2500),
91 ::basegfx::B3DVector(5000, 5000, 5000));
97 p3DObj
= new E3dSphereObj(
98 mpView
->getSdrModelFromSdrView(),
99 mpView
->Get3DDefaultAttributes(),
100 ::basegfx::B3DPoint(0, 0, 0),
101 ::basegfx::B3DVector(5000, 5000, 5000));
107 XPolygon
aXPoly(Point (0, 1250), 2500, 2500, 0, 900, false);
108 aXPoly
.Scale(5.0, 5.0);
110 ::basegfx::B2DPolygon
aB2DPolygon(aXPoly
.getB2DPolygon());
111 if(aB2DPolygon
.areControlPointsUsed())
113 aB2DPolygon
= ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon
);
115 p3DObj
= new E3dLatheObj(
116 mpView
->getSdrModelFromSdrView(),
117 mpView
->Get3DDefaultAttributes(),
118 ::basegfx::B2DPolyPolygon(aB2DPolygon
));
120 /* this is an open object, therefore it has to be handled double-
122 p3DObj
->SetMergedItem(makeSvx3DDoubleSidedItem(true));
126 case SID_3D_HALF_SPHERE
:
128 XPolygon
aXPoly(Point (0, 1250), 2500, 2500, 0, 900, false);
129 aXPoly
.Scale(5.0, 5.0);
131 aXPoly
.Insert(0, Point (2400*5, 1250*5), PolyFlags::Normal
);
132 aXPoly
.Insert(0, Point (2000*5, 1250*5), PolyFlags::Normal
);
133 aXPoly
.Insert(0, Point (1500*5, 1250*5), PolyFlags::Normal
);
134 aXPoly
.Insert(0, Point (1000*5, 1250*5), PolyFlags::Normal
);
135 aXPoly
.Insert(0, Point (500*5, 1250*5), PolyFlags::Normal
);
136 aXPoly
.Insert(0, Point (250*5, 1250*5), PolyFlags::Normal
);
137 aXPoly
.Insert(0, Point (50*5, 1250*5), PolyFlags::Normal
);
138 aXPoly
.Insert(0, Point (0, 1250*5), PolyFlags::Normal
);
140 ::basegfx::B2DPolygon
aB2DPolygon(aXPoly
.getB2DPolygon());
141 if(aB2DPolygon
.areControlPointsUsed())
143 aB2DPolygon
= ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon
);
145 p3DObj
= new E3dLatheObj(
146 mpView
->getSdrModelFromSdrView(),
147 mpView
->Get3DDefaultAttributes(),
148 ::basegfx::B2DPolyPolygon(aB2DPolygon
));
154 ::basegfx::B2DPolygon
aB2DPolygon(::basegfx::utils::createPolygonFromCircle(::basegfx::B2DPoint(1000.0, 0.0), 500.0));
155 if(aB2DPolygon
.areControlPointsUsed())
157 aB2DPolygon
= ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon
);
159 p3DObj
= new E3dLatheObj(
160 mpView
->getSdrModelFromSdrView(),
161 mpView
->Get3DDefaultAttributes(),
162 ::basegfx::B2DPolyPolygon(aB2DPolygon
));
166 case SID_3D_CYLINDER
:
168 ::basegfx::B2DPolygon aInnerPoly
;
170 aInnerPoly
.append(::basegfx::B2DPoint(0, 1000*5));
171 aInnerPoly
.append(::basegfx::B2DPoint(50*5, 1000*5));
172 aInnerPoly
.append(::basegfx::B2DPoint(100*5, 1000*5));
173 aInnerPoly
.append(::basegfx::B2DPoint(200*5, 1000*5));
174 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 1000*5));
175 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 1000*5));
176 aInnerPoly
.append(::basegfx::B2DPoint(450*5, 1000*5));
177 aInnerPoly
.append(::basegfx::B2DPoint(500*5, 1000*5));
178 aInnerPoly
.append(::basegfx::B2DPoint(500*5, -1000*5));
179 aInnerPoly
.append(::basegfx::B2DPoint(450*5, -1000*5));
180 aInnerPoly
.append(::basegfx::B2DPoint(400*5, -1000*5));
181 aInnerPoly
.append(::basegfx::B2DPoint(300*5, -1000*5));
182 aInnerPoly
.append(::basegfx::B2DPoint(200*5, -1000*5));
183 aInnerPoly
.append(::basegfx::B2DPoint(100*5, -1000*5));
184 aInnerPoly
.append(::basegfx::B2DPoint(50*5, -1000*5));
185 aInnerPoly
.append(::basegfx::B2DPoint(0, -1000*5));
186 aInnerPoly
.setClosed(true);
188 p3DObj
= new E3dLatheObj(
189 mpView
->getSdrModelFromSdrView(),
190 mpView
->Get3DDefaultAttributes(),
191 ::basegfx::B2DPolyPolygon(aInnerPoly
));
197 ::basegfx::B2DPolygon aInnerPoly
;
199 aInnerPoly
.append(::basegfx::B2DPoint(0, -1000*5));
200 aInnerPoly
.append(::basegfx::B2DPoint(25*5, -900*5));
201 aInnerPoly
.append(::basegfx::B2DPoint(50*5, -800*5));
202 aInnerPoly
.append(::basegfx::B2DPoint(100*5, -600*5));
203 aInnerPoly
.append(::basegfx::B2DPoint(200*5, -200*5));
204 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 200*5));
205 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 600*5));
206 aInnerPoly
.append(::basegfx::B2DPoint(500*5, 1000*5));
207 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 1000*5));
208 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 1000*5));
209 aInnerPoly
.append(::basegfx::B2DPoint(200*5, 1000*5));
210 aInnerPoly
.append(::basegfx::B2DPoint(100*5, 1000*5));
211 aInnerPoly
.append(::basegfx::B2DPoint(50*5, 1000*5));
212 aInnerPoly
.append(::basegfx::B2DPoint(0, 1000*5));
213 aInnerPoly
.setClosed(true);
215 p3DObj
= new E3dLatheObj(
216 mpView
->getSdrModelFromSdrView(),
217 mpView
->Get3DDefaultAttributes(),
218 ::basegfx::B2DPolyPolygon(aInnerPoly
));
224 ::basegfx::B2DPolygon aInnerPoly
;
226 aInnerPoly
.append(::basegfx::B2DPoint(0, -1000*5));
227 aInnerPoly
.append(::basegfx::B2DPoint(25*5, -900*5));
228 aInnerPoly
.append(::basegfx::B2DPoint(50*5, -800*5));
229 aInnerPoly
.append(::basegfx::B2DPoint(100*5, -600*5));
230 aInnerPoly
.append(::basegfx::B2DPoint(200*5, -200*5));
231 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 200*5));
232 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 600*5));
233 aInnerPoly
.append(::basegfx::B2DPoint(500*5, 1000*5));
234 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 1000*5));
235 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 1000*5));
236 aInnerPoly
.append(::basegfx::B2DPoint(200*5, 1000*5));
237 aInnerPoly
.append(::basegfx::B2DPoint(100*5, 1000*5));
238 aInnerPoly
.append(::basegfx::B2DPoint(50*5, 1000*5));
239 aInnerPoly
.append(::basegfx::B2DPoint(0, 1000*5));
240 aInnerPoly
.setClosed(true);
242 p3DObj
= new E3dLatheObj(
243 mpView
->getSdrModelFromSdrView(),
244 mpView
->Get3DDefaultAttributes(),
245 ::basegfx::B2DPolyPolygon(aInnerPoly
));
246 p3DObj
->SetMergedItem(makeSvx3DHorizontalSegmentsItem(4));
254 void FuConstruct3dObject::ImpPrepareBasic3DShape(E3dCompoundObject
const * p3DObj
, E3dScene
*pScene
)
256 Camera3D aCamera
= pScene
->GetCamera ();
258 // get transformed BoundVolume of the new object
259 basegfx::B3DRange aBoundVol
;
260 basegfx::B3DRange
aObjVol(p3DObj
->GetBoundVolume());
261 aObjVol
.transform(p3DObj
->GetTransform());
262 aBoundVol
.expand(aObjVol
);
263 double fDeepth(aBoundVol
.getDepth());
265 aCamera
.SetPRP(::basegfx::B3DPoint(0.0, 0.0, 1000.0));
266 aCamera
.SetPosition(::basegfx::B3DPoint(0.0, 0.0, mpView
->GetDefaultCamPosZ() + fDeepth
/ 2));
267 aCamera
.SetFocalLength(mpView
->GetDefaultCamFocal());
268 pScene
->SetCamera(aCamera
);
269 basegfx::B3DHomMatrix aTransformation
;
275 aTransformation
.rotate(DEG2RAD(20), 0.0, 0.0);
285 case SID_3D_HALF_SPHERE
:
287 aTransformation
.rotate(DEG2RAD(200), 0.0, 0.0);
291 case SID_3D_CYLINDER
:
300 aTransformation
.rotate(DEG2RAD(90), 0.0, 0.0);
310 pScene
->SetTransform(aTransformation
* pScene
->GetTransform());
312 SfxItemSet
aAttr (mpViewShell
->GetPool());
313 pScene
->SetMergedItemSetAndBroadcast(aAttr
);
316 bool FuConstruct3dObject::MouseButtonDown(const MouseEvent
& rMEvt
)
318 bool bReturn
= FuConstruct::MouseButtonDown(rMEvt
);
320 if ( rMEvt
.IsLeft() && !mpView
->IsAction() )
322 Point
aPnt( mpWindow
->PixelToLogic( rMEvt
.GetPosPixel() ) );
324 mpWindow
->CaptureMouse();
325 sal_uInt16 nDrgLog
= sal_uInt16 ( mpWindow
->PixelToLogic(Size(DRGPIX
,0)).Width() );
327 WaitObject
aWait( static_cast<vcl::Window
*>(mpViewShell
->GetActiveWindow()) );
329 E3dCompoundObject
* p3DObj
= ImpCreateBasic3DShape();
330 E3dScene
* pScene
= mpView
->SetCurrent3DObj(p3DObj
);
332 ImpPrepareBasic3DShape(p3DObj
, pScene
);
333 bReturn
= mpView
->BegCreatePreparedObject(aPnt
, nDrgLog
, pScene
);
335 SdrObject
* pObj
= mpView
->GetCreateObj();
339 SfxItemSet
aAttr(mpDoc
->GetPool());
340 SetStyleSheet(aAttr
, pObj
);
343 aAttr
.Put(XLineStyleItem (drawing::LineStyle_NONE
));
345 pObj
->SetMergedItemSet(aAttr
);
352 bool FuConstruct3dObject::MouseButtonUp(const MouseEvent
& rMEvt
)
354 bool bReturn
= false;
356 if ( mpView
->IsCreateObj() && rMEvt
.IsLeft() )
358 mpView
->EndCreateObj(SdrCreateCmd::ForceEnd
);
362 bReturn
= FuConstruct::MouseButtonUp(rMEvt
) || bReturn
;
365 mpViewShell
->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT
, SfxCallMode::ASYNCHRON
);
370 void FuConstruct3dObject::Activate()
372 mpView
->SetCurrentObj(OBJ_NONE
);
374 FuConstruct::Activate();
377 SdrObjectUniquePtr
FuConstruct3dObject::CreateDefaultObject(const sal_uInt16 nID
, const ::tools::Rectangle
& rRectangle
)
380 E3dCompoundObject
* p3DObj
= ImpCreateBasic3DShape();
382 // E3dView::SetCurrent3DObj part
383 // get transformed BoundVolume of the object
384 basegfx::B3DRange
aObjVol(p3DObj
->GetBoundVolume());
385 aObjVol
.transform(p3DObj
->GetTransform());
386 basegfx::B3DRange
aVolume(aObjVol
);
387 double fW(aVolume
.getWidth());
388 double fH(aVolume
.getHeight());
389 ::tools::Rectangle
a3DRect(0, 0, static_cast<long>(fW
), static_cast<long>(fH
));
390 std::unique_ptr
< E3dScene
, SdrObjectFreeOp
> pScene(new E3dScene(*mpDoc
));
392 // copied code from E3dView::InitScene
393 double fCamZ(aVolume
.getMaxZ() + ((fW
+ fH
) / 4.0));
394 Camera3D
aCam(pScene
->GetCamera());
395 aCam
.SetAutoAdjustProjection(false);
396 aCam
.SetViewWindow(- fW
/ 2, - fH
/ 2, fW
, fH
);
397 ::basegfx::B3DPoint aLookAt
;
398 double fDefaultCamPosZ
= mpView
->GetDefaultCamPosZ();
399 ::basegfx::B3DPoint
aCamPos(0.0, 0.0, fCamZ
< fDefaultCamPosZ
? fDefaultCamPosZ
: fCamZ
);
400 aCam
.SetPosAndLookAt(aCamPos
, aLookAt
);
401 aCam
.SetFocalLength(mpView
->GetDefaultCamFocal());
402 pScene
->SetCamera(aCam
);
403 pScene
->InsertObject(p3DObj
);
404 pScene
->NbcSetSnapRect(a3DRect
);
405 ImpPrepareBasic3DShape(p3DObj
, pScene
.get());
406 SfxItemSet
aAttr(mpDoc
->GetPool());
407 SetStyleSheet(aAttr
, p3DObj
);
408 aAttr
.Put(XLineStyleItem (drawing::LineStyle_NONE
));
409 p3DObj
->SetMergedItemSet(aAttr
);
411 // make object interactive at once
412 pScene
->SetRectsDirty();
414 // Take care of restrictions for the rectangle
415 ::tools::Rectangle
aRect(rRectangle
);
424 ImpForceQuadratic(aRect
);
429 case SID_3D_HALF_SPHERE
:
431 // force horizontal layout
435 case SID_3D_CYLINDER
:
439 // force vertical layout
444 // use changed rectangle, not original one
445 pScene
->SetLogicRect(aRect
);
447 return SdrObjectUniquePtr(pScene
.release());
450 } // end of namespace sd
452 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */