/*! \file src/graph.cpp
    \brief Used to Intercect and other process functions
    \author Klaas Holwerda 
 
    Copyright: 2001-2004 (C) Klaas Holwerda
 
    Licence: see kboollicense.txt 
 
    RCS-ID: $Id: graph.cpp,v 1.7 2009/09/14 16:50:12 titato Exp $
*/

// Grpah is the structure used to store polygons

#include "kbool/booleng.h"
#include "kbool/graph.h"
#include "kbool/graphlst.h"
#include "kbool/node.h"

// Prototype of function
int linkXYsorter( kbLink *, kbLink * );
int linkYXsorter( kbLink *, kbLink * );
int linkLsorter( kbLink *, kbLink * );
int linkYXtopsorter( kbLink *a, kbLink *b );
int linkGraphNumsorter( kbLink *_l1, kbLink* _l2 );

// constructor, initialize with one link
// usage: kbGraph *a_graph = new kbGraph(a_link);
kbGraph::kbGraph( kbLink *a_link, Bool_Engine* GC )
{
    _GC = GC;
    _linklist = new DL_List<void*>();

    _linklist->insbegin( a_link );
    _bin = false;

}


// constructor, initialize graph with no contents
// usage: kbGraph *a_graph = new kbGraph();
kbGraph::kbGraph( Bool_Engine* GC )
{
    _GC = GC;
    _linklist = new DL_List<void*>();
    _bin = false;
}

kbGraph::kbGraph( kbGraph* other )
{
    _GC = other->_GC;
    _linklist = new DL_List<void*>();
    _bin = false;

    int _nr_of_points = other->_linklist->count();
    kbLink* _current = other->GetFirstLink();

    kbNode* _last = _current->GetBeginNode();
    kbNode* node = new kbNode( _current->GetBeginNode()->GetX(), _current->GetBeginNode()->GetY(), _GC );
    kbNode* nodefirst = node;
    for ( int i = 0; i < _nr_of_points; i++ )
    {
        // get the other node on the link
        _last = _current->GetOther( _last );
        // get the other link on the _last node
        _current = _current->Forth( _last );

        kbNode* node2 = new kbNode( _current->GetBeginNode()->GetX(), _current->GetBeginNode()->GetY(), _GC );
        _linklist->insend( new kbLink( node,  node2, _GC ) );
        node = node2;
    }
    _linklist->insend( new kbLink( node,  nodefirst, _GC ) );
}

// destructor
// deletes all object of the linklist
kbGraph::~kbGraph()
{
    {
        TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );

        //first empty the graph
        _LI.delete_all();
    }

    delete _linklist;
}

kbLink* kbGraph::GetFirstLink()
{
    return ( kbLink* ) _linklist->headitem();
}


void kbGraph::Prepare( int intersectionruns )
{
    _GC->SetState( "Intersection" );

    bool found = true;
    int run = 0;
    while( run < intersectionruns && found )
    {
        found = CalculateCrossings( _GC->GetInternalMarge() );
        run++;
    }

//WHY
// Round(_GC->Get_Grid());

    {
        TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
        _LI.foreach_mf( &kbLink::UnMark );// Reset Bin and Mark flag
    }
    _GC->SetState( "Set group A/B Flags" );

    bool dummy = false;

    if ( _GC->GetWindingRule() )
        ScanGraph2( INOUT, dummy );

    ScanGraph2( GENLR, dummy );

// writegraph();

    _GC->SetState( "Set operation Flags" );
    Set_Operation_Flags();

    _GC->SetState( "Remove doubles" );
    // Remove the marked links
    {
        TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
        _LI.tohead();
        while( !_LI.hitroot() )
        {
            if ( _LI.item()->IsMarked() )
            {
                delete _LI.item();
                _LI.remove();
            }
            else
                _LI++;
        }
    }

    _GC->SetState( "Remove inlinks" );
    Remove_IN_Links();


    _GC->SetState( "Finished prepare graph" );
}



// x and y of the point will be rounded to the nearest
// xnew=N*grid and ynew=N*grid
void kbGraph::RoundInt( B_INT grid )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        _LI.item()->GetBeginNode()->RoundInt( grid );
        _LI.item()->GetEndNode()->RoundInt( grid );
        _LI++;
    }
}

// rotate graph minus 90 degrees or plus 90 degrees
void kbGraph::Rotate( bool plus90 )
{
    B_INT swap;
    kbNode* last = NULL;

    B_INT neg = -1;
    if ( plus90 )
        neg = 1;

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.mergesort( linkXYsorter );

    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        if ( _LI.item()->GetBeginNode() != last )
        {
            swap = _LI.item()->GetBeginNode()->GetX();
            _LI.item()->GetBeginNode()->SetX( -neg * ( _LI.item()->GetBeginNode()->GetY() ) );
            _LI.item()->GetBeginNode()->SetY( neg * swap );
            last = _LI.item()->GetBeginNode();
        }
        _LI++;
    }
}

bool kbGraph::RemoveNullLinks()
{
    bool graph_is_modified = false;

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        if ( _LI.item()->GetBeginNode() == _LI.item()->GetEndNode() )
        {
            _LI.item()->MergeNodes( _LI.item()->GetBeginNode() );
            delete _LI.item();
            _LI.remove();
            graph_is_modified = true;
        }
        else
            _LI++;
    }
    return ( graph_is_modified );
}

// Add a link to the graph connection with
// other links is through the link his nodes
void kbGraph::AddLink( kbLink *a_link )
{
    assert( a_link );

    _linklist->insend( a_link );
}


// Add a link to the graph, by giving it two nodes
// the link is then made and added to the graph
void kbGraph::AddLink( kbNode *begin, kbNode *end )
{
    assert( begin && end );
    assert( begin != end );
    AddLink( new kbLink( 0, begin, end, _GC ) );
}


// Checks if there is a zeroline in the graph
bool kbGraph::AreZeroLines( B_INT Marge )
{
    bool Found_it = false;

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        if ( _LI.item()->IsZero( Marge ) )
        {
            Found_it = true;
            break;
        }
        _LI++;
    }
    return Found_it;
}


// Delete links that do not fit the condition for given operation
void kbGraph::DeleteNonCond( BOOL_OP operation )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while( !_LI.hitroot() )
    {
        if ( !_LI.item()->IsMarked( operation ) )
        {
            delete _LI.item();
            _LI.remove();
        }
        else
            _LI++;
    }
}

void kbGraph::HandleNonCond( BOOL_OP operation )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while( !_LI.hitroot() )
    {
        if ( !_LI.item()->IsMarked( operation ) )
        {
            _LI.item()->SetBeenHere();
            _LI.item()->SetGraphNum( -1 );
        }
        _LI++;
    }
}

// All lines in the graph wich have a length < _GC->Get_Marge() will be deleted
//
// input : a marge, standard on _GC->Get_Marge()
// return: true if lines in the graph are deleted
//       : false if no lines in the graph are deleted
bool kbGraph::DeleteZeroLines( B_INT Marge )
{
    // Is the graph modified ?
    bool Is_Modified = false;
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );

    int Processed = _LI.count();

    _LI.tohead();
    while ( Processed > 0 )
    {
        Processed--;
        if ( _LI.item()->IsZero( Marge ) )
        {
            // the current link is zero, so make from both nodes one node
            // and delete the current link from this graph
            _LI.item()->MergeNodes( _LI.item()->GetBeginNode() );
            // if an item is deleted the cursor of the list is set to the next
            // so no explicit forth is needed
            delete _LI.item();
            _LI.remove();
            // we have to set Processed, because if a zero line is deleted
            // another can be made zero by this deletion
            Processed = _LI.count();
            Is_Modified = true;
            if ( _LI.hitroot() )
                _LI.tohead();
        }
        else
            _LI++;
        if ( _LI.hitroot() )
            _LI.tohead();
    }
    return Is_Modified;
}


