view engine/core/pathfinder/routepather/routepather.cpp @ 46:90005975cdbb

* Final LGPL switch step by adjusting the file headers * Remaining issues (just slightly related to the unittest switch): * No working unittest solution for msvc2005 yet * Unittests not working with mingw + scons either though this seems hard to impossible to fix without an expert in this field * sample_unit_test.cpp would need to get modified for unittest++; it still contains the old boost unittest code
author mvbarracuda@33b003aa-7bff-0310-803a-e67f0ece8222
date Sun, 13 Jul 2008 11:05:12 +0000
parents 4a0efb7baf70
children f970f7dab2dd
line wrap: on
line source

/***************************************************************************
 *   Copyright (C) 2005-2008 by the FIFE team                              *
 *   http://www.fifengine.de                                               *
 *   This file is part of FIFE.                                            *
 *                                                                         *
 *   FIFE is free software; you can redistribute it and/or                 *
 *   modify it under the terms of the GNU Lesser General Public            *
 *   License as published by the Free Software Foundation; either          *
 *   version 2.1 of the License, or (at your option) any later version.    *
 *                                                                         *
 *   This library 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     *
 *   Lesser General Public License for more details.                       *
 *                                                                         *
 *   You should have received a copy of the GNU Lesser General Public      *
 *   License along with this library; if not, write to the                 *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

// Standard C++ library includes
#include <cassert>

// 3rd party library includes

// FIFE includes
// These includes are split up in two parts, separated by one empty line
// First block: files included from the FIFE root src directory
// Second block: files included from the same folder
#include "model/metamodel/grids/cellgrid.h"
#include "model/structures/instance.h"
#include "model/structures/layer.h"

#include "pathfinder/searchspace.h"

#include "routepather.h"
#include "routepathersearch.h"

namespace FIFE {
	void RoutePather::setMap(Map* map) {
		if(!map) {
			return;
		}
		m_map = map;
	}

	int RoutePather::getNextLocation(const Instance* instance, const Location& target, 
				double distance_to_travel, Location& nextLocation,
				Location& facingLocation, int session_id, int priority) {
		assert(instance);
		assert(instance->getLocation().getLayer() == target.getLayer());
		if(session_id != -1) {
			PathMap::iterator j = m_paths.find(session_id);
			if(j != m_paths.end()) {
				if(j->second.empty()) {
					m_paths.erase(j);
					return -1;
				} else {
					followPath(instance, j->second, distance_to_travel, nextLocation, facingLocation);
					return session_id;
				}
			} else {
				if(!sessionIdValid(session_id)) {
					//Session id is invalid.
					return -1;
				}
			}
			return session_id;
		}
		SearchSpace* searchspace = getSearchSpace(target.getLayer());
		if(!searchspace) {
			searchspace = new SearchSpace(target.getLayer());
			addSearchSpace(searchspace);
		}
		if(searchspace->isInSearchSpace(target)) {
			session_id = m_nextFreeSessionId++;
			RoutePatherSearch* newSearch = new RoutePatherSearch(session_id, instance->getLocation(), target, searchspace);
			m_sessions.pushElement(SessionQueue::value_type(newSearch, priority));
			addSessionId(session_id);
		}
		return session_id;
	}

	void RoutePather::update() {
		int ticksleft = m_maxticks;
		while(ticksleft >= 0) {
			if(m_sessions.empty()) {
				break;
			}
			Search* priority_session = m_sessions.getPriorityElement().first;
			if(!sessionIdValid(priority_session->getSessionId())) {
				delete priority_session;
				m_sessions.popElement();
				continue;
			}
			priority_session->updateSearch();
			if(priority_session->getSearchStatus() == Search::search_status_complete) {
				Path newPath = priority_session->calcPath();
				m_paths.insert(PathMap::value_type(priority_session->getSessionId(), newPath));
				invalidateSessionId(priority_session->getSessionId());
				delete priority_session;
				m_sessions.popElement();
			} else if(priority_session->getSearchStatus() == Search::search_status_failed) {
				invalidateSessionId(priority_session->getSessionId());
				delete priority_session;
				m_sessions.popElement();
			}
			--ticksleft;
		}
	}

	void RoutePather::followPath(const Instance* instance, Path& path, double speed, Location& nextLocation, Location& facingLocation) {
		Location instanceLoc = instance->getLocation();
		ExactModelCoordinate instancePos = instanceLoc.getMapCoordinates();
		ExactModelCoordinate facingPos = path.front().getMapCoordinates();
		facingPos.x = facingPos.x + (facingPos.x - instancePos.x);
		facingPos.y = facingPos.y + (facingPos.y - instancePos.y);
		facingLocation = path.front();
		facingLocation.setMapCoordinates(facingPos);
		ExactModelCoordinate targetPos = path.front().getMapCoordinates();
		CellGrid* grid = instanceLoc.getLayer()->getCellGrid();
		double dx = (targetPos.x - instancePos.x) * grid->getXScale();
		double dy = (targetPos.y - instancePos.y) * grid->getYScale();
		double distance = sqrt(dx * dx + dy * dy);
		bool pop = false;
		if(speed > distance) {
			speed = distance;
			pop = true;
		}
		if(distance != 0)
		{
			instancePos.x += (dx / distance) * speed;
			instancePos.y += (dy / distance) * speed;

		} else {
			pop = true;
		}
		nextLocation.setMapCoordinates(instancePos);
		if(pop)
		{
			path.pop_front();
			if(!path.empty() && instanceLoc.getLayer()->cellContainsBlockingInstance(path.front().getLayerCoordinates()))
			{
				//TODO: Determine if we're close enough to stop, otherwise find alternate route.
				path.clear();
				return;
			}
		}
	}
	
	bool RoutePather::cancelSession(const int session_id) {
		if(session_id >= 0) {
			PathMap::iterator i = m_paths.find(session_id);
			if(i != m_paths.end()) {
				m_paths.erase(i);
				return true;
			} else {
				invalidateSessionId(session_id);
			}
		}
		return false;
	}

	void RoutePather::addSessionId(const int sessionId) {
		m_registeredSessionIds.push_back(sessionId);
	}

	bool RoutePather::sessionIdValid(const int sessionId) {
		for(SessionList::const_iterator i = m_registeredSessionIds.begin();
			i != m_registeredSessionIds.end();
			++i) {
				if((*i) == sessionId) {
					return true;
				}
		}
		return false;
	}

	bool RoutePather::invalidateSessionId(const int sessionId) {
		for(SessionList::iterator i = m_registeredSessionIds.begin();
			i != m_registeredSessionIds.end();
			++i) {
				if((*i) == sessionId) {
					m_registeredSessionIds.erase(i);
					return true;
				}
		}
		return false;
	}

	bool RoutePather::addSearchSpace(SearchSpace* search_space) {
		std::pair<SearchSpaceMap::iterator, bool> res = m_searchspaces.insert(SearchSpaceMap::value_type(search_space->getLayer(), search_space));
		
		return res.second;
	}

	SearchSpace* RoutePather::getSearchSpace(Layer * const layer) {
		SearchSpaceMap::iterator i = m_searchspaces.find(layer);
		if(i == m_searchspaces.end()) {
			return 0;
		}
		return i->second;
	}
}