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>
22 #include <svx/svxids.hrc>
23 #include <sfx2/dispatch.hxx>
24 #include <sfx2/viewfrm.hxx>
25 #include <tools/poly.hxx>
27 #include <svx/xlineit0.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>
34 #include <vcl/weld.hxx>
40 #include <ViewShell.hxx>
41 #include <drawdoc.hxx>
42 #include <ViewShellBase.hxx>
43 #include <ToolBarManager.hxx>
44 #include <svx/svx3ditems.hxx>
46 #include <basegfx/polygon/b2dpolygontools.hxx>
48 using namespace com::sun::star
;
53 FuConstruct3dObject::FuConstruct3dObject (
59 : FuConstruct(pViewSh
, pWin
, pView
, pDoc
, rReq
)
63 rtl::Reference
<FuPoor
> FuConstruct3dObject::Create( ViewShell
* pViewSh
, ::sd::Window
* pWin
, ::sd::View
* pView
, SdDrawDocument
* pDoc
, SfxRequest
& rReq
, bool bPermanent
)
65 FuConstruct3dObject
* pFunc
;
66 rtl::Reference
<FuPoor
> xFunc( pFunc
= new FuConstruct3dObject( pViewSh
, pWin
, pView
, pDoc
, rReq
) );
67 xFunc
->DoExecute(rReq
);
68 pFunc
->SetPermanent(bPermanent
);
72 void FuConstruct3dObject::DoExecute( SfxRequest
& rReq
)
74 FuConstruct::DoExecute( rReq
);
75 mpViewShell
->GetViewShellBase().GetToolBarManager()->SetToolBar(
76 ToolBarManager::ToolBarGroup::Function
,
77 ToolBarManager::msDrawingObjectToolBar
);
80 rtl::Reference
<E3dCompoundObject
> FuConstruct3dObject::ImpCreateBasic3DShape()
82 rtl::Reference
<E3dCompoundObject
> p3DObj
;
89 p3DObj
= new E3dCubeObj(
90 mpView
->getSdrModelFromSdrView(),
91 mpView
->Get3DDefaultAttributes(),
92 ::basegfx::B3DPoint(-2500, -2500, -2500),
93 ::basegfx::B3DVector(5000, 5000, 5000));
99 p3DObj
= new E3dSphereObj(
100 mpView
->getSdrModelFromSdrView(),
101 mpView
->Get3DDefaultAttributes(),
102 ::basegfx::B3DPoint(0, 0, 0),
103 ::basegfx::B3DVector(5000, 5000, 5000));
109 XPolygon
aXPoly(Point (0, 1250), 2500, 2500, 0_deg100
, 9000_deg100
, false);
110 aXPoly
.Scale(5.0, 5.0);
112 ::basegfx::B2DPolygon
aB2DPolygon(aXPoly
.getB2DPolygon());
113 if(aB2DPolygon
.areControlPointsUsed())
115 aB2DPolygon
= ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon
);
117 p3DObj
= new E3dLatheObj(
118 mpView
->getSdrModelFromSdrView(),
119 mpView
->Get3DDefaultAttributes(),
120 ::basegfx::B2DPolyPolygon(aB2DPolygon
));
122 /* this is an open object, therefore it has to be handled double-
124 p3DObj
->SetMergedItem(makeSvx3DDoubleSidedItem(true));
128 case SID_3D_HALF_SPHERE
:
130 XPolygon
aXPoly(Point (0, 1250), 2500, 2500, 0_deg100
, 9000_deg100
, false);
131 aXPoly
.Scale(5.0, 5.0);
133 aXPoly
.Insert(0, Point (2400*5, 1250*5), PolyFlags::Normal
);
134 aXPoly
.Insert(0, Point (2000*5, 1250*5), PolyFlags::Normal
);
135 aXPoly
.Insert(0, Point (1500*5, 1250*5), PolyFlags::Normal
);
136 aXPoly
.Insert(0, Point (1000*5, 1250*5), PolyFlags::Normal
);
137 aXPoly
.Insert(0, Point (500*5, 1250*5), PolyFlags::Normal
);
138 aXPoly
.Insert(0, Point (250*5, 1250*5), PolyFlags::Normal
);
139 aXPoly
.Insert(0, Point (50*5, 1250*5), PolyFlags::Normal
);
140 aXPoly
.Insert(0, Point (0, 1250*5), PolyFlags::Normal
);
142 ::basegfx::B2DPolygon
aB2DPolygon(aXPoly
.getB2DPolygon());
143 if(aB2DPolygon
.areControlPointsUsed())
145 aB2DPolygon
= ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon
);
147 p3DObj
= new E3dLatheObj(
148 mpView
->getSdrModelFromSdrView(),
149 mpView
->Get3DDefaultAttributes(),
150 ::basegfx::B2DPolyPolygon(aB2DPolygon
));
156 ::basegfx::B2DPolygon
aB2DPolygon(::basegfx::utils::createPolygonFromCircle(::basegfx::B2DPoint(1000.0, 0.0), 500.0));
157 if(aB2DPolygon
.areControlPointsUsed())
159 aB2DPolygon
= ::basegfx::utils::adaptiveSubdivideByAngle(aB2DPolygon
);
161 p3DObj
= new E3dLatheObj(
162 mpView
->getSdrModelFromSdrView(),
163 mpView
->Get3DDefaultAttributes(),
164 ::basegfx::B2DPolyPolygon(aB2DPolygon
));
168 case SID_3D_CYLINDER
:
170 ::basegfx::B2DPolygon aInnerPoly
;
172 aInnerPoly
.append(::basegfx::B2DPoint(0, 1000*5));
173 aInnerPoly
.append(::basegfx::B2DPoint(50*5, 1000*5));
174 aInnerPoly
.append(::basegfx::B2DPoint(100*5, 1000*5));
175 aInnerPoly
.append(::basegfx::B2DPoint(200*5, 1000*5));
176 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 1000*5));
177 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 1000*5));
178 aInnerPoly
.append(::basegfx::B2DPoint(450*5, 1000*5));
179 aInnerPoly
.append(::basegfx::B2DPoint(500*5, 1000*5));
180 aInnerPoly
.append(::basegfx::B2DPoint(500*5, -1000*5));
181 aInnerPoly
.append(::basegfx::B2DPoint(450*5, -1000*5));
182 aInnerPoly
.append(::basegfx::B2DPoint(400*5, -1000*5));
183 aInnerPoly
.append(::basegfx::B2DPoint(300*5, -1000*5));
184 aInnerPoly
.append(::basegfx::B2DPoint(200*5, -1000*5));
185 aInnerPoly
.append(::basegfx::B2DPoint(100*5, -1000*5));
186 aInnerPoly
.append(::basegfx::B2DPoint(50*5, -1000*5));
187 aInnerPoly
.append(::basegfx::B2DPoint(0, -1000*5));
188 aInnerPoly
.setClosed(true);
190 p3DObj
= new E3dLatheObj(
191 mpView
->getSdrModelFromSdrView(),
192 mpView
->Get3DDefaultAttributes(),
193 ::basegfx::B2DPolyPolygon(aInnerPoly
));
199 ::basegfx::B2DPolygon aInnerPoly
;
201 aInnerPoly
.append(::basegfx::B2DPoint(0, -1000*5));
202 aInnerPoly
.append(::basegfx::B2DPoint(25*5, -900*5));
203 aInnerPoly
.append(::basegfx::B2DPoint(50*5, -800*5));
204 aInnerPoly
.append(::basegfx::B2DPoint(100*5, -600*5));
205 aInnerPoly
.append(::basegfx::B2DPoint(200*5, -200*5));
206 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 200*5));
207 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 600*5));
208 aInnerPoly
.append(::basegfx::B2DPoint(500*5, 1000*5));
209 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 1000*5));
210 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 1000*5));
211 aInnerPoly
.append(::basegfx::B2DPoint(200*5, 1000*5));
212 aInnerPoly
.append(::basegfx::B2DPoint(100*5, 1000*5));
213 aInnerPoly
.append(::basegfx::B2DPoint(50*5, 1000*5));
214 aInnerPoly
.append(::basegfx::B2DPoint(0, 1000*5));
215 aInnerPoly
.setClosed(true);
217 p3DObj
= new E3dLatheObj(
218 mpView
->getSdrModelFromSdrView(),
219 mpView
->Get3DDefaultAttributes(),
220 ::basegfx::B2DPolyPolygon(aInnerPoly
));
226 ::basegfx::B2DPolygon aInnerPoly
;
228 aInnerPoly
.append(::basegfx::B2DPoint(0, -1000*5));
229 aInnerPoly
.append(::basegfx::B2DPoint(25*5, -900*5));
230 aInnerPoly
.append(::basegfx::B2DPoint(50*5, -800*5));
231 aInnerPoly
.append(::basegfx::B2DPoint(100*5, -600*5));
232 aInnerPoly
.append(::basegfx::B2DPoint(200*5, -200*5));
233 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 200*5));
234 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 600*5));
235 aInnerPoly
.append(::basegfx::B2DPoint(500*5, 1000*5));
236 aInnerPoly
.append(::basegfx::B2DPoint(400*5, 1000*5));
237 aInnerPoly
.append(::basegfx::B2DPoint(300*5, 1000*5));
238 aInnerPoly
.append(::basegfx::B2DPoint(200*5, 1000*5));
239 aInnerPoly
.append(::basegfx::B2DPoint(100*5, 1000*5));
240 aInnerPoly
.append(::basegfx::B2DPoint(50*5, 1000*5));
241 aInnerPoly
.append(::basegfx::B2DPoint(0, 1000*5));
242 aInnerPoly
.setClosed(true);
244 p3DObj
= new E3dLatheObj(
245 mpView
->getSdrModelFromSdrView(),
246 mpView
->Get3DDefaultAttributes(),
247 ::basegfx::B2DPolyPolygon(aInnerPoly
));
248 p3DObj
->SetMergedItem(makeSvx3DHorizontalSegmentsItem(4));
256 void FuConstruct3dObject::ImpPrepareBasic3DShape(E3dCompoundObject
const * p3DObj
, E3dScene
*pScene
)
258 Camera3D aCamera
= pScene
->GetCamera ();
260 // get transformed BoundVolume of the new object
261 basegfx::B3DRange aBoundVol
;
262 basegfx::B3DRange
aObjVol(p3DObj
->GetBoundVolume());
263 aObjVol
.transform(p3DObj
->GetTransform());
264 aBoundVol
.expand(aObjVol
);
265 double fDeepth(aBoundVol
.getDepth());
267 aCamera
.SetPRP(::basegfx::B3DPoint(0.0, 0.0, 1000.0));
268 aCamera
.SetPosition(::basegfx::B3DPoint(0.0, 0.0, mpView
->GetDefaultCamPosZ() + fDeepth
/ 2));
269 aCamera
.SetFocalLength(mpView
->GetDefaultCamFocal());
270 pScene
->SetCamera(aCamera
);
271 basegfx::B3DHomMatrix aTransformation
;
277 aTransformation
.rotate(basegfx::deg2rad(20), 0.0, 0.0);
287 case SID_3D_HALF_SPHERE
:
289 aTransformation
.rotate(basegfx::deg2rad(200), 0.0, 0.0);
293 case SID_3D_CYLINDER
:
302 aTransformation
.rotate(basegfx::deg2rad(90), 0.0, 0.0);
312 pScene
->SetTransform(aTransformation
* pScene
->GetTransform());
314 SfxItemSet
aAttr (mpViewShell
->GetPool());
315 pScene
->SetMergedItemSetAndBroadcast(aAttr
);
318 bool FuConstruct3dObject::MouseButtonDown(const MouseEvent
& rMEvt
)
320 bool bReturn
= FuConstruct::MouseButtonDown(rMEvt
);
322 if ( rMEvt
.IsLeft() && !mpView
->IsAction() )
324 Point
aPnt( mpWindow
->PixelToLogic( rMEvt
.GetPosPixel() ) );
326 mpWindow
->CaptureMouse();
327 sal_uInt16 nDrgLog
= sal_uInt16 ( mpWindow
->PixelToLogic(Size(mpView
->GetDragThresholdPixels(),0)).Width() );
329 weld::WaitObject
aWait(mpViewShell
->GetFrameWeld());
331 rtl::Reference
<E3dCompoundObject
> p3DObj
= ImpCreateBasic3DShape();
332 rtl::Reference
<E3dScene
> pScene
= mpView
->SetCurrent3DObj(p3DObj
.get());
334 ImpPrepareBasic3DShape(p3DObj
.get(), pScene
.get());
335 bReturn
= mpView
->BegCreatePreparedObject(aPnt
, nDrgLog
, pScene
.get());
337 SdrObject
* pObj
= mpView
->GetCreateObj();
341 SfxItemSet
aAttr(mpDoc
->GetPool());
342 SetStyleSheet(aAttr
, pObj
);
345 aAttr
.Put(XLineStyleItem (drawing::LineStyle_NONE
));
347 pObj
->SetMergedItemSet(aAttr
);
354 bool FuConstruct3dObject::MouseButtonUp(const MouseEvent
& rMEvt
)
356 bool bReturn
= false;
358 if ( mpView
->IsCreateObj() && rMEvt
.IsLeft() )
360 if( mpView
->EndCreateObj( SdrCreateCmd::ForceEnd
) )
366 //Drag was too small to create object, so insert default object at click pos
367 Point
aClickPos(mpWindow
->PixelToLogic(rMEvt
.GetPosPixel()));
368 sal_uInt32
nDefaultObjectSize(1000);
369 sal_Int32
nCenterOffset(-sal_Int32(nDefaultObjectSize
/ 2));
370 aClickPos
.AdjustX(nCenterOffset
);
371 aClickPos
.AdjustY(nCenterOffset
);
373 SdrPageView
*pPV
= mpView
->GetSdrPageView();
375 if(mpView
->IsSnapEnabled())
376 aClickPos
= mpView
->GetSnapPos(aClickPos
, pPV
);
378 ::tools::Rectangle
aNewObjectRectangle(aClickPos
, Size(nDefaultObjectSize
, nDefaultObjectSize
));
379 rtl::Reference
<SdrObject
> pObjDefault
= CreateDefaultObject(nSlotId
, aNewObjectRectangle
);
381 bReturn
= mpView
->InsertObjectAtView(pObjDefault
.get(), *pPV
);
384 bReturn
= FuConstruct::MouseButtonUp(rMEvt
) || bReturn
;
387 mpViewShell
->GetViewFrame()->GetDispatcher()->Execute(SID_OBJECT_SELECT
, SfxCallMode::ASYNCHRON
);
392 void FuConstruct3dObject::Activate()
394 mpView
->SetCurrentObj(SdrObjKind::NONE
);
396 FuConstruct::Activate();
399 rtl::Reference
<SdrObject
> FuConstruct3dObject::CreateDefaultObject(const sal_uInt16 nID
, const ::tools::Rectangle
& rRectangle
)
402 rtl::Reference
<E3dCompoundObject
> p3DObj
= ImpCreateBasic3DShape();
404 // E3dView::SetCurrent3DObj part
405 // get transformed BoundVolume of the object
406 basegfx::B3DRange
aObjVol(p3DObj
->GetBoundVolume());
407 aObjVol
.transform(p3DObj
->GetTransform());
408 basegfx::B3DRange
aVolume(aObjVol
);
409 double fW(aVolume
.getWidth());
410 double fH(aVolume
.getHeight());
411 ::tools::Rectangle
a3DRect(0, 0, static_cast<::tools::Long
>(fW
), static_cast<::tools::Long
>(fH
));
412 rtl::Reference
< E3dScene
> pScene(new E3dScene(*mpDoc
));
414 // copied code from E3dView::InitScene
415 double fCamZ(aVolume
.getMaxZ() + ((fW
+ fH
) / 4.0));
416 Camera3D
aCam(pScene
->GetCamera());
417 aCam
.SetAutoAdjustProjection(false);
418 aCam
.SetViewWindow(- fW
/ 2, - fH
/ 2, fW
, fH
);
419 ::basegfx::B3DPoint aLookAt
;
420 double fDefaultCamPosZ
= mpView
->GetDefaultCamPosZ();
421 ::basegfx::B3DPoint
aCamPos(0.0, 0.0, fCamZ
< fDefaultCamPosZ
? fDefaultCamPosZ
: fCamZ
);
422 aCam
.SetPosAndLookAt(aCamPos
, aLookAt
);
423 aCam
.SetFocalLength(mpView
->GetDefaultCamFocal());
424 pScene
->SetCamera(aCam
);
425 pScene
->InsertObject(p3DObj
.get());
426 pScene
->NbcSetSnapRect(a3DRect
);
427 ImpPrepareBasic3DShape(p3DObj
.get(), pScene
.get());
428 SfxItemSet
aAttr(mpDoc
->GetPool());
429 SetStyleSheet(aAttr
, p3DObj
.get());
430 aAttr
.Put(XLineStyleItem (drawing::LineStyle_NONE
));
431 p3DObj
->SetMergedItemSet(aAttr
);
433 // make object interactive at once
434 pScene
->SetBoundAndSnapRectsDirty();
436 // Take care of restrictions for the rectangle
437 ::tools::Rectangle
aRect(rRectangle
);
446 ImpForceQuadratic(aRect
);
451 case SID_3D_HALF_SPHERE
:
453 // force horizontal layout
457 case SID_3D_CYLINDER
:
461 // force vertical layout
466 // use changed rectangle, not original one
467 pScene
->SetLogicRect(aRect
);
472 } // end of namespace sd
474 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */