QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgs3danimationsettings.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgs3danimationsettings.cpp
3  --------------------------------------
4  Date : July 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 "qgs3danimationsettings.h"
17 
18 #include <QEasingCurve>
19 #include <QDomDocument>
20 
22 
24 {
25  return mKeyframes.isEmpty() ? 0 : mKeyframes.constLast().time;
26 }
27 
29 {
30  if ( mKeyframes.isEmpty() )
31  return Keyframe();
32 
33  if ( time < mKeyframes.constFirst().time )
34  {
35  return mKeyframes.first();
36  }
37  else if ( time >= mKeyframes.constLast().time )
38  {
39  return mKeyframes.last();
40  }
41  else
42  {
43  // TODO: make easing curves configurable.
44  // QEasingCurve is probably not flexible enough, we may need more granular
45  // control with Bezier curves to allow smooth transition at keyframes
46 
47  for ( int i = 0; i < mKeyframes.size() - 1; i++ )
48  {
49  const Keyframe &k0 = mKeyframes.at( i );
50  const Keyframe &k1 = mKeyframes.at( i + 1 );
51  if ( time >= k0.time && time <= k1.time )
52  {
53  float ip = ( time - k0.time ) / ( k1.time - k0.time );
54  float eIp = mEasingCurve.valueForProgress( ip );
55  float eIip = 1.0f - eIp;
56 
57  Keyframe kf;
58  kf.time = time;
59  kf.point.set( k0.point.x() * eIip + k1.point.x() * eIp,
60  k0.point.y() * eIip + k1.point.y() * eIp,
61  k0.point.z() * eIip + k1.point.z() * eIp );
62  kf.dist = k0.dist * eIip + k1.dist * eIp;
63  kf.pitch = k0.pitch * eIip + k1.pitch * eIp;
64 
65  // always use shorter angle
66  float yaw0 = fmod( k0.yaw, 360 ), yaw1 = fmod( k1.yaw, 360 );
67  if ( std::abs( yaw0 - yaw1 ) > 180 )
68  {
69  if ( yaw0 < yaw1 )
70  yaw0 += 360;
71  else
72  yaw1 += 360;
73  }
74 
75  kf.yaw = yaw0 * eIip + yaw1 * eIp;
76  return kf;
77  }
78  }
79  }
80  Q_ASSERT( false );
81  return Keyframe();
82 }
83 
84 void Qgs3DAnimationSettings::readXml( const QDomElement &elem )
85 {
86  mEasingCurve = QEasingCurve( ( QEasingCurve::Type ) elem.attribute( QStringLiteral( "interpolation" ), QStringLiteral( "0" ) ).toInt() );
87 
88  mKeyframes.clear();
89 
90  QDomElement elemKeyframes = elem.firstChildElement( QStringLiteral( "keyframes" ) );
91  QDomElement elemKeyframe = elemKeyframes.firstChildElement( QStringLiteral( "keyframe" ) );
92  while ( !elemKeyframe.isNull() )
93  {
94  Keyframe kf;
95  kf.time = elemKeyframe.attribute( QStringLiteral( "time" ) ).toFloat();
96  kf.point.set( elemKeyframe.attribute( QStringLiteral( "x" ) ).toDouble(),
97  elemKeyframe.attribute( QStringLiteral( "y" ) ).toDouble(),
98  elemKeyframe.attribute( QStringLiteral( "z" ) ).toDouble() );
99  kf.dist = elemKeyframe.attribute( QStringLiteral( "dist" ) ).toFloat();
100  kf.pitch = elemKeyframe.attribute( QStringLiteral( "pitch" ) ).toFloat();
101  kf.yaw = elemKeyframe.attribute( QStringLiteral( "yaw" ) ).toFloat();
102  mKeyframes.append( kf );
103  elemKeyframe = elemKeyframe.nextSiblingElement( QStringLiteral( "keyframe" ) );
104  }
105 }
106 
107 QDomElement Qgs3DAnimationSettings::writeXml( QDomDocument &doc ) const
108 {
109  QDomElement elem = doc.createElement( QStringLiteral( "animation3d" ) );
110  elem.setAttribute( QStringLiteral( "interpolation" ), mEasingCurve.type() );
111 
112  QDomElement elemKeyframes = doc.createElement( QStringLiteral( "keyframes" ) );
113 
114  for ( const Keyframe &keyframe : mKeyframes )
115  {
116  QDomElement elemKeyframe = doc.createElement( QStringLiteral( "keyframe" ) );
117  elemKeyframe.setAttribute( QStringLiteral( "time" ), keyframe.time );
118  elemKeyframe.setAttribute( QStringLiteral( "x" ), keyframe.point.x() );
119  elemKeyframe.setAttribute( QStringLiteral( "y" ), keyframe.point.y() );
120  elemKeyframe.setAttribute( QStringLiteral( "z" ), keyframe.point.z() );
121  elemKeyframe.setAttribute( QStringLiteral( "dist" ), keyframe.dist );
122  elemKeyframe.setAttribute( QStringLiteral( "pitch" ), keyframe.pitch );
123  elemKeyframe.setAttribute( QStringLiteral( "yaw" ), keyframe.yaw );
124  elemKeyframes.appendChild( elemKeyframe );
125  }
126 
127  elem.appendChild( elemKeyframes );
128 
129  return elem;
130 }
QDomElement writeXml(QDomDocument &doc) const
Writes configuration to a DOM element, to be used later with readXml()
Keyframe interpolate(float time) const
Interpolates camera position and rotation at the given point in time.
float duration() const
Returns duration of the whole animation in seconds.
void readXml(const QDomElement &elem)
Reads configuration from a DOM element previously written by writeXml()
double y() const
Returns Y coordinate.
Definition: qgsvector3d.h:51
double z() const
Returns Z coordinate.
Definition: qgsvector3d.h:53
double x() const
Returns X coordinate.
Definition: qgsvector3d.h:49
void set(double x, double y, double z)
Sets vector coordinates.
Definition: qgsvector3d.h:56
float pitch
Tilt of the camera in degrees (0 = looking from the top, 90 = looking from the side,...
float yaw
Horizontal rotation around the focal point in degrees.
QgsVector3D point
Point towards which the camera is looking in 3D world coords.
float time
Relative time of the keyframe in seconds.
float dist
Distance of the camera from the focal point.