// Collects a graph starting at currentnode or attached link
// follow graphs right around.
// since the input node is always a topleft node, we can see on
// a connected link if we or dealing with a hole or NON hole.
// for instance a top link of a hole that is horizontal, always
// is IN above the link and OUT underneath the link.
// this for a non hole the opposite
void kbGraph::CollectGraph( kbNode *current_node, BOOL_OP operation, bool detecthole, int graphnumber, bool& foundholes )
{
    kbLink * currentlink;
    kbLink *nextlink;
    kbNode *next_node;
    kbNode *MyFirst;
    kbNode *Unlinked;
    kbLink *MyFirstlink;

    bool Hole;
    LinkStatus whatside;

    currentlink = current_node->GetNotFlat();
    if ( !currentlink )
    {
        char buf[100];
        if ( detecthole )
            sprintf( buf, "no NON flat link Collectgraph for operation at %15.3lf , %15.3lf",
                     double( current_node->GetX() ), double( current_node->GetY() ) );
        else
            sprintf( buf, "no NON flat link Collectgraph at %15.3lf , %15.3lf",
                     double( current_node->GetX() ), double( current_node->GetY() ) );
        throw Bool_Engine_Error( buf, "Error", 9, 0 );
    }

    currentlink->SetBeenHere();

    if ( detecthole )
        Hole = currentlink->IsHole( operation );
    else
        Hole = currentlink->GetHole(); //simple extract do not detect holes, but use hole flag.

    currentlink->Redirect( current_node );

    foundholes = Hole || foundholes;

    //depending if we have a hole or not
    //we take the left node or right node from the selected link (currentlink)
    //this MEANS for holes go left around and for non holes go right around
    //since the currentlink is already set to binhere, it will not go in that direction
    if ( Hole )
    {
        whatside = IS_LEFT;
        if ( currentlink->GetEndNode()->GetX() > current_node->GetX() )
            current_node = currentlink->GetEndNode();
    }
    else
    {
        whatside = IS_RIGHT;
        if ( currentlink->GetEndNode()->GetX() < current_node->GetX() )
            current_node = currentlink->GetEndNode();
    }
    currentlink->Redirect( current_node );
    MyFirst = current_node; //remember this as the start
    MyFirstlink = currentlink;

    next_node = currentlink->GetEndNode();

    // If this is a hole, Set as special link, this is the top link of this hole !
    // from this link we have to make links to the link above later on.
    if ( Hole )
        currentlink->SetTopHole( true );
    //set also the link as being part of a hole
    if ( detecthole )
        currentlink->SetHole( Hole );
    currentlink->SetGraphNum( graphnumber );

    // Walk over links and redirect them. taking most right links around
    while ( currentlink != NULL )
    {
        if ( Hole )
        {
            nextlink = next_node->GetMost( currentlink, IS_RIGHT, operation );
        }
        else
        {
            nextlink = next_node->GetMost( currentlink, IS_LEFT, operation );
            // next works too if same is used in CollectGraphLast
            //nextlink = next_node->GetMost(currentlink, IS_RIGHT, operation);
        }

        if ( nextlink == NULL )
        { //END POINT MUST BE EQAUL TO BEGIN POINT
            if ( !next_node->Equal( MyFirst, 1 ) )
            {
                throw Bool_Engine_Error( "no next (endpoint != beginpoint)", "graph", 9, 0 );

                //for god sake try this
                //nextlink = next_node->GetMost(currentlink, whatside ,operation);
            }
        }

        current_node = next_node;

        if ( nextlink != NULL )
        {
            nextlink->Redirect( current_node );
            nextlink->SetBeenHere();
            next_node = nextlink->GetEndNode();

            if ( current_node->GetNumberOfLinks() > 2 )
            {  // replace endnode of currentlink and beginnode of nextlink with new node
                Unlinked = new kbNode( current_node, _GC );
                currentlink->Replace( current_node, Unlinked );
                nextlink->Replace( current_node, Unlinked );
            }

            if ( detecthole )
                nextlink->SetHole( Hole );
            nextlink->SetGraphNum( graphnumber );
        }
        else
        {
            //close the found graph properly
            if ( current_node->GetNumberOfLinks() > 2 )
            {  // replace endnode of currentlink and beginnode of nextlink with new node
                Unlinked = new kbNode( current_node, _GC );
                currentlink->Replace( current_node, Unlinked );
                MyFirstlink->Replace( current_node, Unlinked );
            }
        }

        currentlink = nextlink;
    }

    //END POINT MUST BE EQAUL TO BEGIN POINT
    if ( !current_node->Equal( MyFirst, 1 ) )
    {
        throw Bool_Engine_Error( "in collect graph endpoint != beginpoint", "Error", 9, 0 );
    }
}

void kbGraph::CollectGraphLast( kbNode *current_node, BOOL_OP operation, bool detecthole, int graphnumber, bool& foundholes )
{
    kbLink * currentlink;
    kbLink *nextlink;
    kbNode *next_node;
    kbNode *MyFirst;
    kbNode *Unlinked;
    kbLink *MyFirstlink;

    bool Hole;
    LinkStatus whatside;

    currentlink = current_node->GetNotFlat();
    if ( !currentlink )
    {
        char buf[100];
        if ( detecthole )
            sprintf( buf, "no NON flat link Collectgraph for operation at %15.3lf , %15.3lf",
                     double( current_node->GetX() ), double( current_node->GetY() ) );
        else
            sprintf( buf, "no NON flat link Collectgraph at %15.3lf , %15.3lf",
                     double( current_node->GetX() ), double( current_node->GetY() ) );
        throw Bool_Engine_Error( buf, "Error", 9, 0 );
    }

    currentlink->SetBeenHere();

    if ( detecthole )
        Hole = currentlink->IsHole( operation );
    else
        Hole = currentlink->GetHole(); //simple extract do not detect holes, but use hole flag.

    currentlink->Redirect( current_node );

    foundholes = Hole || foundholes;

    //depending if we have a hole or not
    //we take the left node or right node from the selected link (currentlink)
    //this MEANS for holes go left around and for non holes go right around
    //since the currentlink is already set to binhere, it will not go in that direction
    if ( Hole )
    {
        whatside = IS_LEFT;
        if ( currentlink->GetEndNode()->GetX() > current_node->GetX() )
            current_node = currentlink->GetEndNode();
    }
    else
    {
        whatside = IS_RIGHT;
        if ( currentlink->GetEndNode()->GetX() < current_node->GetX() )
            current_node = currentlink->GetEndNode();
    }
    currentlink->Redirect( current_node );
    MyFirst = current_node; //remember this as the start
    MyFirstlink = currentlink;

    next_node = currentlink->GetEndNode();

    // If this is a hole, Set as special link, this is the top link of this hole !
    // from this link we have to make links to the link above later on.
    if ( Hole )
        currentlink->SetTopHole( true );
    currentlink->SetGraphNum( graphnumber );

    // Walk over links and redirect them. taking most right links around
    while ( currentlink != NULL )
    {
        if ( Hole )
        {
            if ( currentlink->GetHoleLink() )
            {
                //in case we entered the hole via the hole link just now, we follow the hole.
                //This is taking as many holes as possible ( most right around)
                nextlink = next_node->GetMostHole( currentlink, IS_RIGHT , operation, false );
                if ( !nextlink ) // hole done?
                    //if we did get to this hole via a holelink?, then we might now be on the return link.
                    //BTW it is also possible that holes are already found via a non linked hole path,
                    //in that case, we did go to the HoleLink here, and directly return on the other holelink.
                    nextlink = next_node->GetHoleLink( currentlink, IS_RIGHT, true, operation );
                if ( !nextlink )
                {
                    //we did get to this hole via a holelink and we are on the returning holelink.
                    //So we left the hole collection, and continue with contours.
                    //Most Right is needed!
                    nextlink = next_node->GetMost( currentlink, IS_RIGHT, operation );
                }
            }
            else
            {
                nextlink = next_node->GetMostHole( currentlink, IS_RIGHT, operation ); // other holes first
                if ( !nextlink )
                    nextlink = next_node->GetHoleLink( currentlink,  IS_RIGHT, true, operation ); // other linked holes first
                if ( !nextlink )
                {
                    //We are leaving the hole.
                    //So we left the hole collection, and continue with contours.
                    //Most Right is needed!
                    nextlink = next_node->GetMost( currentlink, IS_RIGHT, operation );
                }
            }
        }
        else
        {
            //nextlink = next_node->GetMost( currentlink, IS_RIGHT, operation );
            //if ( !nextlink )

            //a hole link is preferred above a normal link. If not no holes would be linked in anyway.
            nextlink = next_node->GetHoleLink( currentlink, IS_RIGHT, true, operation );
            if ( !nextlink )
                //also if we can get to a hole directly within a contour, that is better (get as much as possible)
                nextlink = next_node->GetMostHole( currentlink, IS_RIGHT, operation );
            if ( !nextlink )
                //if non of the above, we are still on the contour and take as must as possible to the left.
                //Like that we take as many contour togethere as possible.

                nextlink = next_node->GetMost( currentlink, IS_LEFT, operation );
            // next works too if same is used in CollectGraphLast
            //nextlink = next_node->GetMost(currentlink, IS_RIGHT, operation);
        }

        if ( nextlink == NULL )
        { //END POINT MUST BE EQAUL TO BEGIN POINT
            if ( !next_node->Equal( MyFirst, 1 ) )
            {
                throw Bool_Engine_Error( "no next (endpoint != beginpoint)", "graph", 9, 0 );

                //for god sake try this
                //nextlink = next_node->GetMost(currentlink, whatside, operation);
            }
        }
        else
        {
            // when holes are already know, use the hole information to
            // go left are right around.
            Hole = nextlink->GetHole() || nextlink->GetHoleLink();
        }
        current_node = next_node;

        if ( nextlink != NULL )
        {
            nextlink->Redirect( current_node );
            nextlink->SetBeenHere();
            next_node = nextlink->GetEndNode();

            if ( current_node->GetNumberOfLinks() > 2 )
            {  // replace endnode of currentlink and beginnode of nextlink with new node
                Unlinked = new kbNode( current_node, _GC );
                currentlink->Replace( current_node, Unlinked );
                nextlink->Replace( current_node, Unlinked );
            }

            nextlink->SetGraphNum( graphnumber );
        }
        else
        {
            //close the found graph properly
            if ( current_node->GetNumberOfLinks() > 2 )
            {  // replace endnode of currentlink and beginnode of nextlink with new node
                Unlinked = new kbNode( current_node, _GC );
                currentlink->Replace( current_node, Unlinked );
                MyFirstlink->Replace( current_node, Unlinked );
            }
        }

        currentlink = nextlink;
    }

    //END POINT MUST BE EQAUL TO BEGIN POINT
    if ( !current_node->Equal( MyFirst, 1 ) )
    {
        throw Bool_Engine_Error( "in collect graph endpoint != beginpoint", "Error", 9, 0 );
    }
}
//==============================================================================
//==============================================================================

