Util::Vector SocialForcesAgent::calcAgentRepulsionForce(float dt)
{
	Util::Vector agentRepulsionForce = Util::Vector(0, 0, 0);
	

	std::set<SteerLib::SpatialDatabaseItemPtr> _neighbors;

	gSpatialDatabase->getItemsInRange(_neighbors,
									  _position.x - this->_radius - _SocialForcesParams.sf_query_radius,
									  _position.x + this->_radius + _SocialForcesParams.sf_query_radius,
									  _position.z - this->_radius - _SocialForcesParams.sf_query_radius,
									  _position.z + this->_radius + _SocialForcesParams.sf_query_radius,
									  dynamic_cast<SteerLib::SpatialDatabaseItemPtr>(this));

	SteerLib::AgentInterface *neighborInterface;
	std::set<SteerLib::SpatialDatabaseItemPtr>::iterator neighbor = _neighbors.begin(); 
	while (neighbor != _neighbors.end()) 
	{
		if ((*neighbor)->isAgent())
		{
			neighborInterface = dynamic_cast<SteerLib::AgentInterface *>(*neighbor);
			float penetration = neighborInterface->computePenetration(this->position(), this->radius());

			if (id() != neighborInterface->id())
				agentRepulsionForce += penetration * _SocialForcesParams.sf_agent_body_force * dt * normalize(position() - neighborInterface->position());
		}

		neighbor++;
	}

    return agentRepulsionForce;
}
Util::Vector SocialForcesAgent::calcAgentRepulsionForce(float dt)
{
	Util::Vector agentRepulsion = Util::Vector(0, 0, 0);

	std::set<SteerLib::SpatialDatabaseItemPtr> _neighbors;
	gSpatialDatabase->getItemsInRange(_neighbors,
		_position.x - (this->_radius + _SocialForcesParams.sf_query_radius),
		_position.x + (this->_radius + _SocialForcesParams.sf_query_radius),
		_position.z - (this->_radius + _SocialForcesParams.sf_query_radius),
		_position.z + (this->_radius + _SocialForcesParams.sf_query_radius),
		dynamic_cast<SteerLib::SpatialDatabaseItemPtr>(this));

	SteerLib::AgentInterface * tempAgent;

	for (std::set<SteerLib::SpatialDatabaseItemPtr>::iterator neighbour = _neighbors.begin(); neighbour != _neighbors.end(); neighbour++)
	{
		if ((*neighbour)->isAgent())
		{
			tempAgent = dynamic_cast<SteerLib::AgentInterface *>(*neighbour);
		}
		else
		{
			continue;
		}


		if ((id() != tempAgent->id()) && (tempAgent->computePenetration(this->position(), this->radius()) > 0.000001))
		{
			agentRepulsion = agentRepulsion + (tempAgent->computePenetration(this->position(), this->radius()) * _SocialForcesParams.sf_agent_body_force * normalize(position() - tempAgent->position()));

		}
	}
	return agentRepulsion;
}
SteerLib::AgentInterface * SimulationEngine::createAgent(const SteerLib::AgentInitialConditions & initialConditions, SteerLib::ModuleInterface * owner)
{
	SteerLib::AgentInterface * newAgent = owner->createAgent();

	if (newAgent != NULL) {
		newAgent->reset(initialConditions,this);
		_agents.push_back(newAgent);
		_agentOwners[newAgent] = owner;
	}

	return newAgent;
}
Util::Vector SocialForcesAgent::calcProximityForce(float dt)
{
	// Find all neighbors.
    std::set<SteerLib::SpatialDatabaseItemPtr> _neighbors;

	gSpatialDatabase->getItemsInRange(_neighbors,
									  _position.x - this->_radius - _SocialForcesParams.sf_query_radius,
									  _position.x + this->_radius + _SocialForcesParams.sf_query_radius,
									  _position.z - this->_radius - _SocialForcesParams.sf_query_radius,
									  _position.z + this->_radius + _SocialForcesParams.sf_query_radius,
									  dynamic_cast<SteerLib::SpatialDatabaseItemPtr>(this));

	// Iterate through neighbors.
	std::set<SteerLib::SpatialDatabaseItemPtr>::iterator neighbor = _neighbors.begin();
	Util::Vector agentForce = Util::Vector(0,0,0);
	Util::Vector obstacleForce = Util::Vector(0,0,0);

	SteerLib::AgentInterface *neighborInterface;
	SteerLib::ObstacleInterface *objectInterface;
	Util::Vector differenceNormal;
	float exponentialFactor;

	while (neighbor != _neighbors.end()){

		if ((*neighbor)->isAgent()){
			neighborInterface = dynamic_cast<SteerLib::AgentInterface *>(*neighbor);
			differenceNormal = normalize(position() - neighborInterface->position());
			
			exponentialFactor = exp((radius() + neighborInterface->radius() - (position() - neighborInterface->position()).length())
									/ _SocialForcesParams.sf_agent_b);
			
			agentForce += differenceNormal * _SocialForcesParams.sf_agent_a * exponentialFactor * dt;
		}

		else{
			objectInterface = dynamic_cast<SteerLib::ObstacleInterface*>(*neighbor);
			Util::Vector obstacleNormal = calcWallNormal(objectInterface);
			std::pair<Util::Point, Util::Point> wallPoints = calcWallPointsFromNormal(objectInterface, obstacleNormal);
			std::pair<float, Util::Point> minDistToPoint = minimum_distance(wallPoints.first, wallPoints.second, position());

			differenceNormal = normalize(position() - minDistToPoint.second);

			exponentialFactor = exp((radius() - (position() - minDistToPoint.second).length()) / _SocialForcesParams.sf_wall_b);

			obstacleForce += differenceNormal * _SocialForcesParams.sf_wall_a * exponentialFactor * dt;
		}
		
		++neighbor;
	}

	return agentForce + obstacleForce;
}
Util::Vector SocialForcesAgent::calcProximityForce(float dt)
{
    Util::Vector proximity_force = Util::Vector(0, 0, 0);

	std::set<SteerLib::SpatialDatabaseItemPtr> _neighbors;
	gSpatialDatabase->getItemsInRange(_neighbors,
		_position.x - (this->_radius + _SocialForcesParams.sf_query_radius),
		_position.x + (this->_radius + _SocialForcesParams.sf_query_radius),
		_position.z - (this->_radius + _SocialForcesParams.sf_query_radius),
		_position.z + (this->_radius + _SocialForcesParams.sf_query_radius),
		dynamic_cast<SteerLib::SpatialDatabaseItemPtr>(this));

	SteerLib::AgentInterface * tempAgent;
	SteerLib::ObstacleInterface * tempObstacle;
	Util::Vector dist = Util::Vector(0, 0, 0);

	for (std::set<SteerLib::SpatialDatabaseItemPtr>::iterator neighbour = _neighbors.begin(); neighbour != _neighbors.end(); neighbour++)
	{
		if ((*neighbour)->isAgent())
		{
			tempAgent = dynamic_cast<SteerLib::AgentInterface *>(*neighbour);
			Util::Vector distTemp = normalize(_position - tempAgent->position());

			dist = dist +
				(distTemp * _SocialForcesParams.sf_agent_a *
						exp(((this->radius() + tempAgent->radius()) - (this->position() - tempAgent->position()).length() ) / _SocialForcesParams.sf_agent_b)
						   
				);
		}
		else
		{
			tempObstacle = dynamic_cast<SteerLib::ObstacleInterface*>(*neighbour);
			Util::Vector wall_normal = calcWallNormal(tempObstacle);
			std::pair<Util::Point, Util::Point> line = calcWallPointsFromNormal(tempObstacle, wall_normal);
			std::pair<float, Util::Point> min_stuff = minimum_distance(line.first, line.second, position());

			Util::Vector distObstacle = normalize(_position - min_stuff.second);
			dist = dist +
				(distObstacle * _SocialForcesParams.sf_wall_a *
						exp(((this->radius()) - (this->position() - min_stuff.second).length() ) / _SocialForcesParams.sf_wall_b)
				);
		}
	}
	proximity_force = dist;
	return proximity_force;
}
Util::Vector SocialForcesAgent::calcProximityForce(float dt)
{
    Util::Vector proximityForce = Util::Vector(0,0,0);

    std::set<SteerLib::SpatialDatabaseItemPtr> _neighbors;
	gSpatialDatabase->getItemsInRange(_neighbors,
		position().x - (radius() + _SocialForcesParams.sf_query_radius),
		position().x + (radius() + _SocialForcesParams.sf_query_radius),
		position().z - (radius() + _SocialForcesParams.sf_query_radius),
		position().z + (radius() + _SocialForcesParams.sf_query_radius),
		this);

	for (std::set<SteerLib::SpatialDatabaseItemPtr>::iterator neighbor = _neighbors.begin();
		neighbor != _neighbors.end(); neighbor++) {

		if ((*neighbor)->isAgent()) {
			SteerLib::AgentInterface *other = dynamic_cast<SteerLib::AgentInterface *>(*neighbor);
			if (id() != other->id()) {
				proximityForce += _SocialForcesParams.sf_agent_a 
								  * exp(((radius()+other->radius())-(position()-other->position()).length())/_SocialForcesParams.sf_agent_b) 
								  * normalize(position() - other->position());
			}
		}
		else {
			SteerLib::ObstacleInterface *wall = dynamic_cast<SteerLib::ObstacleInterface *>(*neighbor);
			if (wall->computePenetration(position(), radius()) > 0.000001) {
				Util::Vector wallNormal = calcWallNormal(wall);
				std::pair<Util::Point, Util::Point> edge = calcWallPointsFromNormal(wall, wallNormal);

				std::pair<float, Util::Point> distance = minimum_distance(edge.first, edge.second, position());

				proximityForce += _SocialForcesParams.sf_wall_a 
								  * exp( (radius()-distance.first) / _SocialForcesParams.sf_wall_b ) 
								  * normalize(position() - distance.second);
			}
		}

	}

    return proximityForce;
}
Util::Vector SocialForcesAgent::calcAgentRepulsionForce(float dt)
{
	Util::Vector agentRepulsionForce = Util::Vector(0,0,0);

	std::set<SteerLib::SpatialDatabaseItemPtr> _neighbors;
	gSpatialDatabase->getItemsInRange(_neighbors,
		position().x - (radius() + _SocialForcesParams.sf_query_radius),
		position().x + (radius() + _SocialForcesParams.sf_query_radius),
		position().z - (radius() + _SocialForcesParams.sf_query_radius),
		position().z + (radius() + _SocialForcesParams.sf_query_radius),
		this);

	for (std::set<SteerLib::SpatialDatabaseItemPtr>::iterator neighbor = _neighbors.begin();
		neighbor != _neighbors.end(); neighbor++) {
		if ((*neighbor)->isAgent()) {
			SteerLib::AgentInterface *other = dynamic_cast<SteerLib::AgentInterface *>(*neighbor);
			if (id() != other->id() && other->computePenetration(position(), radius()) > 0.000001) {
				Util::Vector agentNorm = normalize(position() - other->position());

				// Repulsion
				agentRepulsionForce += _SocialForcesParams.sf_agent_body_force
									   * other->computePenetration(position(), radius()) 
									   * agentNorm;

				// Friction
				Util::Vector agentTangent = Util::Vector(-agentNorm.z, 0, agentNorm.x);
				agentRepulsionForce -= _SocialForcesParams.sf_sliding_friction_force // k
									   * other->computePenetration(position(), radius()) // g
									   * ((velocity() - other->velocity()) * agentTangent) // tangential velocity difference
									   * agentTangent; // tangential direction
			}
		}
	}

    return agentRepulsionForce;
}