router.cpp revision b5e66c5e6adbe1f6d2adc9d5fe7ed26b66fb1bcc
/*
* vim: ts=4 sw=4 et tw=0 wm=0
*
* libavoid - Fast, Incremental, Object-avoiding Line Router
* Copyright (C) 2004-2006 Michael Wybrow <mjwybrow@users.sourceforge.net>
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include "libavoid/visibility.h"
#include "libavoid/connector.h"
#include "libavoid/polyutil.h"
#include "math.h"
//#define ORTHOGONAL_ROUTING
namespace Avoid {
static const unsigned int infoAdd = 1;
static const unsigned int infoDel = 2;
static const unsigned int infoMov = 3;
class MoveInfo {
public:
: shape(s)
{ }
~MoveInfo()
{
}
bool firstMove;
};
: PartialTime(false)
, segmt_penalty(0)
, angle_penalty(0)
, crossing_penalty(200)
// Algorithm options:
, UseAStarSearch(true)
, IgnoreRegions(true)
, SelectiveReroute(true)
, IncludeEndpoints(true)
, UseLeesAlgorithm(false)
, InvisibilityGrph(true)
, ConsolidateMoves(true)
, PartialFeedback(false)
// Instrumentation:
, st_checked_edges(0)
#ifdef LINEDEBUG
, avoid_screen(NULL)
#endif
{ }
{
// o Check all visibility edges to see if this one shape
// blocks them.
#ifdef ORTHOGONAL_ROUTING
#endif
// o Calculate visibility for the new vertices.
if (UseLeesAlgorithm)
{
}
else
{
}
}
{
// o Remove entries related to this shape's vertices
shape->removeFromGraph();
if (SelectiveReroute)
{
}
#ifdef ORTHOGONAL_ROUTING
#endif
delete shape;
// o Check all edges that were blocked by this shape.
if (InvisibilityGrph)
{
}
else
{
// check all edges not in graph
}
}
{
// Sanely cope with the case where the user requests moving the same
// shape multiple times before rerouting connectors.
bool alreadyThere = false;
{
{
"warning: multiple moves requested for shape %d.\n",
(int) id);
// Just update the MoveInfo with the second polygon, but
// leave the firstMove setting alone.
alreadyThere = true;
}
}
if (!alreadyThere)
{
}
if (!ConsolidateMoves)
{
processMoves();
}
}
void Router::processMoves(void)
{
{
return;
}
{
// o Remove entries related to this shape's vertices
shape->removeFromGraph();
{
}
#ifdef ORTHOGONAL_ROUTING
#endif
// Ignore this shape for visibility.
// XXX: We don't really need to do this if we're not using Partial
// Feedback. Without this the blocked edges still route
// around the shape until it leaves the connector.
shape->makeInactive();
}
if (InvisibilityGrph)
{
{
// o Check all edges that were blocked by this shape.
}
}
else
{
// check all edges not in graph
}
{
// Restore this shape for visibility.
shape->makeActive();
#ifdef ORTHOGONAL_ROUTING
#endif
// o Check all visibility edges to see if this one shape
// blocks them.
if (notPartialTime)
{
}
// o Calculate visibility for the new vertices.
if (UseLeesAlgorithm)
{
}
else
{
}
delete moveInf;
}
}
//----------------------------------------------------------------------------
// XXX: attachedShapes and attachedConns both need to be rewritten
// for constant time lookup of attached objects once this info
// is stored better within libavoid. Also they shouldn't need to
// be friends of ConnRef.
// Returns a list of connector Ids of all the connectors of type
// 'type' attached to the shape with the ID 'shapeId'.
const unsigned int type)
{
}
}
}
}
// Returns a list of shape Ids of all the shapes attached to the
// shape with the ID 'shapeId' with connection type 'type'.
const unsigned int type)
{
if ((*i)->_srcId != 0)
{
// Only if there is a shape attached to the other end.
}
}
if ((*i)->_dstId != 0)
{
// Only if there is a shape attached to the other end.
}
}
}
}
// It's intended this function is called after shape movement has
// happened to alert connectors that they need to be rerouted.
void Router::callbackAllInvalidConnectors(void)
{
(*i)->handleInvalid();
}
}
{
// o Check all visibility edges to see if this one shape
// blocks them.
{
{
bool blocked = false;
if (ep_in_poly1 || ep_in_poly2)
{
// Don't check edges that have a connector endpoint
// and are inside the shape being added.
continue;
}
{
{
blocked = true;
break;
}
}
if (blocked)
{
db_printf("\tRemoving newly blocked edge (by shape %3d)"
"... \n\t\t", pid);
tmp->alertConns();
if (InvisibilityGrph)
{
}
else
{
delete tmp;
}
}
}
}
}
{
{
{
tmp->alertConns();
}
{
}
}
}
void Router::checkAllMissingEdges(void)
{
if (IncludeEndpoints)
{
}
else
{
}
{
// Check remaining, earlier vertices
{
{
// Don't keep visibility between edges of different conns
continue;
}
// See if the edge is already there?
if (!found)
{
// Didn't already exist, check.
bool knownNew = true;
}
}
}
}
{
{
{
}
}
}
{
k = k->lstNext)
{
{
}
}
}
{
k = k->lstNext)
{
}
}
#define MIN(a, b) (((a) <= (b)) ? (a) : (b))
#define MAX(a, b) (((a) >= (b)) ? (a) : (b))
#ifdef SELECTIVE_DEBUG
static double AngleAFromThreeSides(const double a, const double b,
const double c)
{
// returns angle A, the angle opposite from side a, in radians
}
#endif
{
{
{
// Ignore uninitialised connectors.
continue;
}
else if (conn->_needs_reroute_flag)
{
// Already marked, so skip.
continue;
}
double estdist;
{
double offy;
double a;
double b;
double c;
double d;
double min;
double max;
{
// Standard case
a = start.x;
c = end.x;
}
{
// Other Standard case
a = start.y;
c = end.y;
}
else
{
// Need to do rotation
//printf("n_p2: (%.1f, %.1f)\n", n_p2.x, n_p2.y);
//printf("n_start: (%.1f, %.1f)\n", n_start.x, n_start.y);
//printf("n_end: (%.1f, %.1f)\n", n_end.x, n_end.y);
//printf("theta = %.2f\n", theta * (180 / PI));
//printf("r_p2: (%.1f, %.1f)\n", r_p2.x, r_p2.y);
//printf("r_start: (%.1f, %.1f)\n", start.x, start.y);
//printf("r_end: (%.1f, %.1f)\n", end.x, end.y);
if (((int) r_p2.y) != 0)
{
abort();
}
// This might be slightly off.
r_p2.y = 0;
a = start.x;
c = end.x;
}
double x;
if ((b + d) == 0)
{
db_printf("WARNING: (b + d) == 0\n");
d = d * -1;
}
if ((b == 0) && (d == 0))
{
db_printf("WARNING: b == d == 0\n");
{
// It's going to get adjusted.
x = a;
}
else
{
continue;
}
}
else
{
x = ((b*c) + (a*d)) / (b + d);
}
//printf("%.1f, %.1f, %.1f, %.1f\n", a, b, c, d);
//printf("x = %.1f\n", x);
// XXX: Use MAX and MIN
//printf("x = %.1f\n", x);
{
xp.y = x;
}
else
{
xp.x = x;
}
//printf("(%.1f, %.1f)\n", xp.x, xp.y);
//printf("is %.1f < %.1f\n", estdist, conndist);
{
#ifdef SELECTIVE_DEBUG
//double angle = AngleAFromThreeSides(dist(start, end),
// e1, e2);
printf("[%3d] - Possible better path found (%.1f < %.1f)\n",
#endif
conn->_needs_reroute_flag = true;
break;
}
}
}
}
{
unsigned int currshape = 0;
int st_shapes = 0;
int st_vertices = 0;
int st_endpoints = 0;
int st_valid_shape_visedges = 0;
int st_valid_endpt_visedges = 0;
int st_invalid_visedges = 0;
{
{
st_shapes++;
}
{
st_vertices++;
}
else
{
// The shape 0 ones are temporary and not considered.
st_endpoints++;
}
}
t = t->lstNext)
{
{
}
else
{
}
}
t = t->lstNext)
{
}
}
}