Fixes to speed alarm and poi alerts. Added flicker effect. Some new fields to text...
[jspeed] / src / compass.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 "compass.h"
24 #include "reader.h"
25 #include "graphicsscene.h"
26 #include "odometer.h"
27
28 namespace
29 {
30     const GraphicsElement::AttributeDetails ATTRIBUTES[Compass::ATTRIBUTE_COUNT] =
31     {
32      {"xpos", true},
33      {"ypos", true},
34      {"zpos", true},
35      {"visiblewhen", false},
36      {"src", false},
37      {"xrotationpoint", true},
38      {"yrotationpoint", true}
39     };
40
41     int const ANIMATION_TIME = 700;
42     int const ANIMATION_FRAMES = 80;
43     int const ANIMATION_UPDATEINTERVAL = 20;
44     double const COMPASS_IGNORE_THRESHOLD = 90.0;
45 }
46
47 Compass::Compass(Reader* reader, bool animate): GraphicsElement(reader),
48 xRotationPoint_(-1), yRotationPoint_(-1), x_(0), y_(0), targetAngle_(0),
49 startAngle_(0), angle_(-1), width_(0), height_(0), imageSet_(false), animate_(animate), timer_(0)
50 {
51     element_ = new QGraphicsPixmapItem();
52
53     if(animate_)
54     {
55         timer_ = new QTimeLine(ANIMATION_TIME);
56         timer_->setFrameRange(0, ANIMATION_FRAMES);
57         timer_->setUpdateInterval(ANIMATION_UPDATEINTERVAL);
58         connect(timer_, SIGNAL(frameChanged(int)), this, SLOT(setFrame(int)));
59     }
60
61 }
62
63 Compass::~Compass()
64 {
65     delete timer_;
66 }
67
68 bool Compass::setAttribute(QString const& name, QString const& value)
69 {
70     int intVal = 0;
71     int attrId = -1;
72
73     if((attrId = getAttribute(name, value, ATTRIBUTES, ATTRIBUTE_COUNT, intVal)) != -1)
74     {
75         Attribute attr = static_cast<Attribute>(attrId);
76
77         switch(attr)
78         {
79         case XPOS:
80             x_ = intVal;
81             break;
82         case YPOS:
83             y_ = intVal;
84             break;
85         case ZPOS:
86             element_->setZValue(intVal);
87             break;
88         case VISIBLEWHEN:
89             setVisibleWhen(strToVisibleWhen(value));
90             break;
91         case SRC:
92             return loadImage(value);
93             break;
94         case XROTATIONPOINT:
95             xRotationPoint_ = intVal;
96             break;
97         case YROTATIONPOINT:
98             yRotationPoint_ = intVal;
99             break;
100         default:
101             qDebug() << "Unknown attribute: " << attr;
102             return false;
103         }
104
105         return true;
106     }
107     else
108     {
109         return false;
110     }
111 }
112
113 void Compass::addToScene(GraphicsScene* scene)
114 {
115     if(!imageSet_)
116     {
117         return;
118     }
119
120     if(xRotationPoint_ < 0)
121     {
122         xRotationPoint_ = width_ / 2;
123     }
124     if(yRotationPoint_ < 0)
125     {
126         yRotationPoint_ = height_ / 2;
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 Compass::update()
142 {
143     if(Odometer::instance().getLatestFix().epd > COMPASS_IGNORE_THRESHOLD)
144     {
145         return;
146     }
147
148     double angle = Odometer::instance().getLatestFix().track * -1.0;
149
150     if(angle < -180)
151     {
152         angle += 360.0;
153     }
154
155     int rounded = static_cast<int>(round(angle));
156
157     if(rounded == angle_)
158     {
159         return;
160     }
161
162     angle_ = rounded;
163
164     if(!animate_)
165     {
166         element_->setRotation(rounded);
167     }
168     else
169     {
170         targetAngle_ = rounded;
171         startAngle_ = element_->rotation();
172
173         if(timer_->state() == QTimeLine::Running)
174         {
175             timer_->stop();
176         }
177
178         timer_->start();
179     }
180 }
181
182 void Compass::setFrame(int frame)
183 {
184     element_->setRotation(startAngle_ + ((static_cast<double>(frame) / ANIMATION_FRAMES) * (targetAngle_ - startAngle_)));
185 }
186
187 bool Compass::loadImage(QString const& name)
188 {
189     QPixmap pixmap;
190     QByteArray data;
191
192     if(!readFile(name, data))
193     {
194         return false;
195     }
196
197     if(!pixmap.loadFromData(data))
198     {
199         setError("Invalid image file: " + name);
200         return false;
201     }
202
203     width_ = pixmap.width();
204     height_ = pixmap.height();
205
206     element_->setPixmap(pixmap);
207     imageSet_ = true;
208
209     return true;
210 }
211
212 QGraphicsItem* Compass::getElement() const
213 {
214     return element_;
215 }
216