1 /***************************************************************************
2 qgslayout3dmapwidget.cpp
3 --------------------------------------
4 Date : August 2018
5 Copyright : (C) 2018 by Martin Dobias
6 Email : wonder dot sk at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgslayout3dmapwidget.h"
17
18 #include "qgisapp.h"
19 #include "qgs3dmapcanvas.h"
20 #include "qgs3dmapcanvasdockwidget.h"
21 #include "qgs3dmapsettings.h"
22 #include "qgscameracontroller.h"
23 #include <QMenu>
24
25
_normalizedAngle(float x)26 float _normalizedAngle( float x )
27 {
28 x = std::fmod( x, 360 );
29 if ( x < 0 ) x += 360;
30 return x;
31 }
32
33 template<typename Func1>
_prepare3DViewsMenu(QMenu * menu,QgsLayout3DMapWidget * w,Func1 slot)34 void _prepare3DViewsMenu( QMenu *menu, QgsLayout3DMapWidget *w, Func1 slot )
35 {
36 QObject::connect( menu, &QMenu::aboutToShow, w, [menu, w, slot]
37 {
38 const QList<Qgs3DMapCanvasDockWidget *> lst = QgisApp::instance()->findChildren<Qgs3DMapCanvasDockWidget *>();
39 menu->clear();
40 for ( auto dock : lst )
41 {
42 QAction *a = menu->addAction( dock->mapCanvas3D()->objectName(), w, slot );
43 // need to use a custom property for identification because Qt likes to add "&" to the action text
44 a->setProperty( "name", dock->mapCanvas3D()->objectName() );
45 }
46 if ( lst.isEmpty() )
47 {
48 menu->addAction( QObject::tr( "No 3D maps defined" ) )->setEnabled( false );
49 }
50 } );
51 }
52
_dock3DViewFromSender(QObject * sender)53 Qgs3DMapCanvasDockWidget *_dock3DViewFromSender( QObject *sender )
54 {
55 QAction *action = qobject_cast<QAction *>( sender );
56 if ( !action )
57 return nullptr;
58
59 QString actionText = action->property( "name" ).toString();
60 const QList<Qgs3DMapCanvasDockWidget *> lst = QgisApp::instance()->findChildren<Qgs3DMapCanvasDockWidget *>();
61 for ( auto dock : lst )
62 {
63 QString objName = dock->mapCanvas3D()->objectName();
64 if ( objName == actionText )
65 {
66 return dock;
67 }
68 }
69 return nullptr;
70 }
71
72
QgsLayout3DMapWidget(QgsLayoutItem3DMap * map3D)73 QgsLayout3DMapWidget::QgsLayout3DMapWidget( QgsLayoutItem3DMap *map3D )
74 : QgsLayoutItemBaseWidget( nullptr, map3D )
75 , mMap3D( map3D )
76 {
77 setupUi( this );
78
79 mCenterXSpinBox->setClearValue( 0 );
80 mCenterYSpinBox->setClearValue( 0 );
81 mCenterZSpinBox->setClearValue( 0 );
82 mDistanceToCenterSpinBox->setClearValue( 1000 );
83
84 //add widget for general composer item properties
85 mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, map3D );
86 mainLayout->addWidget( mItemPropertiesWidget );
87
88 mMenu3DCanvases = new QMenu( this );
89 mCopySettingsButton->setMenu( mMenu3DCanvases );
90 _prepare3DViewsMenu( mMenu3DCanvases, this, &QgsLayout3DMapWidget::copy3DMapSettings );
91
92 mMenu3DCanvasesPose = new QMenu( this );
93 mPoseFromViewButton->setMenu( mMenu3DCanvasesPose );
94 _prepare3DViewsMenu( mMenu3DCanvasesPose, this, &QgsLayout3DMapWidget::copeCameraPose );
95
96 QList<QgsDoubleSpinBox *> lst;
97 lst << mCenterXSpinBox << mCenterYSpinBox << mCenterZSpinBox << mDistanceToCenterSpinBox << mPitchAngleSpinBox << mHeadingAngleSpinBox;
98 for ( QgsDoubleSpinBox *spinBox : qgis::as_const( lst ) )
99 connect( spinBox, qgis::overload<double>::of( &QgsDoubleSpinBox::valueChanged ), this, &QgsLayout3DMapWidget::updateCameraPose );
100
101 updateCameraPoseWidgetsFromItem();
102 }
103
setMasterLayout(QgsMasterLayoutInterface * masterLayout)104 void QgsLayout3DMapWidget::setMasterLayout( QgsMasterLayoutInterface *masterLayout )
105 {
106 if ( mItemPropertiesWidget )
107 mItemPropertiesWidget->setMasterLayout( masterLayout );
108 }
109
updateCameraPoseWidgetsFromItem()110 void QgsLayout3DMapWidget::updateCameraPoseWidgetsFromItem()
111 {
112 QgsCameraPose pose = mMap3D->cameraPose();
113 whileBlocking( mCenterXSpinBox )->setValue( pose.centerPoint().x() );
114 whileBlocking( mCenterYSpinBox )->setValue( pose.centerPoint().y() );
115 whileBlocking( mCenterZSpinBox )->setValue( pose.centerPoint().z() );
116 whileBlocking( mDistanceToCenterSpinBox )->setValue( pose.distanceFromCenterPoint() );
117 whileBlocking( mPitchAngleSpinBox )->setValue( _normalizedAngle( pose.pitchAngle() ) );
118 whileBlocking( mHeadingAngleSpinBox )->setValue( _normalizedAngle( pose.headingAngle() ) );
119 }
120
copy3DMapSettings()121 void QgsLayout3DMapWidget::copy3DMapSettings()
122 {
123 Qgs3DMapCanvasDockWidget *dock = _dock3DViewFromSender( sender() );
124 if ( !dock )
125 return;
126
127 Qgs3DMapSettings *settings = new Qgs3DMapSettings( *dock->mapCanvas3D()->map() );
128
129 // first setting passed on
130 if ( !mMap3D->mapSettings() )
131 {
132 // copy background color
133 mMap3D->setBackgroundColor( settings->backgroundColor() );
134
135 // copy camera position details
136 mMap3D->setCameraPose( dock->mapCanvas3D()->cameraController()->cameraPose() );
137 updateCameraPoseWidgetsFromItem();
138 }
139
140 mMap3D->setMapSettings( settings );
141 }
142
copeCameraPose()143 void QgsLayout3DMapWidget::copeCameraPose()
144 {
145 Qgs3DMapCanvasDockWidget *dock = _dock3DViewFromSender( sender() );
146 if ( dock )
147 {
148 mMap3D->setCameraPose( dock->mapCanvas3D()->cameraController()->cameraPose() );
149 updateCameraPoseWidgetsFromItem();
150 }
151 }
152
updateCameraPose()153 void QgsLayout3DMapWidget::updateCameraPose()
154 {
155 QgsCameraPose pose;
156 pose.setCenterPoint( QgsVector3D( mCenterXSpinBox->value(), mCenterYSpinBox->value(), mCenterZSpinBox->value() ) );
157 pose.setDistanceFromCenterPoint( mDistanceToCenterSpinBox->value() );
158 pose.setPitchAngle( mPitchAngleSpinBox->value() );
159 pose.setHeadingAngle( mHeadingAngleSpinBox->value() );
160 mMap3D->setCameraPose( pose );
161 }
162
setNewItem(QgsLayoutItem * item)163 bool QgsLayout3DMapWidget::setNewItem( QgsLayoutItem *item )
164 {
165 QgsLayoutItem3DMap *newItem = qobject_cast< QgsLayoutItem3DMap * >( item );
166 if ( !newItem )
167 return false;
168
169 mMap3D = newItem;
170 mItemPropertiesWidget->setItem( newItem );
171
172 updateCameraPoseWidgetsFromItem();
173
174 return true;
175 }
176