+/*
+ * This file is part of jSpeed.
+ *
+ * jSpeed is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * jSpeed is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with jSpeed. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <QtGui/QGraphicsPixmapItem>
+#include <QtCore/QDebug>
+#include <QtCore/QTimeLine>
+#include <math.h>
+#include "compass.h"
+#include "reader.h"
+#include "graphicsscene.h"
+#include "odometer.h"
+
+namespace
+{
+ const GraphicsElement::AttributeDetails ATTRIBUTES[Compass::ATTRIBUTE_COUNT] =
+ {
+ {"xpos", true},
+ {"ypos", true},
+ {"zpos", true},
+ {"visiblewhen", false},
+ {"src", false},
+ {"xrotationpoint", true},
+ {"yrotationpoint", true}
+ };
+
+ int const ANIMATION_TIME = 700;
+ int const ANIMATION_FRAMES = 80;
+ int const ANIMATION_UPDATEINTERVAL = 20;
+ double const COMPASS_IGNORE_THRESHOLD = 90.0;
+}
+
+Compass::Compass(Reader* reader, bool animate): GraphicsElement(reader),
+xRotationPoint_(-1), yRotationPoint_(-1), x_(0), y_(0), targetAngle_(0),
+startAngle_(0), angle_(-1), width_(0), height_(0), imageSet_(false), animate_(animate), timer_(0)
+{
+ element_ = new QGraphicsPixmapItem();
+
+ if(animate_)
+ {
+ timer_ = new QTimeLine(ANIMATION_TIME);
+ timer_->setFrameRange(0, ANIMATION_FRAMES);
+ timer_->setUpdateInterval(ANIMATION_UPDATEINTERVAL);
+ connect(timer_, SIGNAL(frameChanged(int)), this, SLOT(setFrame(int)));
+ }
+
+}
+
+Compass::~Compass()
+{
+ delete timer_;
+}
+
+bool Compass::setAttribute(QString const& name, QString const& value)
+{
+ int intVal = 0;
+ int attrId = -1;
+
+ if((attrId = getAttribute(name, value, ATTRIBUTES, ATTRIBUTE_COUNT, intVal)) != -1)
+ {
+ Attribute attr = static_cast<Attribute>(attrId);
+
+ switch(attr)
+ {
+ case XPOS:
+ x_ = intVal;
+ break;
+ case YPOS:
+ y_ = intVal;
+ break;
+ case ZPOS:
+ element_->setZValue(intVal);
+ break;
+ case VISIBLEWHEN:
+ setVisibleWhen(strToVisibleWhen(value));
+ break;
+ case SRC:
+ return loadImage(value);
+ break;
+ case XROTATIONPOINT:
+ xRotationPoint_ = intVal;
+ break;
+ case YROTATIONPOINT:
+ yRotationPoint_ = intVal;
+ break;
+ default:
+ qDebug() << "Unknown attribute: " << attr;
+ return false;
+ }
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void Compass::addToScene(GraphicsScene* scene)
+{
+ if(!imageSet_)
+ {
+ return;
+ }
+
+ if(xRotationPoint_ < 0)
+ {
+ xRotationPoint_ = width_ / 2;
+ }
+ if(yRotationPoint_ < 0)
+ {
+ yRotationPoint_ = height_ / 2;
+ }
+
+ element_->setTransformOriginPoint(xRotationPoint_, yRotationPoint_);
+ element_->setX(x_ - xRotationPoint_);
+ element_->setY(y_ - yRotationPoint_);
+
+ bool animateVal = animate_;
+ animate_ = false;
+ update();
+ animate_ = animateVal;
+
+ scene->addItem(element_);
+}
+
+void Compass::update()
+{
+ if(Odometer::instance().getLatestFix().epd > COMPASS_IGNORE_THRESHOLD)
+ {
+ return;
+ }
+
+ double angle = Odometer::instance().getLatestFix().track * -1.0;
+
+ if(angle < -180)
+ {
+ angle += 360.0;
+ }
+
+ int rounded = static_cast<int>(round(angle));
+
+ if(rounded == angle_)
+ {
+ return;
+ }
+
+ angle_ = rounded;
+
+ if(!animate_)
+ {
+ element_->setRotation(rounded);
+ }
+ else
+ {
+ targetAngle_ = rounded;
+ startAngle_ = element_->rotation();
+
+ if(timer_->state() == QTimeLine::Running)
+ {
+ timer_->stop();
+ }
+
+ timer_->start();
+ }
+}
+
+void Compass::setFrame(int frame)
+{
+ element_->setRotation(startAngle_ + ((static_cast<double>(frame) / ANIMATION_FRAMES) * (targetAngle_ - startAngle_)));
+}
+
+bool Compass::loadImage(QString const& name)
+{
+ QPixmap pixmap;
+ QByteArray data;
+
+ if(!readFile(name, data))
+ {
+ return false;
+ }
+
+ if(!pixmap.loadFromData(data))
+ {
+ setError("Invalid image file: " + name);
+ return false;
+ }
+
+ width_ = pixmap.width();
+ height_ = pixmap.height();
+
+ element_->setPixmap(pixmap);
+ imageSet_ = true;
+
+ return true;
+}
+
+QGraphicsItem* Compass::getElement() const
+{
+ return element_;
+}
+