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 "DragMethod_RotateDiagram.hxx"
21 #include <DrawViewWrapper.hxx>
22 
23 #include <SelectionHelper.hxx>
24 #include <ChartModelHelper.hxx>
25 #include <DiagramHelper.hxx>
26 #include <ChartTypeHelper.hxx>
27 #include <ThreeDHelper.hxx>
28 #include <defines.hxx>
29 #include <svx/sdr/overlay/overlaypolypolygon.hxx>
30 
31 #include <svx/scene3d.hxx>
32 #include <basegfx/matrix/b3dhommatrix.hxx>
33 #include <com/sun/star/beans/XPropertySet.hpp>
34 #include <com/sun/star/frame/XModel.hpp>
35 #include <basegfx/polygon/b2dpolypolygontools.hxx>
36 #include <svx/sdr/contact/viewcontactofe3dscene.hxx>
37 #include <drawinglayer/geometry/viewinformation3d.hxx>
38 
39 namespace chart
40 {
41 
42 using namespace ::com::sun::star;
43 using ::com::sun::star::uno::Reference;
44 
DragMethod_RotateDiagram(DrawViewWrapper & rDrawViewWrapper,const OUString & rObjectCID,const Reference<frame::XModel> & xChartModel,RotationDirection eRotationDirection)45 DragMethod_RotateDiagram::DragMethod_RotateDiagram( DrawViewWrapper& rDrawViewWrapper
46         , const OUString& rObjectCID
47         , const Reference< frame::XModel >& xChartModel
48         , RotationDirection eRotationDirection )
49     : DragMethod_Base( rDrawViewWrapper, rObjectCID, xChartModel, ActionDescriptionProvider::ActionType::Rotate )
50     , m_pScene(nullptr)
51     , m_aReferenceRect(100,100,100,100)
52     , m_aStartPos(0,0)
53     , m_aWireframePolyPolygon()
54     , m_fInitialXAngleRad(0.0)
55     , m_fInitialYAngleRad(0.0)
56     , m_fInitialZAngleRad(0.0)
57     , m_fAdditionalXAngleRad(0.0)
58     , m_fAdditionalYAngleRad(0.0)
59     , m_fAdditionalZAngleRad(0.0)
60     , m_nInitialHorizontalAngleDegree(0)
61     , m_nInitialVerticalAngleDegree(0)
62     , m_nAdditionalHorizontalAngleDegree(0)
63     , m_nAdditionalVerticalAngleDegree(0)
64     , m_eRotationDirection(eRotationDirection)
65     , m_bRightAngledAxes(false)
66 {
67     m_pScene = SelectionHelper::getSceneToRotate( rDrawViewWrapper.getNamedSdrObject( rObjectCID ) );
68     SdrObject* pObj = rDrawViewWrapper.getSelectedObject();
69     if(!(pObj && m_pScene))
70         return;
71 
72     m_aReferenceRect = pObj->GetLogicRect();
73 
74     m_aWireframePolyPolygon = m_pScene->CreateWireframe();
75 
76     uno::Reference< chart2::XDiagram > xDiagram( ChartModelHelper::findDiagram(getChartModel()) );
77     uno::Reference< beans::XPropertySet > xDiagramProperties( xDiagram, uno::UNO_QUERY );
78     if( !xDiagramProperties.is() )
79         return;
80 
81     ThreeDHelper::getRotationFromDiagram( xDiagramProperties
82         , m_nInitialHorizontalAngleDegree, m_nInitialVerticalAngleDegree );
83 
84     ThreeDHelper::getRotationAngleFromDiagram( xDiagramProperties
85         , m_fInitialXAngleRad, m_fInitialYAngleRad, m_fInitialZAngleRad );
86 
87     if( ChartTypeHelper::isSupportingRightAngledAxes(
88         DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
89         xDiagramProperties->getPropertyValue("RightAngledAxes") >>= m_bRightAngledAxes;
90     if(m_bRightAngledAxes)
91     {
92         if( m_eRotationDirection==ROTATIONDIRECTION_Z )
93             m_eRotationDirection=ROTATIONDIRECTION_FREE;
94         ThreeDHelper::adaptRadAnglesForRightAngledAxes( m_fInitialXAngleRad, m_fInitialYAngleRad );
95     }
96 }
~DragMethod_RotateDiagram()97 DragMethod_RotateDiagram::~DragMethod_RotateDiagram()
98 {
99 }
GetSdrDragComment() const100 OUString DragMethod_RotateDiagram::GetSdrDragComment() const
101 {
102     return OUString();
103 }
BeginSdrDrag()104 bool DragMethod_RotateDiagram::BeginSdrDrag()
105 {
106     m_aStartPos = DragStat().GetStart();
107     Show();
108     return true;
109 }
MoveSdrDrag(const Point & rPnt)110 void DragMethod_RotateDiagram::MoveSdrDrag(const Point& rPnt)
111 {
112     if( !DragStat().CheckMinMoved(rPnt) )
113         return;
114 
115     Hide();
116 
117     //calculate new angle
118     double fX = F_PI2 * static_cast<double>(rPnt.Y() - m_aStartPos.Y())
119         / (m_aReferenceRect.GetHeight() > 0 ? static_cast<double>(m_aReferenceRect.GetHeight()) : 1.0);
120     double fY = F_PI * static_cast<double>(rPnt.X() - m_aStartPos.X())
121         / (m_aReferenceRect.GetWidth() > 0 ? static_cast<double>(m_aReferenceRect.GetWidth()) : 1.0);
122 
123     if( m_eRotationDirection != ROTATIONDIRECTION_Y )
124         m_fAdditionalYAngleRad = fY;
125     else
126         m_fAdditionalYAngleRad = 0.0;
127     if( m_eRotationDirection != ROTATIONDIRECTION_X )
128         m_fAdditionalXAngleRad = fX;
129     else
130         m_fAdditionalXAngleRad = 0.0;
131     m_fAdditionalZAngleRad = 0.0;
132 
133     if( m_eRotationDirection == ROTATIONDIRECTION_Z )
134     {
135         m_fAdditionalXAngleRad = 0.0;
136         m_fAdditionalYAngleRad = 0.0;
137 
138         double fCx = m_aReferenceRect.Center().X();
139         double fCy = m_aReferenceRect.Center().Y();
140 
141         m_fAdditionalZAngleRad = atan((fCx - m_aStartPos.X())/(m_aStartPos.Y()-fCy))
142             + atan((fCx - rPnt.X())/(fCy-rPnt.Y()));
143     }
144 
145     m_nAdditionalHorizontalAngleDegree = static_cast<sal_Int32>(basegfx::rad2deg(m_fAdditionalXAngleRad));
146     m_nAdditionalVerticalAngleDegree = -static_cast<sal_Int32>(basegfx::rad2deg(m_fAdditionalYAngleRad));
147 
148     DragStat().NextMove(rPnt);
149     Show();
150 }
EndSdrDrag(bool)151 bool DragMethod_RotateDiagram::EndSdrDrag(bool /*bCopy*/)
152 {
153     Hide();
154 
155     if( m_bRightAngledAxes || m_eRotationDirection==ROTATIONDIRECTION_Z )
156     {
157         double fResultX = m_fInitialXAngleRad + m_fAdditionalXAngleRad;
158         double fResultY = m_fInitialYAngleRad + m_fAdditionalYAngleRad;
159         double fResultZ = m_fInitialZAngleRad + m_fAdditionalZAngleRad;
160 
161         if(m_bRightAngledAxes)
162             ThreeDHelper::adaptRadAnglesForRightAngledAxes( fResultX, fResultY );
163 
164         ThreeDHelper::setRotationAngleToDiagram( uno::Reference< beans::XPropertySet >( ChartModelHelper::findDiagram( getChartModel() ), uno::UNO_QUERY )
165             , fResultX, fResultY, fResultZ );
166     }
167     else
168     {
169         ThreeDHelper::setRotationToDiagram( ( uno::Reference< beans::XPropertySet >( ChartModelHelper::findDiagram( getChartModel() ), uno::UNO_QUERY ) )
170             , m_nInitialHorizontalAngleDegree+m_nAdditionalHorizontalAngleDegree, m_nInitialVerticalAngleDegree+m_nAdditionalVerticalAngleDegree );
171     }
172 
173     return true;
174 }
CreateOverlayGeometry(sdr::overlay::OverlayManager & rOverlayManager,const sdr::contact::ObjectContact & rObjectContact)175 void DragMethod_RotateDiagram::CreateOverlayGeometry(
176     sdr::overlay::OverlayManager& rOverlayManager,
177     const sdr::contact::ObjectContact& rObjectContact)
178 {
179     ::basegfx::B3DHomMatrix aCurrentTransform;
180     aCurrentTransform.translate( -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
181                                  -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0,
182                                  -FIXED_SIZE_FOR_3D_CHART_VOLUME/2.0 );
183 
184     double fResultX = m_fInitialXAngleRad + m_fAdditionalXAngleRad;
185     double fResultY = m_fInitialYAngleRad + m_fAdditionalYAngleRad;
186     double fResultZ = m_fInitialZAngleRad + m_fAdditionalZAngleRad;
187 
188     if(!m_bRightAngledAxes)
189     {
190         if( m_eRotationDirection!=ROTATIONDIRECTION_Z )
191         {
192             ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
193                 m_nInitialHorizontalAngleDegree+m_nAdditionalHorizontalAngleDegree, -(m_nInitialVerticalAngleDegree+m_nAdditionalVerticalAngleDegree)
194                 , fResultX, fResultY, fResultZ );
195         }
196         aCurrentTransform.rotate( fResultX, fResultY, fResultZ );
197     }
198     else
199     {
200         ThreeDHelper::adaptRadAnglesForRightAngledAxes( fResultX, fResultY );
201         aCurrentTransform.shearXY(fResultY,-fResultX);
202     }
203 
204     if(!(m_aWireframePolyPolygon.count() && m_pScene))
205         return;
206 
207     const sdr::contact::ViewContactOfE3dScene& rVCScene = static_cast< sdr::contact::ViewContactOfE3dScene& >(m_pScene->GetViewContact());
208     const drawinglayer::geometry::ViewInformation3D& aViewInfo3D(rVCScene.getViewInformation3D());
209     const basegfx::B3DHomMatrix aWorldToView(aViewInfo3D.getDeviceToView() * aViewInfo3D.getProjection() * aViewInfo3D.getOrientation());
210     const basegfx::B3DHomMatrix aTransform(aWorldToView * aCurrentTransform);
211 
212     // transform to relative scene coordinates
213     basegfx::B2DPolyPolygon aPolyPolygon(basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(m_aWireframePolyPolygon, aTransform));
214 
215     // transform to 2D view coordinates
216     aPolyPolygon.transform(rVCScene.getObjectTransformation());
217 
218     std::unique_ptr<sdr::overlay::OverlayPolyPolygonStripedAndFilled> pNew(
219         new sdr::overlay::OverlayPolyPolygonStripedAndFilled(
220             aPolyPolygon));
221 
222     insertNewlyCreatedOverlayObjectForSdrDragMethod(
223         std::move(pNew),
224         rObjectContact,
225         rOverlayManager);
226 }
227 } //namespace chart
228 
229 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
230