/* * Copyright 2010 OpenXcom Developers. * * This file is part of OpenXcom. * * OpenXcom 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. * * OpenXcom 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 OpenXcom. If not, see . */ #define _USE_MATH_DEFINES #include "MovingTarget.h" #include namespace OpenXcom { /** * Initializes a moving target with blank coordinates. */ MovingTarget::MovingTarget() : Target(), _dest(0), _speedLon(0.0), _speedLat(0.0), _speed(0) { } MovingTarget::~MovingTarget() { } /** * Loads the moving target from a YAML file. * @param node YAML node. */ void MovingTarget::load(const YAML::Node &node) { Target::load(node); node["speedLon"] >> _speedLon; node["speedLat"] >> _speedLat; node["speed"] >> _speed; } /** * Saves the moving target to a YAML file. * @param out YAML emitter. */ void MovingTarget::save(YAML::Emitter &out) const { Target::save(out); if (_dest != 0) { out << YAML::Key << "dest" << YAML::Value; _dest->saveId(out); } out << YAML::Key << "speedLon" << YAML::Value << _speedLon; out << YAML::Key << "speedLat" << YAML::Value << _speedLat; out << YAML::Key << "speed" << YAML::Value << _speed; } /** * Returns the destination the moving target is heading to. * @return Pointer to destination. */ Target *const MovingTarget::getDestination() const { return _dest; } /** * Changes the destination the moving target is heading to. * @param dest Pointer to destination. */ void MovingTarget::setDestination(Target *dest) { // Remove moving target from old destination's followers if (_dest != 0) { for (std::vector::iterator i = _dest->getFollowers()->begin(); i != _dest->getFollowers()->end(); ++i) { if ((*i) == this) { _dest->getFollowers()->erase(i); break; } } } _dest = dest; // Add moving target to new destination's followers if (_dest != 0) { _dest->getFollowers()->push_back(this); } calculateSpeed(); } /** * Returns the speed of the moving target. * @return Speed in knots. */ int MovingTarget::getSpeed() const { return _speed; } /** * Changes the speed of the moving target. * @param speed Speed in knots. */ void MovingTarget::setSpeed(int speed) { _speed = speed; calculateSpeed(); } /** * Converts the speed from the standard knots (nautical miles per hour), * and converts it into radians per 5 in-game seconds. * @return Speed in radians. */ double MovingTarget::getRadianSpeed() const { // Each nautical mile is 1/60th of a degree. // Each hour contains 300 5-seconds. return _speed * (1 / 60.0) * (M_PI / 180) / 300.0; } /** * Returns the distance between this moving target and any other * target on the globe, accounting for the wrap-around. * @param target Pointer to other target. * @param dLon Returned longitude difference. * @param dLat Returned latitude difference. * @returns Distance in radian. */ double MovingTarget::getDistance(Target *target, double *dLon, double *dLat) const { double minLength = 2*M_PI, lat = target->getLatitude(); for (double lon = target->getLongitude() - 2*M_PI; lon <= target->getLongitude() + 2*M_PI + 0.01; lon += 2*M_PI) { double dx = lon - _lon; double dy = lat - _lat; double length = sqrt(dx * dx + dy * dy); if (length < minLength) { minLength = length; *dLon = dx; *dLat = dy; } } return minLength; } /** * Calculates the speed vector for the moving target * based on the current raw speed and destination. */ void MovingTarget::calculateSpeed() { if (_dest != 0) { double dLon, dLat; double length = getDistance(_dest, &dLon, &dLat); _speedLon = dLon / length * getRadianSpeed(); _speedLat = dLat / length * getRadianSpeed(); } else { _speedLon = 0; _speedLat = 0; } } /** * Checks if the moving target has finished its route by checking * if it has exceeded the destination position based on the speed vector. * @return True if it has, False otherwise. */ bool MovingTarget::finishedRoute() const { return (((_speedLon > 0 && _lon >= _dest->getLongitude()) || (_speedLon < 0 && _lon <= _dest->getLongitude()) || _speedLon == 0) && ((_speedLat > 0 && _lat >= _dest->getLatitude()) || (_speedLat < 0 && _lat <= _dest->getLatitude()) || _speedLat == 0)); } /** * Checks if the moving target has reached its destination. * @return True if it has, False otherwise. */ bool MovingTarget::reachedDestination() const { if (_dest == 0) { return false; } return (_lon == _dest->getLongitude() && _lat == _dest->getLatitude()); } }