// Extract bi-directional graphs from this graph
// Mark the graphs also as being a hole or not.
void kbGraph::Extract_Simples( BOOL_OP operation, bool detecthole, bool& foundholes )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    if ( _LI.empty() ) return;
    kbNode *begin;
    int graphnumber = 1;

    _LI.mergesort( linkYXtopsorter );
    _LI.tohead();
    while ( true )
    {
        begin = GetMostTopLeft( &_LI ); // from all the most Top nodes,
        // take the most left one
        // to most or not to most, that is the question
        if ( !begin )
            break;

        try // collect the graph
        {
            if ( detecthole )
                CollectGraph( begin, operation, detecthole, graphnumber++, foundholes );
            else
                //CollectGraph( begin,operation,detecthole,graphnumber++, foundholes );
                CollectGraphLast( begin, operation, detecthole, graphnumber++, foundholes );
        }
        catch ( Bool_Engine_Error & error )
        {
            _GC->info( error.GetErrorMessage(), "error" );
            throw error;
        }
    }
}

void kbGraph::Split( kbGraphList* partlist )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    if ( _LI.empty() ) return;

    kbGraph *part = NULL;
    int graphnumber = 0;

    //sort the graph on graphnumber
    _LI.mergesort( linkGraphNumsorter );

    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        if ( _LI.item()->GetGraphNum() > 0 && graphnumber != _LI.item()->GetGraphNum() )
        {
            graphnumber = _LI.item()->GetGraphNum();
            part = new kbGraph( _GC );
            partlist->insend( part );
        }
        kbLink* tmp = _LI.item();
        if ( _LI.item()->GetGraphNum() > 0 )
        {
            part->AddLink( tmp );
        }
        else
        {
            delete tmp;
        }
        _LI.remove();
    }
}

bool kbGraph::GetBeenHere()
{
    return _bin;
}

// return total number of links in this graph
int kbGraph::GetNumberOfLinks()
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    return _LI.count();
}

//for all operations set the operation flags for the links
//based on the Group_Left_Right values
void kbGraph::Set_Operation_Flags()
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while( !_LI.hitroot() )
    {
        _LI.item()->SetLineTypes();
        _LI++;
    }
}

//  Remove unused (those not used for any operation) links
void kbGraph::Remove_IN_Links()
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    for ( int t = _LI.count() ; t > 0; t-- )
    {
        // Is this link not used for any operation?
        if ( _LI.item()->IsUnused() )
        {
            delete _LI.item();
            _LI.remove();
        }
        else
            _LI++;
    }
}

void kbGraph::ResetBinMark()
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    if ( _LI.empty() ) return;
    _LI.foreach_mf( &kbLink::UnMark );//reset bin and mark flag of each link
}

void kbGraph::ReverseAllLinks()
{
    kbNode * dummy;
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        // swap the begin- and endnode of the current link
        dummy = _LI.item()->GetBeginNode();
        _LI.item()->SetBeginNode( _LI.item()->GetEndNode() );
        _LI.item()->SetEndNode( dummy );
        _LI++;
    }
}

void kbGraph::SetBeenHere( bool value )
{
    _bin = value;
}

// ReSet the flags  of the links
void kbGraph::Reset_flags()
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.foreach_mf( &kbLink::Reset_flags );
}

// ReSet the bin and mark flag of the links
void kbGraph::Reset_Mark_and_Bin()
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.foreach_mf( &kbLink::UnMark );//reset bin and mark flag of each link
}

// Set the group of the links to the same as newgroup
void kbGraph::SetGroup( GroupType newgroup )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        _LI.item()->SetGroup( newgroup );
        _LI++;
    }
}


// Set the number of the links to the same as newnr
void kbGraph::SetNumber( const int newnr )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        _LI.item()->SetGraphNum( newnr );
        _LI++;
    }
}


// This function will simplify a graph with the following rules
//
// This are the rules for symplifying the graphs
// 1. The following point is the same as the current one
// 2. The point after the following point is the same as the current one
// 3. The point after the following point lies on the same line as the current
//
// input : a marge
// return: true if graph is modified
//   : false if graph is NOT simplified
bool kbGraph::Simplify( B_INT Marge )
{
    bool graph_is_modified = false;
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    int Processed = _LI.count();

    _LI.foreach_mf( &kbLink::UnMark );//reset bin and mark flag of each link

    _LI.tohead();
    GroupType mygroup = _LI.item()->Group();

    // All items must be processed
    while ( Processed > 0 )
    {
        // Gives the number of items to process
        Processed--;
        // Check if line is marked
        // Links will be marked during the process
        if ( _LI.item()->IsMarked() )
        {
            delete _LI.item();
            _LI.remove();
            graph_is_modified = true;
            Processed = _LI.count();
            if ( _LI.hitroot() )
                _LI.tohead();
            continue;
        }

        // Line is not marked, check if line is zero
        if ( _LI.item()->IsZero( Marge ) )
        {
            _LI.item()->MergeNodes( _LI.item()->GetBeginNode() );
            delete _LI.item();
            _LI.remove();
            graph_is_modified = true;
            Processed = _LI.count();
            if ( _LI.hitroot() )
                _LI.tohead();
            continue;
        }

        // begin with trying to simplify the link
        {
            // Line is not marked, not zero, so maybe it can be simplified
            bool virtual_link_is_modified;
            kbNode *new_begin, *new_end, *a_node;
            kbLink *a_link;

            _LI.item()->Mark();
            new_begin = _LI.item()->GetBeginNode();
            new_end   = _LI.item()->GetEndNode();

            // while virtual link is modified
            do
            {
                virtual_link_is_modified = false;
                // look in the previous direction
                if ( ( a_link = new_begin->GetPrevLink() ) != NULL )
                {
                    a_node = a_link->GetBeginNode();
                    if ( a_node->Simplify( new_begin, new_end, Marge ) )
                    {
                        new_begin->GetPrevLink()->Mark();
                        new_begin = a_node;
                        virtual_link_is_modified = true;
                    }
                }
                // look in the next direction
                if ( ( a_link = new_end->GetNextLink() ) != NULL )
                {
                    a_node = a_link->GetEndNode();
                    if ( a_node->Simplify( new_begin, new_end, Marge ) )
                    {
                        new_end->GetNextLink()->Mark();
                        new_end = a_node;
                        virtual_link_is_modified = true;
                    }
                }
                graph_is_modified = ( bool ) ( graph_is_modified || virtual_link_is_modified );
            }
            while ( virtual_link_is_modified );

            // was the link simplified
            if ( ( _LI.item()->GetBeginNode() != new_begin ) ||
                    ( _LI.item()->GetEndNode() != new_end ) )
            {
                // YES !!!!!
                int number = _LI.item()->GetGraphNum();
                delete _LI.item();
                _LI.remove();

                if ( _LI.hitroot() )
                    _LI.tohead();

                kbLink *newlink = new kbLink( number, new_begin, new_end, _GC );
                newlink->SetGroup( mygroup );

                _LI.insend( newlink );
                Processed = _LI.count();
                graph_is_modified = true;
                continue;
            }
            _LI.item()->UnMark();
        } // end of try to simplify
        _LI++;
        if ( _LI.hitroot() )
            _LI.tohead();
    }//end while all processed

    return graph_is_modified;
}

