/*
* vim: ts=4 sw=4 et tw=0 wm=0
*
* libavoid - Fast, Incremental, Object-avoiding Line Router
*
* Copyright (C) 2004-2009 Monash University
*
* --------------------------------------------------------------------
* The Visibility Sweep technique is based upon the method described
* in Section 5.2 of:
* Lee, D.-T. (1978). Proximity and reachability in the plane.,
* PhD thesis, Department of Electrical Engineering,
* University of Illinois, Urbana, IL.
* --------------------------------------------------------------------
*
* 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.
* See the file LICENSE.LGPL distributed with the library.
*
* Licensees holding a valid commercial license may use this file in
* accordance with the commercial license agreement provided with the
* library.
*
* 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.
*
* Author(s): Michael Wybrow <mjwybrow@users.sourceforge.net>
*/
#include <algorithm>
#include <cfloat>
#define _USE_MATH_DEFINES
#include <cmath>
#include "libavoid/visibility.h"
#include "libavoid/vertices.h"
#include "libavoid/geometry.h"
#include "libavoid/assertions.h"
#ifdef LINEDEBUG
#include "SDL_gfxPrimitives.h"
#endif
namespace Avoid {
{
if ( !(router->InvisibilityGrph) )
{
// Clear shape from graph.
shape->removeFromGraph();
}
{
bool knownNew = true;
db_printf("-- CONSIDERING --\n");
db_printf("\tFirst Half:\n");
{
if (j->id == dummyOrthogID)
{
// Don't include orthogonal dummy vertices.
continue;
}
}
db_printf("\tSecond Half:\n");
{
if (k->id == dummyOrthogID)
{
// Don't include orthogonal dummy vertices.
continue;
}
}
}
}
{
if ( !(router->InvisibilityGrph) )
{
// Clear shape from graph.
shape->removeFromGraph();
}
{
vertexSweep(i);
}
}
const bool gen_contains)
{
// Make sure we're only doing ptVis for endpoints.
if ( !(router->InvisibilityGrph) )
{
point->removeFromGraph();
}
{
}
if (router->UseLeesAlgorithm)
{
}
else
{
k = k->lstNext)
{
if (k->id == dummyOrthogID)
{
// Don't include orthogonal dummy vertices.
continue;
}
}
if (partner)
{
}
}
}
//============================================================================
// SWEEP CODE
//
class PointPair
{
public:
{
angle = pos_to_angle(x, y);
}
{
// Firstly order by angle.
{
// If the points are collinear, then order them in increasing
// distance from the point we are sweeping around.
{
// XXX: Add this assertion back if we require that
// connector endpoints have unique IDs. For the
// moment it is okay for them to have the same ID.
//COLA_ASSERT(vInf->id != rhs.vInf->id);
// If comparing two points at the same physical
// position, then order them by their VertIDs.
}
}
}
static double pos_to_angle(double x, double y)
{
if (y == 0)
{
return ((x < 0) ? 180 : 0);
}
else if (x == 0)
{
return ((y < 0) ? 270 : 90);
}
if (x < 0)
{
ang += 180;
}
else if (y < 0)
{
ang += 360;
}
COLA_ASSERT(ang >= 0);
return ang;
}
double angle;
double distance;
};
class EdgePair
{
public:
EdgePair() :
angleDist(0.0)
{
// The default constuctor should never be called.
// This is defined to appease the MSVC compiler.
COLA_ASSERT(false);
}
vInf2(v),
{
}
{
{
}
}
{
{
return true;
}
return false;
}
{
{
return false;
}
return true;
}
void setNegativeAngle(void)
{
angle = -1.0;
}
{
{
}
{
}
{
if (result != DO_INTERSECT)
{
// This can happen with points that appear to have the
// same angle but at are at slightly different positions
}
else
{
}
}
return angleDist;
}
double dist1;
double dist2;
double angle;
double angleDist;
};
class isBoundingShape
{
public:
// Class instance remembers the ShapeSet.
{ }
// The following is an overloading of the function call operator.
{
{
return true;
}
return false;
}
private:
// MSVC wants to generate the assignment operator and the default
// constructor, but fails. Therefore we declare them private and
// don't implement them.
isBoundingShape & operator=(isBoundingShape const &);
};
{
if (T.empty())
{
// No blocking edges.
return true;
}
bool visible = true;
{
{
// If the ray intersects just the endpoint of a
// blocking edge then ignore that edge.
++closestIt;
continue;
}
break;
}
{
return true;
}
{
// It's a connector endpoint, so we have to ignore
// edges of containing shapes for determining visibility.
{
{
// This is not a containing edge so do the normal
// test and then stop.
{
visible = false;
}
onBorderIDs.end())
{
// Touching, but centerPoint is on another edge of
// shape shape, so count as blocking.
visible = false;
}
break;
}
// This was a containing edge, so consider the next along.
++closestIt;
}
}
else
{
// Just test to see if this point is closer than the closest
// edge blocking this ray.
{
visible = false;
}
onBorderIDs.end())
{
// Touching, but centerPoint is on another edge of
// shape shape, so count as blocking.
visible = false;
}
}
if (!visible)
{
#ifdef LINEDEBUG
if (router->avoid_screen)
{
}
#endif
}
return visible;
}
{
// List of shape (and maybe endpt) vertices, except p
// Sort list, around
VertSet v;
// Initialise the vertex list
{
{
// Don't include the center point itself.
continue;
}
{
// Don't include orthogonal dummy vertices.
continue;
}
{
// Don't include edge points of containing shapes.
db_printf("Center is inside shape %u so ignore shape edges.\n",
shapeID);
continue;
}
{
// Add shape vertex.
}
else
{
// Add connector endpoint.
{
// Center is a shape vertex, so add all endpoint vertices.
}
else
{
// Center is an endpoint, so only include the other
// endpoint from the matching connector.
{
}
}
}
}
// Add edges to T that intersect the initial ray.
{
COLA_ASSERT(centerInf != k);
{
k->point))
{
}
{
// Record that centerPoint is on an obstacle line.
}
}
{
k->point))
{
}
{
// Record that centerPoint is on an obstacle line.
}
}
}
{
(*c).setNegativeAngle();
}
// Start the actual sweep.
{
#ifdef LINEDEBUG
#endif
{
}
{
(*c).setCurrAngle(*t);
}
e.sort();
// Check visibility.
int blocker = 0;
{
}
{
}
{
if (router->InvisibilityGrph)
{
db_printf("\tSetting invisibility edge... \n\t\t");
edge->addBlocker(0);
}
}
else
{
if (currVisible)
{
#ifdef LINEDEBUG
if (router->avoid_screen)
{
SDL_Delay(1000);
}
#endif
db_printf("\tSetting visibility edge... \n\t\t");
}
else if (router->InvisibilityGrph)
{
db_printf("\tSetting invisibility edge... \n\t\t");
}
}
{
delete edge;
}
{
// This is a shape edge
{
{
}
{
e.push_front(prevPair);
}
}
{
{
}
{
e.push_front(nextPair);
}
}
}
#ifdef LINEDEBUG
if (router->avoid_screen)
{
}
#endif
}
}
}