Initial commit.
[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 <QtCore/QDebug>
20 #include <QtCore/QTimeLine>
21 #include <QtGui/QGraphicsItemAnimation>
22 #include <QtGui/QGraphicsPixmapItem>
23 #include <math.h>
24 #include "pointer.h"
25 #include "reader.h"
26 #include "graphicsscene.h"
27 #include "odometer.h"
28
29 namespace
30 {
31     const GraphicsElement::AttributeDetails ATTRIBUTES[Pointer::ATTRIBUTE_COUNT] =
32     {
33      {"xpos", true},
34      {"ypos", 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 SRC:
89             return loadImage(value);
90             break;
91         case ZEROANGLE:
92             zeroAngle_ = intVal;
93             break;
94         case FULLANGLE:
95             fullAngle_ = intVal;
96             break;
97         case ZEROSPEED:
98             zeroSpeed_ = intVal;
99             break;
100         case FULLSPEED:
101             fullSpeed_ = intVal;
102             break;
103         case XROTATIONPOINT:
104             xRotationPoint_ = intVal;
105             break;
106         case YROTATIONPOINT:
107             yRotationPoint_ = intVal;
108             break;
109         default:
110             qDebug() << "Unknown attribute: " << attr;
111             return false;
112         }
113
114         return true;
115     }
116     else
117     {
118         return false;
119     }
120 }
121
122 void Pointer::addToScene(GraphicsScene* scene)
123 {
124     if(!imageSet_)
125     {
126         return;
127     }
128
129     element_->setTransformOriginPoint(xRotationPoint_, yRotationPoint_);
130     element_->setX(x_ - xRotationPoint_);
131     element_->setY(y_ - yRotationPoint_);
132
133     bool animateVal = animate_;
134     animate_ = false;
135     update();
136     animate_ = animateVal;
137
138     scene->addItem(element_);
139 }
140
141 void Pointer::update()
142 {
143     double speed = Odometer::instance().getLatestFix().kmSpeed;
144
145     if(speed < zeroSpeed_)
146     {
147         speed = static_cast<double>(zeroSpeed_);
148     }
149     else if(speed > fullSpeed_)
150     {
151         speed = static_cast<double>(fullSpeed_);
152     }
153
154     double multiplier = static_cast<double>(speed - zeroSpeed_) / (fullSpeed_ - zeroSpeed_);
155     double angle = static_cast<double>(zeroAngle_) + ((fullAngle_ - zeroAngle_) * multiplier);
156
157     int rounded = static_cast<int>(round(angle));
158
159     if(rounded == angle_)
160     {
161         return;
162     }
163
164     angle_ = rounded;
165
166     if(!animate_)
167     {
168         element_->setRotation(rounded);
169     }
170     else
171     {
172         targetAngle_ = rounded;
173         startAngle_ = element_->rotation();
174
175         if(timer_->state() == QTimeLine::Running)
176         {
177             timer_->stop();
178         }
179
180         timer_->start();
181     }
182 }
183
184 void Pointer::setFrame(int frame)
185 {
186     element_->setRotation(startAngle_ + ((static_cast<double>(frame) / ANIMATION_FRAMES) * (targetAngle_ - startAngle_)));
187 }
188
189 bool Pointer::loadImage(QString const& name)
190 {
191     QPixmap pixmap;
192     QByteArray data;
193
194     if(!readFile(name, data))
195     {
196         return false;
197     }
198
199     if(!pixmap.loadFromData(data))
200     {
201         setError("Invalid image file: " + name);
202         return false;
203     }
204
205     element_->setPixmap(pixmap);
206     imageSet_ = true;
207
208     return true;
209 }