/*
// This function will smoothen a graph with the following rules
//
// 0. Process graphs with more than 3 links only. (while more than 3)
//  Otherwise some objects may end-up as lines or disappear completely.
// 1.
//  a. ?  Does begin-node lay on line(prevline.beginnode,endnode)
//     ->  merge beginnode to endnode
//  b. ?  Does end-node lay on line(beginnode,nextline.endnode)
//     ->  merge endnode to beginnode
// 2.
//  a. ?  Is distance between prevline.beginnode and endnode to short
//     ->  merge beginnode to endnode
//   b. ?  Is distance between beginnode and nextline.endnode to short
//     ->  merge endnode to beginnode
// 3.
//  a. ?  Does (this)beginnode lay in area of nextline
//    AND does cross-node lay on nextline
//   ->   move endnode to crossing of prevline and nextline
//  b. ?  Does (this)endnode lay in area of prevline
//    AND does cross-node lay on prevline
//   ->   move beginnode to crossing of prevline and nextline
// 4.
//  ?  Is this link too short
//   ?  Is prevline shorter than nextline
//     Y ->  ?  Is prevlink shorter than maxlength
//     ->  merge endnode to beginnode
//     N ->  ?  Is nextlink shorter than maxlength
//     ->  merge endnode to beginnode
//
//
// Types of glitches / lines to remove :
//
//    \         /      \     /       \         /
//   Z---A---B  OR  Z-------B---A    =>   Z-------B
//
//   (1)
//
//   ----A    C----          =>  ----A-----C----
//    \   /
//   (2)   \ /
//        B
//
//   ---Z                                          ---Z
//       \                                                \
//   (3)  \                                                \
//         \   B----------C--       =>          A---B----------C--
//          \ /
//           A
//
//   --Z---A                                          --Z__
//          \                                              -__
//   (4)     B------------C--       =>            B------------C--
//
// linkLsorter(L1,L2)
//  ret:
//   +1  L1 < L2
//    0  L1 == L2
//   -1  L1 > L2
//
*/
bool kbGraph::Smoothen( B_INT Marge )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    if ( _LI.count() <= 3 ) // Don't modify it
        return false;

    kbNode *Z, *A, *B, *C, *cross_node = new kbNode( _GC );
    kbLink *prevlink, *nextlink, *thislink;
    kbLine prevline( _GC ),  nextline( _GC ),  thisline( _GC );
    kbLine prevhelp( _GC ),  nexthelp( _GC );

    kbLink  LZB( new kbNode( _GC ), new kbNode( _GC ), _GC ),
    LAC( new kbNode( _GC ), new kbNode( _GC ), _GC );

    double distance = 0;
    double prevdist, nextdist;

    bool doprev, donext;
    bool graph_is_modified = false;
    bool kill = false; // for first instance

    _LI.tohead();
    int todo = _LI.count();
    thislink = _LI.item();
    B = thislink->GetEndNode();
    nextlink = thislink->Forth( B );

    // Type 1
    while ( todo > 0 )
    {
        if ( kill == true )
        {
            // remove link from graph
            _LI.toitem( thislink );
            graph_is_modified = true;
            delete _LI.item();
            _LI.remove();
            kill = false;
            thislink = nextlink;
            todo--;
            if ( _LI.count() < 3 )
                break;
        }

        A = thislink->GetBeginNode();
        B = thislink->GetEndNode();

        if ( A->ShorterThan( B, 1 ) )
        {
            A->Merge( B );
            kill = true;
            continue;
        }

        Z = thislink->Forth( A )->GetBeginNode();
        C = thislink->Forth( B )->GetEndNode();
        thisline.Set( thislink );
        thisline.CalculateLineParameters();
        nextlink = thislink->Forth( B );

        if ( thisline.PointInLine( Z, distance, 0.0 ) == ON_AREA )
        { // Z--A--B =>  Z--B       Merge this to previous
            thislink->MergeNodes( B ); // remove A
            kill = true;
            continue;
        }
        else if ( thisline.PointInLine( C, distance, 0.0 ) == ON_AREA )
        { // A--B--C =>  A--C       Merge this to next
            thislink->MergeNodes( A ); // remove B
            kill = true;
            continue;
        }

        thislink = nextlink;
        todo--;
    }

    kill = false;
    todo = _LI.count();
    _LI.mergesort( linkLsorter );
    _LI.tohead();

    while ( todo > 0 )
    {
        if ( kill == true )
        {
            delete _LI.item();
            _LI.remove();
            graph_is_modified = true;
            kill = false;
            //mergesort(linkLsorter);
            _LI.mergesort( linkLsorter );
            _LI.tohead();
            todo = _LI.count();
            if ( todo < 3 )  // A polygon, at least, has 3 sides
                break;
        }

        // Keep this order!
        thislink = _LI.item();
        A = thislink->GetBeginNode();
        B = thislink->GetEndNode();
        prevlink = thislink->Forth( A );
        nextlink = thislink->Forth( B );
        Z = prevlink->GetBeginNode();
        C = nextlink->GetEndNode();

        if ( A->ShorterThan( B, 1 ) )
        {
            A->Merge( B );
            kill = true;
            continue;
        }

        prevline.Set( prevlink );
        prevline.CalculateLineParameters();
        nextline.Set( nextlink );
        nextline.CalculateLineParameters();

        // Type 2
        if ( B->ShorterThan( Z, Marge ) )
        { // Z--A--B =>  Z--B       Merge this to previous
            thislink->MergeNodes( B ); // remove A
            kill = true;
            continue;
        }
        else if ( A->ShorterThan( C, Marge ) )
        { // A--B--C =>  A--C       Merge this to next
            thislink->MergeNodes( A ); // remove B
            kill = true;
            continue;
        }


        *LZB.GetBeginNode() = *Z;
        *LZB.GetEndNode() = *B;
        *LAC.GetBeginNode() = *A;
        *LAC.GetEndNode() = *C;
        prevhelp.Set( &LZB );
        nexthelp.Set( &LAC );
        prevhelp.CalculateLineParameters();
        nexthelp.CalculateLineParameters();


        // Type 4
        doprev = bool( prevhelp.PointInLine( A, prevdist, ( double )Marge ) == IN_AREA );
        donext = bool( nexthelp.PointInLine( B, nextdist, ( double )Marge ) == IN_AREA );
        doprev = bool( B->ShorterThan( Z, _GC->GetInternalMaxlinemerge() ) && doprev );
        donext = bool( A->ShorterThan( C, _GC->GetInternalMaxlinemerge() ) && donext );

        if ( doprev && donext )
        {
            if ( fabs( prevdist ) <= fabs( nextdist ) )
                thislink->MergeNodes( B ); // remove A
            else
                thislink->MergeNodes( A ); // remove B

            kill = true;
            continue;
        }
        else if ( doprev )
        {
            thislink->MergeNodes( B ); // remove A
            kill = true;
            continue;
        }
        else if ( donext )
        {
            thislink->MergeNodes( A ); // remove B
            kill = true;
            continue;
        }


        thisline.Set( thislink );
        thisline.CalculateLineParameters();

        // Type 1
        if ( thisline.PointInLine( Z, distance, 0.0 ) == ON_AREA )
        { // Z--A--B =>  Z--B       Merge this to previous
            thislink->MergeNodes( B ); // remove A
            kill = true;
            continue;
        }
        else if ( thisline.PointInLine( C, distance, 0.0 ) == ON_AREA )
        { // A--B--C =>  A--C       Merge this to next
            thislink->MergeNodes( A ); // remove B
            kill = true;
            continue;
        }


        // Type 3
        if ( nextline.PointInLine( A, distance, ( double ) Marge ) == IN_AREA )
        {
            if ( nextline.Intersect2( cross_node, &prevline ) )
            {
                if ( nextline.PointInLine( cross_node, distance, 0.0 ) == IN_AREA )
                {
                    B->Set( cross_node );
                    thislink->MergeNodes( B ); // remove A
                    kill = true;
                    continue;
                }
                else
                {
                    thislink->MergeNodes( A ); // remove B
                    kill = true;
                    continue;
                }
            }
            else
            {
                thislink->MergeNodes( A ); // remove B
                kill = true;
                continue;
            }
        }

        // Type 3
        if ( prevline.PointInLine( B, distance, ( double )Marge ) == IN_AREA )
        {
            if ( prevline.Intersect2( cross_node, &nextline ) )
            {
                if ( prevline.PointInLine( cross_node, distance, 0.0 ) == IN_AREA )
                {
                    A->Set( cross_node );
                    thislink->MergeNodes( A ); // remove B
                    kill = true;
                    continue;
                }
                else
                {
                    thislink->MergeNodes( B ); // remove A
                    kill = true;
                    continue;
                }
            }
            else
            {
                thislink->MergeNodes( B ); // remove A
                kill = true;
                continue;
            }
        }

        todo--;
        _LI++;
    } // end: while all processed

    delete cross_node;

    return graph_is_modified;
}


// Give the graphnumber of the first link in the graphlist
int kbGraph::GetGraphNum()
{
    return ( ( kbLink* )_linklist->headitem() )->GetGraphNum();
}


// get the node with the highest Y value
kbNode* kbGraph::GetTopNode()
{
    B_INT max_Y = MAXB_INT;
    kbNode* result;

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );

    _LI.tohead();
    while ( !_LI.hitroot() )
    {
        if ( !( _LI.item()->GetBeginNode()->GetY() < max_Y ) )
            break;
        _LI++;
    }
    result = _LI.item()->GetBeginNode();

    return result;
}

// THE GRAPH MUST be SORTED before using this function
// mergesort(linkYXtopsorter);
// Get the mostleft top node from the graph  for which the link flag is not set yet
kbNode* kbGraph::GetMostTopLeft( TDLI<kbLink>* _LI )
{
    while ( !_LI->hitroot() )
    {
        if ( !_LI->item()->BeenHere() )
        {
            kbLink * a = _LI->item();
            //find the top node of this link (sorted on top allready)
            if ( a->GetBeginNode()->GetY() > a->GetEndNode()->GetY() )
                return( a->GetBeginNode() );
            if ( a->GetBeginNode()->GetY() < a->GetEndNode()->GetY() )
                return( a->GetEndNode() );
            else
                return( a->GetBeginNode() );
        }
        ( *_LI )++;
    }
    return NULL;
}

// Take the linkslist over from a other graph
// The linklist of the other graph will be empty afterwards
void kbGraph::TakeOver( kbGraph *other )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.takeover( other->_linklist );
}

// calculate crossing with scanbeams
bool kbGraph::CalculateCrossings( B_INT Marge )
{
    // POINT <==> POINT
    _GC->SetState( "Node to Node" );

    bool found = false;
    bool dummy = false;

    found = Merge_NodeToNode( Marge ) != 0;

    if ( _linklist->count() < 3 )
        return found;

    // POINT <==> LINK
    _GC->SetState( "Node to kbLink 0" );

    found = ScanGraph2( NODELINK, dummy ) != 0 || found;

    _GC->SetState( "Rotate -90" );
    Rotate( false );

    _GC->SetState( "Node to kbLink -90" );
    found = ScanGraph2( NODELINK, dummy ) != 0 || found;

    _GC->SetState( "Rotate +90" );
    Rotate( true );

    // LINK <==> LINK
    _GC->SetState( "intersect" );

    found = ScanGraph2( LINKLINK, dummy ) != 0 || found;

    /*
       if (!checksort())
       { {
        TDLI<kbLink> _LI=TDLI<kbLink>(_linklist);
      _LI.mergesort(linkXYsorter);
         }
       writeintersections();
       writegraph(true);
       }
    */

// Rotate(false);
// _GC->SetState("kbLink to kbLink -90");
//   ScanGraph2(LINKLINK);
// Rotate(true);

    writegraph( true );

    _GC->Write_Log( "Node to Node" );
    _GC->SetState( "Node to Node" );

    found = Merge_NodeToNode( Marge ) != 0 || found;
    writegraph( true );

    return found;
}

