b48412e8749ec2f3ab25abe8078de64308f1473a
[jspeed] / src / pointer.cpp
1 /*
2  * This file is part of jSpeed.
3  *
4  * jSpeed is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * jSpeed is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with jSpeed.  If not, see <http://www.gnu.org/licenses/>.
16  *
17  */
18
19 #include <QtGui/QGraphicsPixmapItem>
20 #include <QtCore/QDebug>
21 #include <QtCore/QTimeLine>
22 #include <math.h>
23 #include "pointer.h"
24 #include "reader.h"
25 #include "graphicsscene.h"
26 #include "odometer.h"
27
28 namespace
29 {
30     const GraphicsElement::AttributeDetails ATTRIBUTES[Pointer::ATTRIBUTE_COUNT] =
31     {
32      {"xpos", true},
33      {"ypos", true},
34      {"src", false},
35      {"zeroangle", true},
36      {"fullangle", true},
37      {"zerospeed", true},
38      {"fullspeed", true},
39      {"xrotationpoint", true},
40      {"yrotationpoint", true}
41     };
42
43     int const ANIMATION_TIME = 500;
44     int const ANIMATION_FRAMES = 50;
45     int const ANIMATION_UPDATEINTERVAL = 20;
46 }
47
48 Pointer::Pointer(Reader* reader, bool animate): QObject(0), GraphicsElement(reader),
49 xRotationPoint_(0), yRotationPoint_(0), x_(0), y_(0), zeroAngle_(0),
50 fullAngle_(180), zeroSpeed_(0), fullSpeed_(220), targetAngle_(0),
51 startAngle_(0), angle_(-1), imageSet_(false), animate_(animate), timer_(0)
52 {
53     element_ = new QGraphicsPixmapItem();
54
55     if(animate_)
56     {
57         timer_ = new QTimeLine(ANIMATION_TIME);
58         timer_->setFrameRange(0, ANIMATION_FRAMES);
59         timer_->setUpdateInterval(ANIMATION_UPDATEINTERVAL);
60         connect(timer_, SIGNAL(frameChanged(int)), this, SLOT(setFrame(int)));
61     }
62
63 }
64
65 Pointer::~Pointer()
66 {
67     delete timer_;
68 }
69
70 bool Pointer::setAttribute(QString const& name, QString const& value)
71 {
72     int intVal = 0;
73     int attrId = -1;
74
75     if((attrId = getAttribute(name, value, ATTRIBUTES, ATTRIBUTE_COUNT, intVal)) != -1)
76     {
77         Attribute attr = static_cast<Attribute>(attrId);
78
79         switch(attr)
80         {
81         case XPOS:
82             x_ = intVal;
83             break;
84         case YPOS:
85             y_ = intVal;
86             break;
87         case SRC:
88             return loadImage(value);
89             break;
90         case ZEROANGLE:
91             zeroAngle_ = intVal;
92             break;
93         case FULLANGLE:
94             fullAngle_ = intVal;
95             break;
96         case ZEROSPEED:
97             zeroSpeed_ = intVal;
98             break;
99         case FULLSPEED:
100             fullSpeed_ = intVal;
101             break;
102         case XROTATIONPOINT:
103             xRotationPoint_ = intVal;
104             break;
105         case YROTATIONPOINT:
106             yRotationPoint_ = intVal;
107             break;
108         default:
109             qDebug() << "Unknown attribute: " << attr;
110             return false;
111         }
112
113         return true;
114     }
115     else
116     {
117         return false;
118     }
119 }
120
121 void Pointer::addToScene(GraphicsScene* scene)
122 {
123     if(!imageSet_)
124     {
125         return;
126     }
127
128     element_->setTransformOriginPoint(xRotationPoint_, yRotationPoint_);
129     element_->setX(x_ - xRotationPoint_);
130     element_->setY(y_ - yRotationPoint_);
131
132     bool animateVal = animate_;
133     animate_ = false;
134     update();
135     animate_ = animateVal;
136
137     scene->addItem(element_);
138 }
139
140 void Pointer::update()
141 {
142     double speed = Odometer::instance().getLatestFix().kmSpeed;
143
144     if(speed < zeroSpeed_)
145     {
146         speed = static_cast<double>(zeroSpeed_);
147     }
148     else if(speed > fullSpeed_)
149     {
150         speed = static_cast<double>(fullSpeed_);
151     }
152
153     double multiplier = static_cast<double>(speed - zeroSpeed_) / (fullSpeed_ - zeroSpeed_);
154     double angle = static_cast<double>(zeroAngle_) + ((fullAngle_ - zeroAngle_) * multiplier);
155
156     int rounded = static_cast<int>(round(angle));
157
158     if(rounded == angle_)
159     {
160         return;
161     }
162
163     angle_ = rounded;
164
165     if(!animate_)
166     {
167         element_->setRotation(rounded);
168     }
169     else
170     {
171         targetAngle_ = rounded;
172         startAngle_ = element_->rotation();
173
174         if(timer_->state() == QTimeLine::Running)
175         {
176             timer_->stop();
177         }
178
179         timer_->start();
180     }
181 }
182
183 void Pointer::setFrame(int frame)
184 {
185     element_->setRotation(startAngle_ + ((static_cast<double>(frame) / ANIMATION_FRAMES) * (targetAngle_ - startAngle_)));
186 }
187
188 bool Pointer::loadImage(QString const& name)
189 {
190     QPixmap pixmap;
191     QByteArray data;
192
193     if(!readFile(name, data))
194     {
195         return false;
196     }
197
198     if(!pixmap.loadFromData(data))
199     {
200         setError("Invalid image file: " + name);
201         return false;
202     }
203
204     element_->setPixmap(pixmap);
205     imageSet_ = true;
206
207     return true;
208 }
209
210 QGraphicsItem* Pointer::getElement() const
211 {
212     return element_;
213 }
214