kicad/polygon/kbool/src/node.cpp

613 lines
15 KiB
C++

/*! \file ../src/node.cpp
\brief Holds a GDSII node structure
\author Probably Klaas Holwerda
Copyright: 2001-2004 (C) Probably Klaas Holwerda
Licence: wxWidgets Licence
RCS-ID: $Id: node.cpp,v 1.7 2005/06/17 23:01:03 kbluck Exp $
*/
#ifdef __GNUG__
#pragma implementation
#endif
#include "../include/node.h"
#include "../include/link.h"
#include "../include/line.h"
#include <math.h>
//this here is to initialize the static iterator of node
//with NOLIST constructor
//TDLI<KBoolLink> Node::_linkiter=TDLI<KBoolLink>(_GC);
Node::Node(Bool_Engine* GC) : LPoint(0,0)
{
_GC=GC;
_linklist=new DL_List<void*>();
}
Node::Node(B_INT const X, B_INT const Y, Bool_Engine* GC) : LPoint(X,Y)
{
_GC=GC;
_linklist=new DL_List<void*>();
}
Node::Node(LPoint* const a_point, Bool_Engine* GC) : LPoint(a_point)
{
_GC=GC;
_linklist=new DL_List<void*>();
}
//Node::Node(Node * const other) : LPoint(other)
Node::Node(Node * const other, Bool_Engine* GC)
{
_GC=GC;
_x = other->_x;
_y = other->_y;
_linklist=new DL_List<void*>();
}
Node& Node::operator=(const Node &other_node)
{
_x = other_node._x;
_y = other_node._y;
return *this;
}
// x and y of the point will be rounded to the nearest
// xnew=N*grid and ynew=N*grid
void Node::RoundInt(B_INT grid)
{
_x=(B_INT) floor((_x + grid * 0.5) / grid) * grid;
_y=(B_INT) floor((_y + grid * 0.5) / grid) * grid;
}
Node::~Node()
{
delete _linklist;
}
DL_List<void*>* Node::GetLinklist()
{
return _linklist;
}
void Node::AddLink(KBoolLink *a_link)
{
// assert(a_link);
_linklist->insbegin(a_link);
}
KBoolLink* Node::GetIncomingLink()
{
if (((KBoolLink*)_linklist->headitem())->GetEndNode() == this)
return (KBoolLink*)_linklist->headitem();
else
return (KBoolLink*)_linklist->tailitem();
}
KBoolLink* Node::GetOutgoingLink()
{
if (((KBoolLink*)_linklist->headitem())->GetBeginNode() == this)
return (KBoolLink*)_linklist->headitem();
else
return (KBoolLink*)_linklist->tailitem();
}
//
// Returns the number of connected links
//
int Node::GetNumberOfLinks()
{
return _linklist->count();
}
KBoolLink* Node::GetOtherLink(KBoolLink* prev)
{
if (prev==(KBoolLink*)_linklist->headitem())
return (KBoolLink*)_linklist->tailitem();
if (prev==(KBoolLink*)_linklist->tailitem())
return (KBoolLink*)_linklist->headitem();
return NULL;
}
int Node::Merge(Node *other)
{
if (this==other) //they are already merged dummy
return 0;
_GC->_linkiter->Attach(_linklist);
int Counter;
// used to delete Iterator on other->_linklist
// otherwise there can't be a takeover, because for takeover there can't
// be an iterator on other->_linklist;
{
TDLI<KBoolLink> Iother(other->_linklist);
KBoolLink* temp;
Counter = Iother.count();
Iother.tohead();
while (!Iother.hitroot())
{
temp=Iother.item();
//need to test both nodes because it may be a zero length link
if (temp->GetEndNode()==other)
temp->SetEndNode(this);
if (temp->GetBeginNode()==other)
temp->SetBeginNode(this);
Iother++;
}
_GC->_linkiter->takeover(&Iother);
}
_GC->_linkiter->Detach();
//at this moment the other nodes has no link pointing to it so it needs to be deleted
delete other;
return Counter;
}
void Node::RemoveLink(KBoolLink *a_link)
{
// assert(a_link);
_GC->_linkiter->Attach(_linklist);
if (_GC->_linkiter->toitem(a_link)) // find the link
_GC->_linkiter->remove();
_GC->_linkiter->Detach();
}
// This function will determinate if the given three points
// can be simplified to two points
//
// input : three nodes, the first and the second must be points of
// a line in correct order, the third point is a point of another
// line.
// output: -
// return: true if points can be simplified
// false if points can't be simplified
bool Node::Simplify(Node *First, Node *Second, B_INT Marge)
{
double distance=0;
// The first and second point are a zero line, if so we can
// make a line between the first and third point
if (First->Equal(Second,Marge))
return true;
// Are the first and third point equal, if so
// we can delete the second point
if (First->Equal(this, Marge))
return true;
// Used tmp_link.set here, because the link may not be linked in the graph,
// because the point of the graphs are used, after use of the line we have
//to set the link to zero so the nodes will not be destructed by exit of the function
KBoolLink tmp_link(_GC);
tmp_link.Set(First,Second);
KBoolLine tmp_line(_GC);
tmp_line.Set(&tmp_link);
// If third point is on the same line which is made from the first
// and second point then we can delete the second point
if (tmp_line.PointOnLine(this,distance, (double) Marge) == ON_AREA)
{
tmp_link.Set(NULL,NULL);
return true;
}
//
//
tmp_link.Set(Second,this);
tmp_line.Set(&tmp_link);
if (tmp_line.PointOnLine(First,distance, (double) Marge) == ON_AREA)
{
tmp_link.Set(NULL,NULL);
return true;
}
tmp_link.Set(NULL,NULL);
return false;
}
KBoolLink* Node::GetNextLink()
{
int Aantal = _linklist->count();
// assert (Aantal != 0);
// there is one link, so there is no previous link
if (Aantal == 1)
return NULL;
int Marked_Counter = 0;
KBoolLink *the_link = NULL;
// count the marked links
_GC->_linkiter->Attach(_linklist);
_GC->_linkiter->tohead();
while (!_GC->_linkiter->hitroot())
{
if (_GC->_linkiter->item()->IsMarked())
Marked_Counter++;
else
{
if (!the_link)
the_link = _GC->_linkiter->item();
}
(*_GC->_linkiter)++;
}
_GC->_linkiter->Detach();
if (Aantal - Marked_Counter != 1)
// there arent two unmarked links
return NULL;
else
{
if (the_link->GetBeginNode() == this)
return the_link;
else
return NULL;
}
}
KBoolLink* Node::GetPrevLink()
{
int Aantal;
if (!_linklist)
return NULL;
Aantal = _linklist->count();
// assert (Aantal != 0);
// there is one link, so there is no previous link
if (Aantal == 1)
return NULL;
int Marked_Counter = 0;
KBoolLink *the_link = NULL;
_GC->_linkiter->Attach(_linklist);
// count the marked links
_GC->_linkiter->tohead();
while (!_GC->_linkiter->hitroot())
{
if (_GC->_linkiter->item()->IsMarked())
Marked_Counter++;
else
{
if (!the_link)
the_link = _GC->_linkiter->item();
}
(*_GC->_linkiter)++;
}
_GC->_linkiter->Detach();
if (Aantal - Marked_Counter != 1)
// there arent two unmarked links
return NULL;
else
{
if (the_link->GetEndNode() == this)
return the_link;
else
return NULL;
}
}
bool Node::SameSides( KBoolLink* const prev , KBoolLink* const link, BOOL_OP operation )
{
bool directedLeft;
bool directedRight;
if ( prev->GetEndNode() == this ) //forward direction
{
directedLeft = prev->IsMarkedLeft( operation );
directedRight = prev->IsMarkedRight( operation );
if ( link->GetBeginNode() == this ) //forward direction
{
return directedLeft == link->IsMarkedLeft( operation ) &&
directedRight == link->IsMarkedRight( operation );
}
return directedLeft == link->IsMarkedRight( operation ) &&
directedRight == link->IsMarkedLeft( operation );
}
directedLeft = prev->IsMarkedRight( operation );
directedRight = prev->IsMarkedLeft( operation );
if ( link->GetBeginNode() == this ) //forward direction
{
return directedLeft == link->IsMarkedLeft( operation ) &&
directedRight == link->IsMarkedRight( operation );
}
return directedLeft == link->IsMarkedRight( operation ) &&
directedRight == link->IsMarkedLeft( operation );
}
// on the node get the link
// is the most right or left one
// This function is used to collect the simple graphs from a graph
KBoolLink* Node::GetMost( KBoolLink* const prev ,LinkStatus whatside, BOOL_OP operation )
{
KBoolLink *reserve=0;
KBoolLink *Result = NULL,*link;
Node* prevbegin = prev->GetOther(this);
if (_linklist->count() == 2) // only two links to this node take the one != prev
{
if ( (link = (KBoolLink*)_linklist->headitem()) == prev ) //this is NOT the one to go on
link = (KBoolLink*)_linklist->tailitem();
if (!link->BeenHere() && SameSides( prev, link, operation ) )
//we are back where we started (bin is true) return Null
return link;
return(0);
}
_GC->_linkiter->Attach(_linklist);
_GC->_linkiter->tohead();
//more then 2 links to the Node
while(!_GC->_linkiter->hitroot())
{
link = _GC->_linkiter->item();
if ( !link->BeenHere() &&
SameSides( prev, link, operation ) &&
link != prev //should be set to bin already
)
{
if (prevbegin == link->GetOther(this) )//pointers equal
//we are going back in the same direction on a parallel link
//only take this possibility if nothing else is possible
reserve = link;
else
{ //this link is in a different direction
if (!Result)
Result = link; //first one found sofar
else
{
if (prev->PointOnCorner(Result, link) == whatside )
//more to the whatside than take this one
Result = link;
}
}
}
(*_GC->_linkiter)++;
}
// if there is a next link found return it
// else if a parallel link is found return that one
// else return NULL
_GC->_linkiter->Detach();
return ((Result) ? Result : reserve);
}
// on the node get the link
// is the most right or left one
// This function is used to collect the simple graphs from a graph
KBoolLink* Node::GetMostHole( KBoolLink* const prev, LinkStatus whatside, BOOL_OP operation )
{
KBoolLink *reserve=0;
KBoolLink *Result=NULL,*link;
Node* prevbegin = prev->GetOther(this);
if (_linklist->count() == 2) // only two links to this node take the one != prev
{
if ( (link = (KBoolLink*)_linklist->headitem()) == prev ) //this is NOT the one to go on
link = (KBoolLink*)_linklist->tailitem();
if ( link->GetHole() && !link->GetHoleLink() && !link->BeenHere() && SameSides( prev, link, operation ) )
//we are back where we started (bin is true) return Null
return link;
return(0);
}
_GC->_linkiter->Attach(_linklist);
_GC->_linkiter->tohead();
//more then 2 links to the Node
while(!_GC->_linkiter->hitroot())
{
link = _GC->_linkiter->item();
if ( !link->BeenHere() &&
link->GetHole() &&
!link->GetHoleLink() &&
SameSides( prev, link, operation ) &&
link != prev //should be set to bin already
)
{
if (prevbegin == link->GetOther(this) )//pointers equal
//we are going back in the same direction on a parallel link
//only take this possibility if nothing else is possible
reserve = link;
else
{ //this link is in a different direction
if (!Result)
Result = link; //first one found sofar
else
{
if (prev->PointOnCorner(Result, link) == whatside )
//more to the whatside than take this one
Result = link;
}
}
}
(*_GC->_linkiter)++;
}
// if there is a next link found return it
// else if a parallel link is found return that one
// else return NULL
_GC->_linkiter->Detach();
return ((Result) ? Result : reserve);
}
// this function gets the highest not flat link
KBoolLink* Node::GetHoleLink( KBoolLink* const prev, bool checkbin, BOOL_OP operation )
{
KBoolLink *Result=NULL,*link;
_GC->_linkiter->Attach(_linklist);
for(_GC->_linkiter->tohead();!_GC->_linkiter->hitroot();(*_GC->_linkiter)++)
{
link=_GC->_linkiter->item();
if ( link->GetHoleLink() &&
( !checkbin || ( checkbin && !link->BeenHere()) ) &&
SameSides( prev, link, operation )
)
{
Result=link;
break;
}
}
_GC->_linkiter->Detach();
return (Result);
}
// this function gets the highest not flat link
KBoolLink* Node::GetNotFlat()
{
KBoolLink *Result=NULL,*link;
_GC->_linkiter->Attach(_linklist);
double tangold = 0.0;
double tangnew = 0.0;
for(_GC->_linkiter->tohead();!_GC->_linkiter->hitroot();(*_GC->_linkiter)++)
{
link=_GC->_linkiter->item();
if (!_GC->_linkiter->item()->BeenHere())
{
B_INT dx=link->GetOther(this)->GetX()-_x;
B_INT dy=link->GetOther(this)->GetY()-_y;
if (dx!=0)
{
tangnew=fabs( (double) dy / (double) dx );
}
else
{
tangnew=MAXDOUBLE;
}
if (!Result)
{
//this link is in a different direction
Result=link; //first one found sofar
tangold=tangnew;
}
else
{
if(tangnew < tangold)
{
//this one is higher (more horizontal) then the old Result
Result=link;
tangold=tangnew;
}
}
}
}
// if there is a next link found return it
// else if a parallel link is found return that one
// else return NULL
_GC->_linkiter->Detach();
return (Result);
}
// on the node get the link that is not BIN
// and that has the same graphnumber and is in same direction
KBoolLink *Node::Follow(KBoolLink* const prev )
{
KBoolLink *temp;
_GC->_linkiter->Attach(_linklist);
_GC->_linkiter->tohead();
while(!_GC->_linkiter->hitroot())
{
if (( _GC->_linkiter->item() != prev ) &&
( !_GC->_linkiter->item()->BeenHere()) &&
( _GC->_linkiter->item()->GetGraphNum() == prev->GetGraphNum()) &&
(
( (prev->GetEndNode() == this) &&
(_GC->_linkiter->item()->GetEndNode() !=this)
)
||
( (prev->GetBeginNode() == this) &&
(_GC->_linkiter->item()->GetBeginNode() !=this)
)
)
)
{
temp=_GC->_linkiter->item();
_GC->_linkiter->Detach();
return(temp);
}
(*_GC->_linkiter)++;
}
_GC->_linkiter->Detach();
return (0);
}
// this function gets the highest (other node) link ascending from the node
// that has the bin flag set as the argument binset
// if no such link exists return 0
KBoolLink* Node::GetBinHighest(bool binset)
{
KBoolLink *Result=NULL,*link;
_GC->_linkiter->Attach(_linklist);
double tangold = 0.0;
double tangnew = 0.0;
for(_GC->_linkiter->tohead();!_GC->_linkiter->hitroot();(*_GC->_linkiter)++)
{
link=_GC->_linkiter->item();
if (_GC->_linkiter->item()->BeenHere() == binset)
{
B_INT dx=link->GetOther(this)->GetX()-_x;
B_INT dy=link->GetOther(this)->GetY()-_y;
if (dx!=0)
{
tangnew = (double) dy / (double) dx;
}
else if (dy > 0)
{
tangnew = MAXDOUBLE;
}
else
{
tangnew = -MAXDOUBLE;
}
if (!Result)
{
Result = link; //first one found sofar
tangold = tangnew;
}
else
{
if(tangnew > tangold)
{
//this one is higher then the old Result
Result = link;
tangold = tangnew;
}
}
}
}
// if there is a link found return it
// else return NULL
_GC->_linkiter->Detach();
return (Result);
}