// neem de nodes die binnen de margeafstand bij elkaar liggen samen RICHARD
int kbGraph::Merge_NodeToNode( B_INT Marge )
{
    //aantal punten dat verplaatst is
    int merges = 0;
    {
        TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );

        //unmark all links; markflag wordt gebruikt om aan te geven
        //of een link (eigenlijk beginnode ervan) al verwerkt is
        _LI.foreach_mf( &kbLink::UnMark );

        //sort links on x value of beginnode
        _LI.mergesort( linkXYsorter );

        //extra iterator voor doorlopen links in graph
        {
            TDLI<kbLink>  links = TDLI<kbLink>( _linklist );

            kbNode *nodeOne, *nodeTwo;
            //verwerk alle links (alle (begin)nodes)
            for( _LI.tohead(); !_LI.hitroot(); _LI++ )
            {
                nodeOne = _LI.item()->GetBeginNode();

                // link (beginnode) al verwerkt?
                if( !_LI.item()->IsMarked() )
                {
                    // wordt verwerkt dus markeer
                    _LI.item()->Mark();

                    // doorloop alle links vanaf huidige tot link buiten marge
                    links.toiter( &_LI );links++;
                    while ( !links.hitroot() )
                    {
                        nodeTwo = links.item()->GetBeginNode();

                        // marked?
                        if( !links.item()->IsMarked() )
                        {
                            // x van beginnode vd link binnen marge?
                            if( babs( nodeOne->GetX() - nodeTwo->GetX() ) <= Marge )
                            {
                                // y van beginnode vd link binnen marge?
                                // zijn twee node-object referenties wel verschillend?
                                if( babs( nodeOne->GetY() - nodeTwo->GetY() ) <= Marge &&
                                        ( !( nodeOne == nodeTwo ) )
                                  )
                                {
                                    links.item()->Mark();
                                    nodeOne->Merge( nodeTwo );
                                    merges++;
                                }//y binnen marge en niet zelfde node
                            }//x binnen marge?
                            else
                            {
                                // link valt buiten marge; de rest vd links
                                // dus ook (omdat lijst gesorteerd is)
                                links.totail();
                            }
                        }//marked?
                        links++;
                    }//current -> ongeldig
                }//verwerkt?
            }//all links

        }//om de extra iterator te verwijderen
    }
    RemoveNullLinks();

    return merges;
}


int kbGraph::ScanGraph2( SCANTYPE scantype, bool& holes )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    int found = 0;

    //sort links on x and y value of beginnode
    _LI.mergesort( linkXYsorter );

    writegraph( false );

    //bin flag is used in scanbeam so reset
    _LI.foreach_mf( &kbLink::SetNotBeenHere );

    ScanBeam* scanbeam = new ScanBeam( _GC );
    kbNode*  _low;
    kbNode*  _high;

    _LI.tohead();
    while ( !_LI.attail() )
    {
        _low = _LI.item()->GetBeginNode();
        //find new links for the new beam and remove the old links
        if ( scanbeam->FindNew( scantype, &_LI, holes ) )
            found++;

        //find a new low node, this should be a node not eqaul to the current _low
        do
        {  _LI++;}
        while ( !_LI.hitroot() && ( _low == _LI.item()->GetBeginNode() ) );
        if ( _LI.hitroot() )
            //if the last few links share the same beginnode
            //we arive here
            break;
        else
            _high = _LI.item()->GetBeginNode();

        scanbeam->SetType( _low, _high );

        if ( scanbeam->RemoveOld( scantype, &_LI, holes ) )
            found++;
    }

    delete scanbeam;
    return found;
}


/*
 
//       scanbeam->writebeam();
 
      if (j%100 ==0)
      {
        long x;
        long y;
        char buf[80];
     x=(long)_lowlink->GetBeginNode()->GetX();
     y=(long)_lowlink->GetBeginNode()->GetY();
        sprintf(buf," x=%I64d , y=%I64d here %I64d",x,y,scanbeam->count());
   _GC->SetState(buf);
       scanbeam->writebeam();
      }
 
 
 
         writegraph(false);
            if (!checksort())
            {
               double x=_lowlink->GetBeginNode()->GetX();
               checksort();
            }
 
 
 
         _LI++;
      }
   }
 
 delete scanbeam;
 return 0;
}
 
 
         if (!checksort())
         {
            x=_lowlink->GetBeginNode()->GetX();
            checksort();
         }
 
         if (x >= -112200)
         {
//          writegraph(true);
//          scanbeam->writebeam();
         }
*/


//=============================== Global Functions =============================

// Sorts the links on the X values
int linkXYsorter( kbLink *a, kbLink* b )
{
    if ( a->GetBeginNode()->GetX() < b->GetBeginNode()->GetX() )
        return( 1 );
    if ( a->GetBeginNode()->GetX() > b->GetBeginNode()->GetX() )
        return( -1 );
    //they are eqaul in x
    if ( a->GetBeginNode()->GetY() < b->GetBeginNode()->GetY() )
        return( -1 );
    if ( a->GetBeginNode()->GetY() > b->GetBeginNode()->GetY() )
        return( 1 );
    //they are eqaul in y
    return( 0 );
}

// Sorts the links on the Y value of the beginnode
int linkYXsorter( kbLink *a, kbLink* b )
{
    if ( a->GetBeginNode()->GetY() > b->GetBeginNode()->GetY() )
        return( 1 );
    if ( a->GetBeginNode()->GetY() < b->GetBeginNode()->GetY() )
        return( -1 );
    if ( a->GetBeginNode()->GetX() > b->GetBeginNode()->GetX() )
        return( -1 );
    if ( a->GetBeginNode()->GetX() < b->GetBeginNode()->GetX() )
        return( 1 );
    return( 0 );
}


// The sort function for sorting graph from shortest to longest (_l1 < _l2)
int linkLsorter( kbLink *_l1, kbLink* _l2 )
{
    B_INT dx1, dx2, dy1, dy2;
    dx1 = ( _l1->GetEndNode()->GetX() - _l1->GetBeginNode()->GetX() );
    dx1 *= dx1;
    dy1 = ( _l1->GetEndNode()->GetY() - _l1->GetBeginNode()->GetY() );
    dy1 *= dy1;
    dx2 = ( _l2->GetEndNode()->GetX() - _l2->GetBeginNode()->GetX() );
    dx2 *= dx2;
    dy2 = ( _l2->GetEndNode()->GetY() - _l2->GetBeginNode()->GetY() );
    dy2 *= dy2;

    dx1 += dy1; dx2 += dy2;

    if ( dx1 > dx2 )
        return( -1 );
    if ( dx1 < dx2 )
        return( 1 );
    return( 0 );
}

// The sort function for the links in a graph (a.topnode < b.topnode)
// if the two links lay with the top nodes on eachother the most left will be selected

int linkYXtopsorter( kbLink *a, kbLink *b )
{

    if ( bmax( a->GetBeginNode()->GetY(), a->GetEndNode()->GetY() ) < bmax( b->GetBeginNode()->GetY(), b->GetEndNode()->GetY() ) )
        return -1;

    if ( bmax( a->GetBeginNode()->GetY(), a->GetEndNode()->GetY() ) > bmax( b->GetBeginNode()->GetY(), b->GetEndNode()->GetY() ) )
        return 1;

    //equal
    if ( bmin( a->GetBeginNode()->GetX(), a->GetEndNode()->GetX() ) < bmin( b->GetBeginNode()->GetX(), b->GetEndNode()->GetX() ) )
        return -1;

    if ( bmin( a->GetBeginNode()->GetX(), a->GetEndNode()->GetX() ) > bmin( b->GetBeginNode()->GetX(), b->GetEndNode()->GetX() ) )
        return 1;

    return 0;
}

// The sort function for sorting graph from shortest to longest (_l1 < _l2)
int linkGraphNumsorter( kbLink *_l1, kbLink* _l2 )
{
    if ( _l1->GetGraphNum() > _l2->GetGraphNum() )
        return( -1 );
    if ( _l1->GetGraphNum() < _l2->GetGraphNum() )
        return( 1 );
    return( 0 );
}

