34e6b8de66d8429e1ede274ccc25422097e3d9c4
[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      {"zpos", true},
35      {"src", false},
36      {"zeroangle", true},
37      {"fullangle", true},
38      {"zerospeed", true},
39      {"fullspeed", true},
40      {"xrotationpoint", true},
41      {"yrotationpoint", true}
42     };
43
44     int const ANIMATION_TIME = 500;
45     int const ANIMATION_FRAMES = 50;
46     int const ANIMATION_UPDATEINTERVAL = 20;
47 }
48
49 Pointer::Pointer(Reader* reader, bool animate): QObject(0), GraphicsElement(reader),
50 xRotationPoint_(0), yRotationPoint_(0), x_(0), y_(0), zeroAngle_(0),
51 fullAngle_(180), zeroSpeed_(0), fullSpeed_(220), targetAngle_(0),
52 startAngle_(0), angle_(-1), imageSet_(false), animate_(animate), timer_(0)
53 {
54     element_ = new QGraphicsPixmapItem();
55
56     if(animate_)
57     {
58         timer_ = new QTimeLine(ANIMATION_TIME);
59         timer_->setFrameRange(0, ANIMATION_FRAMES);
60         timer_->setUpdateInterval(ANIMATION_UPDATEINTERVAL);
61         connect(timer_, SIGNAL(frameChanged(int)), this, SLOT(setFrame(int)));
62     }
63
64 }
65
66 Pointer::~Pointer()
67 {
68     delete timer_;
69 }
70
71 bool Pointer::setAttribute(QString const& name, QString const& value)
72 {
73     int intVal = 0;
74     int attrId = -1;
75
76     if((attrId = getAttribute(name, value, ATTRIBUTES, ATTRIBUTE_COUNT, intVal)) != -1)
77     {
78         Attribute attr = static_cast<Attribute>(attrId);
79
80         switch(attr)
81         {
82         case XPOS:
83             x_ = intVal;
84             break;
85         case YPOS:
86             y_ = intVal;
87             break;
88         case ZPOS:
89             element_->setZValue(intVal);
90             break;
91         case SRC:
92             return loadImage(value);
93             break;
94         case ZEROANGLE:
95             zeroAngle_ = intVal;
96             break;
97         case FULLANGLE:
98             fullAngle_ = intVal;
99             break;
100         case ZEROSPEED:
101             zeroSpeed_ = intVal;
102             break;
103         case FULLSPEED:
104             fullSpeed_ = intVal;
105             break;
106         case XROTATIONPOINT:
107             xRotationPoint_ = intVal;
108             break;
109         case YROTATIONPOINT:
110             yRotationPoint_ = intVal;
111             break;
112         default:
113             qDebug() << "Unknown attribute: " << attr;
114             return false;
115         }
116
117         return true;
118     }
119     else
120     {
121         return false;
122     }
123 }
124
125 void Pointer::addToScene(GraphicsScene* scene)
126 {
127     if(!imageSet_)
128     {
129         return;
130     }
131
132     element_->setTransformOriginPoint(xRotationPoint_, yRotationPoint_);
133     element_->setX(x_ - xRotationPoint_);
134     element_->setY(y_ - yRotationPoint_);
135
136     bool animateVal = animate_;
137     animate_ = false;
138     update();
139     animate_ = animateVal;
140
141     scene->addItem(element_);
142 }
143
144 void Pointer::update()
145 {
146     double speed = Odometer::instance().getLatestFix().kmSpeed;
147
148     if(speed < zeroSpeed_)
149     {
150         speed = static_cast<double>(zeroSpeed_);
151     }
152     else if(speed > fullSpeed_)
153     {
154         speed = static_cast<double>(fullSpeed_);
155     }
156
157     double multiplier = static_cast<double>(speed - zeroSpeed_) / (fullSpeed_ - zeroSpeed_);
158     double angle = static_cast<double>(zeroAngle_) + ((fullAngle_ - zeroAngle_) * multiplier);
159
160     int rounded = static_cast<int>(round(angle));
161
162     if(rounded == angle_)
163     {
164         return;
165     }
166
167     angle_ = rounded;
168
169     if(!animate_)
170     {
171         element_->setRotation(rounded);
172     }
173     else
174     {
175         targetAngle_ = rounded;
176         startAngle_ = element_->rotation();
177
178         if(timer_->state() == QTimeLine::Running)
179         {
180             timer_->stop();
181         }
182
183         timer_->start();
184     }
185 }
186
187 void Pointer::setFrame(int frame)
188 {
189     element_->setRotation(startAngle_ + ((static_cast<double>(frame) / ANIMATION_FRAMES) * (targetAngle_ - startAngle_)));
190 }
191
192 bool Pointer::loadImage(QString const& name)
193 {
194     QPixmap pixmap;
195     QByteArray data;
196
197     if(!readFile(name, data))
198     {
199         return false;
200     }
201
202     if(!pixmap.loadFromData(data))
203     {
204         setError("Invalid image file: " + name);
205         return false;
206     }
207
208     element_->setPixmap(pixmap);
209     imageSet_ = true;
210
211     return true;
212 }
213
214 QGraphicsItem* Pointer::getElement() const
215 {
216     return element_;
217 }
218