// Perform an operation on the graph
void kbGraph::Boolean( BOOL_OP operation, kbGraphList* Result )
{
    _GC->SetState( "Performing Operation" );

    // At this moment we have one graph
    // step one, split it up in single graphs, and mark the holes
    // step two, make one graph again and link the holes
    // step three, split up again and dump the result in Result

    _GC->SetState( "Extract simples first " );

    ResetBinMark();
    DeleteNonCond( operation );
    HandleNonCond( operation );

    bool foundholes = false;
    try
    {
        WriteGraphKEY( _GC );
        writegraph( true );

        Extract_Simples( operation, true, foundholes );
    }
    catch ( Bool_Engine_Error & error )
    {
        throw error;
    }

    // now we will link all the holes in de graphlist
    // By the scanbeam method we will search all the links that are marked
    // as topleft link of a the hole polygon, when we find them we will get the
    // closest link, being the one higher in the beam.
    // Next we will create a link and nodes toceoonect the hole into it outside contour
    // or other hole.
    _GC->SetState( "Linking Holes" );

    if ( _linklist->count() == 0 )
        //extract simples did leaf an empty graph
        //so we are ready
        return;

    if ( foundholes && _GC->GetLinkHoles() )
    {
        //the first extract simples introduced nodes at the same location that are not merged.
        //e.g. Butterfly polygons as two seperate polygons.
        //The scanlines can not cope with this, so merge them, and later extract one more time.
        Merge_NodeToNode( 0 );

#if KBOOL_LOG == 1
        //_GC->SetLog( true ); 
        _GC->Write_Log( "LINKHOLES\n" );
#endif
        writegraph( false );

        //link the holes into the non holes if there are any.
        bool holes = false;
        ScanGraph2( LINKHOLES, holes );

        WriteGraphKEY( _GC );
        writegraph( true );
        if ( holes )
        {
            //to delete extra points
            //those extra points are caused by link holes
            //and are eqaul ( the smallest number in integer is 1 )
            DeleteZeroLines( 1 );

            _GC->SetState( "extract simples last" );
            ResetBinMark();
            HandleNonCond( operation );
            DeleteNonCond( operation );
            Extract_Simples( operation, false, foundholes );
        }
    }

    //writegraph( false );
    Split( Result );
}

// Perform an correction on the graph
void kbGraph::Correction( kbGraphList* Result, double factor )
{
    // At this moment we have one graph
    // step one, split it up in single graphs, and mark the holes
    // step two, make one graph again and link the holes
    // step three, split up again and dump the result in Result
    _GC->SetState( "Extract simple graphs" );

    //extract the (MERGE or OR) result from the graph
    if ( Simplify( _GC->GetGrid() ) )
        if ( GetNumberOfLinks() < 3 )
            return;

    kbGraph* original = new kbGraph( _GC );

    {
        if ( _linklist->empty() ) return;

        kbLink* _current = GetFirstLink();
        kbNode *_first = new kbNode( _current->GetBeginNode(), _GC );
        kbNode *_last  = _current->GetBeginNode();
        kbNode *_begin = _first;
        kbNode *_end   = _first;

        int _nr_of_points = GetNumberOfLinks();
        for ( int i = 1; i < _nr_of_points; i++ )
        {
            // get the other node on the link
            _last = _current->GetOther( _last );
            // make a node from this point
            _end = new kbNode( _last, _GC );

            // make a link between begin and end
            original->AddLink( _begin, _end );

            _begin = _end;
            _current = _current->Forth( _last );
        }

        // make a link between the _begin and the first to close the graph
        original->AddLink( _begin, _first );
    }

    SetNumber( 1 );
    SetGroup( GROUP_A );
    Prepare( 1 );
    ResetBinMark();
    //DeleteNonCond(BOOL_OR);
    HandleNonCond( BOOL_OR );

    bool foundholes = false;
    Extract_Simples( BOOL_OR, true, foundholes );
    Split( Result );

    //Result contains the separate boundaries and holes

    //ring creation should never be alternate rule, since it overlaps.
    //So temprarely modify it.
    bool rule = _GC->GetWindingRule();
    _GC->SetWindingRule( true );

    _GC->SetState( "Create rings" );
    //first create a ring around all simple graphs
    {
        TDLI<kbGraph> IResult = TDLI<kbGraph>( Result );
        kbGraphList *_ring = new kbGraphList( _GC );
        {
            //put into one graphlist
            IResult.tohead();
            int i;
            int n = IResult.count();
            for ( i = 0;i < n;i++ )
            {
                {
                    IResult.item()->MakeClockWise();
                    IResult.item()->CreateRing_fast( _ring, fabs( factor ) );
                    //     IResult.item()->CreateRing(_ring,fabs(factor));
                }
                delete( IResult.item() );
                IResult.remove();

                //move ring graphlist to result
                while ( !_ring->empty() )
                {
                    //add to end
                    ( ( kbGraph* )_ring->headitem() )->MakeClockWise();
                    IResult.insend( ( kbGraph* )_ring->headitem() );
                    _ring->removehead();
                }
            }
        }
        delete _ring;

        //IResult contains all rings
        //prepare the graphs for extracting the links of a certain operation
        //set original graphlist to groupA and ring to groupB
        int i = 2;
        IResult.tohead();
        while ( !IResult.hitroot() )
        {
            IResult.item()->Reset_flags();
            IResult.item()->SetGroup( GROUP_B );
            IResult.item()->SetNumber( i );
            i++;
            IResult++;
        }
    }

    //a ring shape can overlap itself, for alternate filling this is problem.
    //doing a merge in winding rule makes this oke, since overlap is removed by it.
    if ( !rule ) //alternate rule?
    {
        Prepare( 1 );
        Boolean( BOOL_OR, Result );

        TDLI<kbGraph> IResult = TDLI<kbGraph>( Result );
        //IResult contains all rings
        //prepare the graphs for extracting the links of a certain operation
        //set original graphlist to groupA and ring to groupB
        int i = 2;
        IResult.tohead();
        while ( !IResult.hitroot() )
        {
            IResult.item()->Reset_flags();
            IResult.item()->SetGroup( GROUP_B );
            IResult.item()->SetNumber( i );
            i++;
            IResult++;
        }
    }

    //restore filling rule
    _GC->SetWindingRule( rule );

    TakeOver( original );
    Reset_flags();
    SetNumber( 1 );
    SetGroup( GROUP_A );
    Result->MakeOneGraph( this ); // adds all graph its links to original
    // Result will be empty afterwords


    //merge ring with original shapes for positive correction else subtract ring

    //calculate intersections etc.
    //SINCE correction will calculate intersections between
    //ring and original _GC->Get_Marge() must be set a lot smaller then factor
    //during the rest of this routine
    //else wierd effects will be the result.
    double Backup_Marge = _GC->GetMarge();

    if ( _GC->GetInternalMarge() > fabs( factor / 100 ) )
    {
        _GC->SetInternalMarge( ( B_INT ) fabs( factor / 100 ) );
        //less then 1 is usless since all coordinates are integers
        if ( _GC->GetInternalMarge() < 1 )
            _GC->SetInternalMarge( 1 );
    }


    Prepare( 1 );

    _GC->SetState( "Add/Substract rings" );

    if ( factor > 0 )
        Boolean( BOOL_OR, Result );
    else
        Boolean( BOOL_A_SUB_B, Result );

    _GC->SetMarge( Backup_Marge );

    //the result of the graph correction is in Result
    delete original;
}

// Perform an operation on the graph
void kbGraph::MakeRing( kbGraphList* Result, double factor )
{

    bool rule = _GC->GetWindingRule();
    _GC->SetWindingRule( true );

    // At this moment we have one graph
    // step one, split it up in single graphs, and mark the holes
    // step two, make one graph again and link the holes
    // step three, split up again and dump the result in Result
    _GC->SetState( "Extract simple graphs" );

    //extract the (MERGE or OR) result from the graph
    SetNumber( 1 );
    Prepare( 1 );

    ResetBinMark();
    //DeleteNonCond(BOOL_OR);
    HandleNonCond( BOOL_OR );

    bool foundholes = false;
    Extract_Simples( BOOL_OR, true, foundholes );
    Split( Result );
    //Iresult contains the separate boundaries and holes
    //make a correction on the boundaries factor
    //make a correction on the holes -factor

    _GC->SetState( "Create rings" );

    //first create a ring around all simple graphs
    TDLI<kbGraph> IResult = TDLI<kbGraph>( Result );
    kbGraphList *_ring = new kbGraphList( _GC );
    {
        IResult.tohead();
        int i;
        int n = IResult.count();
        for ( i = 0;i < n;i++ )
        {
            {
                IResult.item()->MakeClockWise();
                IResult.item()->CreateRing_fast( _ring, fabs( factor ) );
            }
            delete( IResult.item() );
            IResult.remove();

            //move ring graphlist to result
            while ( !_ring->empty() )
            {
                //add to end
                ( ( kbGraph* )_ring->headitem() )->MakeClockWise();
                IResult.insend( ( kbGraph* )_ring->headitem() );
                _ring->removehead();
            }
        }
    }
    delete _ring;
    _GC->SetWindingRule( rule );
}

//create a ring shapes on every edge of the graph
void kbGraph::CreateRing( kbGraphList *ring, double factor )
{
    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    while( !_LI.hitroot() )
    {
        kbGraph * shape = new kbGraph( _GC );
        //generate shape around link
        shape->Make_Rounded_Shape( _LI.item(), factor );
        ring->insbegin( shape );
        _LI++;
    }
}

//create a ring shapes on every edge of the graph
void kbGraph::CreateRing_fast( kbGraphList *ring, double factor )
{
    kbNode * begin;
    kbLink* currentlink;
    kbLine  currentline( _GC );

    kbLine  firstline( _GC );

    kbLink* nextlink;
    kbLine nextline( _GC );

    {
        TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
        _LI.foreach_mf( &kbLink::UnMark );//reset bin and mark flag of each link
        _LI.mergesort( linkYXsorter );
        _LI.tohead();

        begin = GetMostTopLeft( &_LI ); // from all the most Top nodes,
        // take the most left one
    }
    if ( !begin )
        return;

    currentlink = begin->GetIncomingLink();
    currentline.Set( currentlink );
    currentline.CalculateLineParameters();

    nextlink = begin->GetOutgoingLink();
    nextline.Set( nextlink );
    nextline.CalculateLineParameters();

    firstline.Set( nextlink );
    firstline.CalculateLineParameters();

    while ( nextlink )
    {
        kbGraph * shape = new kbGraph( _GC );
        {

            kbNode* _last_ins_left  = 0;
            kbNode* _last_ins_right = 0;

            currentline.Create_Begin_Shape( &nextline, &_last_ins_left, &_last_ins_right, factor, shape );

            while( true )
            {
                currentline = nextline;
                currentlink = nextlink;
                currentlink->SetBeenHere();

                nextlink = currentlink->GetEndNode()->Follow( currentlink );
                if ( nextlink )
                {
                    nextline.Set( nextlink );
                    nextline.CalculateLineParameters();
                    if ( !currentline.Create_Ring_Shape( &nextline, &_last_ins_left, &_last_ins_right, factor, shape ) )
                        break;
                }
                else
                    break;
            }

            //finish this part
            if ( nextlink )
                currentline.Create_End_Shape( &nextline, _last_ins_left, _last_ins_right, factor, shape );
            else
                currentline.Create_End_Shape( &firstline, _last_ins_left, _last_ins_right, factor, shape );

            shape->MakeOneDirection();
            shape->MakeClockWise();
        }

        //if the shape is very small first merge it with the previous shape
        if ( !ring->empty() && shape->Small( ( B_INT ) fabs( factor * 3 ) ) )
        {
            TDLI<kbGraph> Iring = TDLI<kbGraph>( ring );

            Iring.totail();

            kbGraphList *_twoshapes = new kbGraphList( _GC );
            _twoshapes->insbegin( shape );
            _twoshapes->insbegin( Iring.item() );
            Iring.remove();
            _twoshapes->Merge();

            //move merged graphlist to ring
            Iring.takeover( _twoshapes );
            delete _twoshapes;
        }
        else
            ring->insend( shape );

        currentlink->SetBeenHere();
    }
}

//create an arc and add it to the graph
//center of circle
//begin point of arc
//end point of arc
//radius of arc
//aberation for generating the segments
void kbGraph::CreateArc( kbNode* center, kbNode* begin, kbNode* end, double radius, bool clock, double aber )
{
    double phi, dphi, dx, dy;
    int Segments;
    int i;
    double ang1, ang2, phit;

    kbNode* _last_ins;
    kbNode* _current;

    _last_ins = begin;

    dx = ( double ) _last_ins->GetX() - center->GetX();
    dy = ( double ) _last_ins->GetY() - center->GetY();
    ang1 = atan2( dy, dx );
    if ( ang1 < 0 ) ang1 += 2.0 * M_PI;
    dx = ( double ) end->GetX() - center->GetX();
    dy = ( double ) end->GetY() - center->GetY();
    ang2 = atan2( dy, dx );
    if ( ang2 < 0 ) ang2 += 2.0 * M_PI;

    if ( clock )
    { //clockwise
        if ( ang2 > ang1 )
            phit = 2.0 * M_PI - ang2 + ang1;
        else
            phit = ang1 - ang2;
    }
    else
    { //counter_clockwise
        if ( ang1 > ang2 )
            phit = -( 2.0 * M_PI - ang1 + ang2 );
        else
            phit = -( ang2 - ang1 );
    }

    //what is the delta phi to get an accurancy of aber
    dphi = 2 * acos( ( radius - aber ) / radius );

    //set the number of segments
    if ( phit > 0 )
        Segments = ( int )ceil( phit / dphi );
    else
        Segments = ( int )ceil( -phit / dphi );

    if ( Segments <= 1 )
        Segments = 1;
    if ( Segments > 6 )
        Segments = 6;

    dphi = phit / ( Segments );

    for ( i = 1; i < Segments; i++ )
    {
        dx = ( double ) _last_ins->GetX() - center->GetX();
        dy = ( double ) _last_ins->GetY() - center->GetY();
        phi = atan2( dy, dx );

        _current = new kbNode( ( B_INT ) ( center->GetX() + radius * cos( phi - dphi ) ),
                             ( B_INT ) ( center->GetY() + radius * sin( phi - dphi ) ), _GC );
        AddLink( _last_ins, _current );

        _last_ins = _current;
    }

    // make a node from the endnode of link
    AddLink( _last_ins, end );
}

void kbGraph::CreateArc( kbNode* center, kbLine* incoming, kbNode* end, double radius, double aber )
{
    double distance = 0;
    if ( incoming->PointOnLine( center, distance, _GC->GetAccur() ) == RIGHT_SIDE )
        CreateArc( center, incoming->GetEndNode(), end, radius, true, aber );
    else
        CreateArc( center, incoming->GetEndNode(), end, radius, false, aber );
}

void kbGraph::MakeOneDirection()
{
    int _nr_of_points = _linklist->count();
    kbLink* _current = ( kbLink* )_linklist->headitem();

    kbNode* _last = _current->GetBeginNode();
    kbNode* dummy;

    for ( int i = 0; i < _nr_of_points; i++ )
    {
        // get the other node on the link
        _last = _current->GetOther( _last );
        // get the other link on the node
        _current = _current->Forth( _last );

        if ( _current->GetBeginNode() != _last )
        {
            // swap the begin- and endnode of the current link
            dummy = _current->GetBeginNode();
            _current->SetBeginNode( _current->GetEndNode() );
            _current->SetEndNode( dummy );
        }
    }
}

bool kbGraph::Small( B_INT howsmall )
{

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    _LI.tohead();
    kbNode* bg = _LI.item()->GetBeginNode();
    B_INT xmin = bg->GetX();
    B_INT xmax = bg->GetX();
    B_INT ymin = bg->GetY();
    B_INT ymax = bg ->GetY();
    while ( !_LI.hitroot() )
    {
        bg = _LI.item()->GetBeginNode();
        // make _boundingbox bigger if the link makes the graph bigger
        // Checking if point is in bounding-box with marge
        xmin = bmin( xmin, bg->GetX() );
        xmax = bmax( xmax, bg->GetX() );
        ymin = bmin( ymin, bg->GetY() );
        ymax = bmax( ymax, bg->GetY() );
        _LI++;
    }

    B_INT dx = ( xmax - xmin );
    B_INT dy = ( ymax - ymin );

    if ( ( dx < howsmall ) && ( dy < howsmall ) )
        return true;

    return false;
}


//create a circle at end and begin point
// and block in between
void kbGraph::Make_Rounded_Shape( kbLink* a_link, double factor )
{
    double phi, dphi, dx, dy;
    int Segments = 6;
    int i;


    kbLine theline( a_link, _GC );
    theline.CalculateLineParameters();

    kbNode* _current;
    kbNode *_first = new kbNode( a_link->GetBeginNode(), _GC );
    kbNode *_last_ins = _first;

    theline.Virtual_Point( _first, factor );

    // make a node from this point
    _current = new kbNode( a_link->GetEndNode(), _GC );
    theline.Virtual_Point( _current, factor );

    // make a link between the current and the previous and add this to graph
    AddLink( _last_ins, _current );
    _last_ins = _current;

    // make a half circle around the clock with the opposite point as
    // the middle point of the circle
    dphi = M_PI / ( Segments );
    for ( i = 1; i < Segments; i++ )
    {
        dx = ( double ) _last_ins->GetX() - a_link->GetEndNode()->GetX();
        dy = ( double ) _last_ins->GetY() - a_link->GetEndNode()->GetY();
        phi = atan2( dy, dx );

        _current = new kbNode( ( B_INT ) ( a_link->GetEndNode()->GetX() + factor * cos( phi - dphi ) ),
                             ( B_INT ) ( a_link->GetEndNode()->GetY() + factor * sin( phi - dphi ) ), _GC );

        AddLink( _last_ins, _current );

        _last_ins = _current;
    }

    // make a node from the endnode of link
    _current = new kbNode( a_link->GetEndNode(), _GC );
    theline.Virtual_Point( _current, -factor );
    AddLink( _last_ins, _current );
    _last_ins = _current;

    // make a node from this beginnode of link
    _current = new kbNode( a_link->GetBeginNode(), _GC );
    theline.Virtual_Point( _current, -factor );
    AddLink( _last_ins, _current );
    _last_ins = _current;

    for ( i = 1; i < Segments; i++ )
    {
        dx = ( double ) _last_ins->GetX() - a_link->GetBeginNode()->GetX();
        dy = ( double ) _last_ins->GetY() - a_link->GetBeginNode()->GetY();
        phi = atan2( dy, dx );

        _current = new kbNode( ( B_INT )( a_link->GetBeginNode()->GetX() + factor * cos( phi - dphi ) ),
                             ( B_INT )( a_link->GetBeginNode()->GetY() + factor * sin( phi - dphi ) ), _GC );

        AddLink( _last_ins, _current );

        _last_ins = _current;
    }

    // make a link between the last and the first to close the graph
    AddLink( _last_ins, _first );
}

//make the graph clockwise orientation,
//return if the graph needed redirection
bool kbGraph::MakeClockWise()
{
    if ( _GC->GetOrientationEntryMode() )
        return false;

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    if ( _LI.empty() ) return false;

    kbLink *currentlink;
    kbNode *begin;

    _LI.foreach_mf( &kbLink::UnMark );//reset bin and mark flag of each link
    _LI.mergesort( linkYXtopsorter );
    _LI.tohead();

    begin = GetMostTopLeft( &_LI ); // from all the most Top nodes,
    // take the most left one

    currentlink = begin->GetNotFlat();
    if ( !currentlink )
    {
        char buf[100];
        sprintf( buf, "no NON flat link MakeClockWise at %15.3lf , %15.3lf",
                 double( begin->GetX() ), double( begin->GetY() ) );
        throw Bool_Engine_Error( buf, "Error", 9, 0 );
    }

    //test to see if the orientation is right or left
    if ( currentlink->GetBeginNode() == begin )
    {
        if ( currentlink->GetEndNode()->GetX() < begin->GetX() )
        {
            //going left
            //it needs redirection
            ReverseAllLinks();
            return true;
        }
    }
    else
    {
        if ( currentlink->GetBeginNode()->GetX() > begin->GetX() )
        {  //going left
            //it needs redirection
            ReverseAllLinks();
            return true;
        }
    }
    return false;
}

bool kbGraph::writegraph( bool linked )
{
#if KBOOL_DEBUG == 1

    FILE * file = _GC->GetLogFile();

    if ( file == NULL )
        return true;

    fprintf( file, "# graph\n" );

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    if ( _LI.empty() )
    {
        return true;
    }

    _LI.tohead();
    while( !_LI.hitroot() )
    {
        kbLink * curl = _LI.item();

        fprintf( file, " linkbegin %I64d %I64d \n", curl->GetBeginNode()->GetX() , curl->GetBeginNode()->GetY() );

        if ( linked )
        {
            TDLI<kbLink> Inode( curl->GetBeginNode()->GetLinklist() );
            Inode.tohead();
            while( !Inode.hitroot() )
            {

                fprintf( file, " b %I64d %I64d \n", Inode.item()->GetBeginNode()->GetX() , Inode.item()->GetBeginNode()->GetY() );

                fprintf( file, " e %I64d %I64d \n", Inode.item()->GetEndNode()->GetX() , Inode.item()->GetEndNode()->GetY() );

                Inode++;
            }
        }
        fprintf( file, " linkend %I64d %I64d \n", curl->GetEndNode()->GetX() , curl->GetEndNode()->GetY() );


        if ( linked )
        {
            TDLI<kbLink> Inode( curl->GetEndNode()->GetLinklist() );
            Inode.tohead();
            while( !Inode.hitroot() )
            {

                fprintf( file, " b %I64d %I64d \n", Inode.item()->GetBeginNode()->GetX() , Inode.item()->GetBeginNode()->GetY() );

                fprintf( file, " e %I64d %I64d \n", Inode.item()->GetEndNode()->GetX() , Inode.item()->GetEndNode()->GetY() );

                Inode++;
            }

        }

        if ( curl->GetBeginNode() == curl->GetEndNode() )
            fprintf( file, "     null_link \n" );

        fprintf( file, "    group %d ", curl->Group() );
        fprintf( file, "    bin   %d ", curl->BeenHere() );
        fprintf( file, "    mark  %d ", curl->IsMarked() );
        fprintf( file, "    leftA %d ", curl->GetLeftA() );
        fprintf( file, "    rightA %d ", curl->GetRightA() );
        fprintf( file, "    leftB %d ", curl->GetLeftB() );
        fprintf( file, "    rightB %d \n", curl->GetRightB() );
        fprintf( file, "    or %d ", curl->IsMarked( BOOL_OR ) );
        fprintf( file, "    and %d " , curl->IsMarked( BOOL_AND ) );
        fprintf( file, "    exor %d " , curl->IsMarked( BOOL_EXOR ) );
        fprintf( file, "    a_sub_b %d " , curl->IsMarked( BOOL_A_SUB_B ) );
        fprintf( file, "    b_sub_a %d " , curl->IsMarked( BOOL_B_SUB_A ) );
        fprintf( file, "    hole %d " , curl->GetHole() );
        fprintf( file, "    top_hole %d \n" , curl->IsTopHole() );

        _LI++;
    }

#endif

    return true;
}

bool kbGraph::writeintersections()
{

#if KBOOL_DEBUG == 1

    FILE * file = _GC->GetLogFile();

    if ( file == NULL )
        return true;

    fprintf( file, "# graph\n" );

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    if ( _LI.empty() )
    {
        return true;
    }

    _LI.tohead();
    while( !_LI.hitroot() )
    {
        kbLink * curl = _LI.item();
        TDLI<kbLink> Inode( curl->GetBeginNode()->GetLinklist() );
        Inode.tohead();
        if ( Inode.count() > 2 )
        {
            fprintf( file, " count %I64d", Inode.count() );
            fprintf( file, " b %I64d %I64d \n\n", curl->GetBeginNode()->GetX() , curl->GetBeginNode()->GetY() );
        }
        _LI++;
    }
#endif

    return true;
}

bool kbGraph::checksort()
{
    // if empty then just insert
    if ( _linklist->empty() )
        return true;

    TDLI<kbLink> _LI = TDLI<kbLink>( _linklist );
    // put new item left of the one that is bigger
    _LI.tohead();
    kbLink* prev = _LI.item();
    kbLink* cur = _LI.item();
    _LI++;
    while( !_LI.hitroot() )
    {
        kbLink * aap = _LI.item();
        if ( linkXYsorter( prev, _LI.item() ) == -1 )
        {
            cur = aap;

            return false;
        }
        prev = _LI.item();
        _LI++;
    }
    return true;
}


void kbGraph::WriteKEY( Bool_Engine* GC, FILE* file )
{
    double scale = 1.0 / GC->GetGrid() / GC->GetGrid();

    bool ownfile = false;
    if ( !file )
    {
        file = fopen( "keyfile.key", "w" );
        ownfile = true;

        fprintf( file, "\
                 HEADER 5; \
                 BGNLIB; \
                 LASTMOD {2-11-15  15:39:21}; \
                 LASTACC {2-11-15  15:39:21}; \
                 LIBNAME trial; \
                 UNITS; \
                 USERUNITS 0.0001; PHYSUNITS 1e-009; \
                 \
                 BGNSTR;  \
                 CREATION {2-11-15  15:39:21}; \
                 LASTMOD  {2-11-15  15:39:21}; \
                 STRNAME top; \
                 ");
    }

    TDLI<kbLink> _LI=TDLI<kbLink>(_linklist);
    if (_LI.empty())
    {
        if ( ownfile )
        {
            fprintf(file,"\
                    ENDSTR top; \
                    ENDLIB; \
                    ");
            fclose (file);

        }
        return;
    }


    _LI.tohead();
    kbLink* curl = _LI.item();

    if ( _LI.item()->Group() == GROUP_A )
        fprintf(file,"BOUNDARY; LAYER 0;  DATATYPE 0;\n");
    else
        fprintf(file,"BOUNDARY; LAYER 1;  DATATYPE 0;\n");
    fprintf(file," XY % d; \n", _LI.count()+1 );

    double firstx = curl->GetBeginNode()->GetX()*scale;
    double firsty = curl->GetBeginNode()->GetY()*scale;
    fprintf(file,"X % f;\t", firstx);
    fprintf(file,"Y % f; \n", firsty);
    _LI++;

    while(!_LI.hitroot())
    {
        kbLink* curl = _LI.item();

        fprintf(file,"X % f;\t", curl->GetBeginNode()->GetX()*scale);
        fprintf(file,"Y % f; \n", curl->GetBeginNode()->GetY()*scale);

        _LI++;
    }
    fprintf(file,"X % f;\t", firstx);
    fprintf(file,"Y % f; \n", firsty);
    fprintf(file,"ENDEL;\n");

    if ( ownfile )
    {
        fprintf(file,"\
                ENDSTR top; \
                ENDLIB; \
                ");
        fclose (file);

    }
}


void kbGraph::WriteGraphKEY(Bool_Engine* GC)
{
#if KBOOL_DEBUG

    double scale = 1.0/GC->GetGrid()/GC->GetGrid();

    FILE* file = fopen("keygraphfile.key", "w");

    fprintf(file,"\
            HEADER 5; \
            BGNLIB; \
            LASTMOD {2 - 11 - 15  15: 39: 21}; \
            LASTACC {2 - 11 - 15  15: 39: 21}; \
            LIBNAME trial; \
            UNITS; \
            USERUNITS 1; PHYSUNITS 1e-006; \
            \
            BGNSTR;  \
            CREATION {2 - 11 - 15  15: 39: 21}; \
            LASTMOD  {2 - 11 - 15  15: 39: 21}; \
            STRNAME top; \
            ");


    TDLI<kbLink> _LI=TDLI<kbLink>(_linklist);
    if (_LI.empty())
    {
        fprintf(file,"\
                ENDSTR top; \
                ENDLIB; \
                ");
        fclose (file);
        return;
    }

    _LI.tohead();
    kbLink* curl;

    int _nr_of_points = _linklist->count();
    for (int i = 0; i < _nr_of_points; i++)
    {
        curl = _LI.item();

        if ( curl->Group() == GROUP_A )
            fprintf(file,"PATH; LAYER 0;\n");
        else
            fprintf(file,"PATH; LAYER 1;\n");

        fprintf(file," XY % d; \n", 2 );
        fprintf(file,"X % f;\t", curl->GetBeginNode()->GetX()*scale);
        fprintf(file,"Y % f; \n", curl->GetBeginNode()->GetY()*scale);
        fprintf(file,"X % f;\t", curl->GetEndNode()->GetX()*scale);
        fprintf(file,"Y % f; \n", curl->GetEndNode()->GetY()*scale);
        _LI++;
        fprintf(file,"ENDEL;\n");
    }

    fprintf(file,"\
            ENDSTR top; \
            ENDLIB; \
            ");

    fclose (file);
#endif
}




