/*! \file src/booleng.cpp \author Klaas Holwerda Copyright: 2001-2004 (C) Klaas Holwerda Licence: see kboollicense.txt RCS-ID: $Id: booleng.cpp,v 1.7 2009/09/14 16:50:12 titato Exp $ */ #include "kbool/booleng.h" #include <time.h> #include "kbool/link.h" #include "kbool/line.h" #include "kbool/node.h" #include "kbool/graph.h" #include "kbool/graphlst.h" B_INT bmin( B_INT const value1, B_INT const value2 ) { return( ( value1 < value2 ) ? value1 : value2 ); } B_INT bmax( B_INT const value1, B_INT const value2 ) { return( ( value1 > value2 ) ? value1 : value2 ); } B_INT babs( B_INT a ) { if ( a < 0 ) a = -a; return a; } //-------------------------------------------------------------------/ //----------------- Bool_Engine_Error -------------------------------/ //-------------------------------------------------------------------/ Bool_Engine_Error::Bool_Engine_Error( string message, string header, int degree, int fatal ) { _message = message; _header = header; _degree = degree; _fatal = fatal; } Bool_Engine_Error::Bool_Engine_Error( const Bool_Engine_Error& a ) { _message = a._message; _header = a._header; _degree = a._degree; _fatal = a._fatal; } Bool_Engine_Error::~Bool_Engine_Error() { _message = ""; _header = ""; } string Bool_Engine_Error::GetErrorMessage() { return _message; } string Bool_Engine_Error::GetHeaderMessage() { return _header; } int Bool_Engine_Error::GetErrorDegree() { return _degree; } int Bool_Engine_Error::GetFatal() { return _fatal; } //-------------------------------------------------------------------/ //----------------- Bool_Engine -------------------------------------/ //-------------------------------------------------------------------/ Bool_Engine::Bool_Engine() { _linkiter = new TDLI<kbLink>(); m_intersectionruns = 1; m_orientationEntryMode = false; m_doLinkHoles = true; m_allowNonTopHoleLinking = true; m_graphlist = new kbGraphList( this ); m_ACCUR = 1e-4; m_WINDINGRULE = true; m_GraphToAdd = NULL; m_firstNodeToAdd = NULL; m_lastNodeToAdd = NULL; m_logfile = NULL; #if KBOOL_LOG == 1 SetLog( true ); #else SetLog( false ); #endif } Bool_Engine::~Bool_Engine() { if ( m_logfile != NULL ) fclose ( m_logfile ); delete _linkiter; delete m_graphlist; } void Bool_Engine::SetLog( bool OnOff ) { m_doLog = OnOff; if ( m_doLog ) { if ( m_logfile == NULL ) { // create a new logfile m_logfile = fopen( KBOOL_LOGFILE, "w" ); if ( m_logfile == NULL ) fprintf( stderr, "Bool_Engine: Unable to write to Boolean Engine logfile\n" ); else { time_t timer; struct tm * today; timer = time( NULL ); today = localtime( &timer ); fprintf( m_logfile, "Logfile created on:\t\t\t%s", ctime( &timer ) ); } } } else { if ( m_logfile != NULL ) { fclose ( m_logfile ); m_logfile = NULL; } } } void Bool_Engine::SetState( string process ) { Write_Log( process ); } void Bool_Engine::error( string text, string title ) { Write_Log( "FATAL ERROR: ", title ); Write_Log( "FATAL ERROR: ", text ); throw Bool_Engine_Error( " Fatal Error", "Fatal Error", 9, 1 ); } void Bool_Engine::info( string text, string title ) { Write_Log( "FATAL ERROR: ", title ); Write_Log( "FATAL ERROR: ", text ); } void Bool_Engine::SetMarge( double marge ) { m_MARGE = marge; Write_Log( "Bool_Engine::m_MARGE = %f\n", m_MARGE ); } double Bool_Engine::GetAccur() { return m_ACCUR; } void Bool_Engine::SetRoundfactor( double roundfac ) { m_ROUNDFACTOR = roundfac; Write_Log( "Bool_Engine::m_ROUNDFACTOR = %f\n", m_ROUNDFACTOR ); } double Bool_Engine::GetRoundfactor() { return m_ROUNDFACTOR; } double Bool_Engine::GetMarge() { return m_MARGE; } void Bool_Engine::SetDGrid( double dgrid ) { m_DGRID = dgrid; Write_Log( "Bool_Engine::m_DGRID = %f\n", m_DGRID ); } double Bool_Engine::GetDGrid() { return m_DGRID; } void Bool_Engine::SetGrid( B_INT grid ) { m_GRID = grid; Write_Log( "Bool_Engine::m_GRID = %lld\n", m_GRID ); } B_INT Bool_Engine::GetGrid() { return m_GRID; } void Bool_Engine::SetCorrectionAber( double aber ) { m_CORRECTIONABER = aber; Write_Log( "Bool_Engine::m_CORRECTIONABER = %f\n", m_CORRECTIONABER ); } double Bool_Engine::GetCorrectionAber() { return m_CORRECTIONABER; } void Bool_Engine::SetCorrectionFactor( double aber ) { m_CORRECTIONFACTOR = aber; Write_Log( "Bool_Engine::m_CORRECTIONFACTOR = %f\n", m_CORRECTIONFACTOR ); } double Bool_Engine::GetCorrectionFactor() { return m_CORRECTIONFACTOR; } void Bool_Engine::SetSmoothAber( double aber ) { m_SMOOTHABER = aber; Write_Log( "Bool_Engine::m_SMOOTHABER = %f\n", m_SMOOTHABER ); } double Bool_Engine::GetSmoothAber() { return m_SMOOTHABER; } void Bool_Engine::SetMaxlinemerge( double maxline ) { m_MAXLINEMERGE = maxline; Write_Log( "Bool_Engine::m_MAXLINEMERGE = %f\n", m_MAXLINEMERGE ); } double Bool_Engine::GetMaxlinemerge() { return m_MAXLINEMERGE; } void Bool_Engine::SetWindingRule( bool rule ) { m_WINDINGRULE = rule; } bool Bool_Engine::GetWindingRule() { return m_WINDINGRULE; } void Bool_Engine::SetInternalMarge( B_INT marge ) { m_MARGE = ( double )marge / m_GRID / m_DGRID; } B_INT Bool_Engine::GetInternalMarge() { return ( B_INT ) ( m_MARGE * m_GRID * m_DGRID ); } double Bool_Engine::GetInternalCorrectionAber() { return m_CORRECTIONABER * m_GRID * m_DGRID; } double Bool_Engine::GetInternalCorrectionFactor() { return m_CORRECTIONFACTOR * m_GRID * m_DGRID; } double Bool_Engine::GetInternalSmoothAber() { return m_SMOOTHABER * m_GRID * m_DGRID; } B_INT Bool_Engine::GetInternalMaxlinemerge() { return ( B_INT ) ( m_MAXLINEMERGE * m_GRID * m_DGRID ); } #define TRIALS 30 bool Bool_Engine::Do_Operation( BOOL_OP operation ) { #if KBOOL_DEBUG kbGraphList * saveme = new kbGraphList( m_graphlist ); #endif try { switch ( operation ) { case ( BOOL_OR ): case ( BOOL_AND ): case ( BOOL_EXOR ): case ( BOOL_A_SUB_B ): case ( BOOL_B_SUB_A ): m_graphlist->Boolean( operation, m_intersectionruns ); break; case ( BOOL_CORRECTION ): m_graphlist->Correction(); break; case ( BOOL_MAKERING ): m_graphlist->MakeRings(); break; case ( BOOL_SMOOTHEN ): m_graphlist->Smoothen( GetInternalSmoothAber() ); break; default: { error( "Wrong operation", "Command Error" ); return false; } } } catch ( Bool_Engine_Error & error ) { #if KBOOL_DEBUG delete m_graphlist; m_graphlist = new kbGraphList( saveme ); m_graphlist->WriteGraphsKEY( this ); #endif if ( m_logfile != NULL ) { fclose ( m_logfile ); m_logfile = NULL; } info( error.GetErrorMessage(), "error" ); throw error; } catch( ... ) { #if KBOOL_DEBUG delete m_graphlist; m_graphlist = new kbGraphList( saveme ); m_graphlist->WriteGraphsKEY( this ); #endif if ( m_logfile != NULL ) { fclose ( m_logfile ); m_logfile = NULL; } info( "Unknown exception", "error" ); throw ; } #if KBOOL_DEBUG delete saveme; #endif return true; } bool Bool_Engine::StartPolygonAdd( GroupType A_or_B ) { #if KBOOL_DEBUG if ( m_logfile != NULL ) fprintf( m_logfile, "-> StartPolygonAdd(%d)\n", A_or_B ); #endif if ( m_GraphToAdd != NULL ) return false; kbGraph *myGraph = new kbGraph( this ); m_graphlist->insbegin( myGraph ); m_GraphToAdd = myGraph; m_groupType = A_or_B; return true; } bool Bool_Engine::AddPoint( double x, double y ) { if ( m_GraphToAdd == NULL ){return false;} double scaledx = x * m_DGRID * m_GRID; double scaledy = y * m_DGRID * m_GRID; if ( scaledx > MAXB_INT || scaledx < MINB_INT ) error( "X coordinate of vertex to big", "" ); if ( scaledy > MAXB_INT || scaledy < MINB_INT ) error( "Y coordinate of vertex to big", "" ); B_INT rintx = ( ( B_INT ) ( x * m_DGRID ) ) * m_GRID; B_INT rinty = ( ( B_INT ) ( y * m_DGRID ) ) * m_GRID; kbNode *myNode = new kbNode( rintx, rinty, this ); // adding first point to graph if ( m_firstNodeToAdd == NULL ) { #if KBOOL_DEBUG if ( m_logfile != NULL ) { fprintf( m_logfile, "-> AddPt() *FIRST* :" ); fprintf( m_logfile, " input: x = %f, y = %f\n", x, y ); fprintf( m_logfile, " input: x = %I64d, y = %I64d\n", rintx, rinty ) ; } #endif m_firstNodeToAdd = ( kbNode * ) myNode; m_lastNodeToAdd = ( kbNode * ) myNode; } else { #if KBOOL_DEBUG if ( m_logfile != NULL ) { fprintf( m_logfile, "-> AddPt():" ); fprintf( m_logfile, " input: x = %f, y = %f\n", x, y ); fprintf( m_logfile, " input: x = %I64d, y = %I64d\n", rintx, rinty ) ; } #endif m_GraphToAdd->AddLink( m_lastNodeToAdd, myNode ); m_lastNodeToAdd = ( kbNode * ) myNode; } return true; } bool Bool_Engine::EndPolygonAdd() { if ( m_GraphToAdd == NULL ) {return false;} m_GraphToAdd->AddLink( m_lastNodeToAdd, m_firstNodeToAdd ); m_GraphToAdd->SetGroup( m_groupType ); m_GraphToAdd = NULL; m_lastNodeToAdd = NULL; m_firstNodeToAdd = NULL; return true; } bool Bool_Engine::StartPolygonGet() { if ( !m_graphlist->empty() ) { m_getGraph = ( kbGraph* ) m_graphlist->headitem(); m_getLink = m_getGraph->GetFirstLink(); m_getNode = m_getLink->GetBeginNode(); m_numPtsInPolygon = m_getGraph->GetNumberOfLinks(); m_numNodesVisited = 0; return true; } else { return false; } } bool Bool_Engine::PolygonHasMorePoints() { // see if first point if ( m_numNodesVisited == 0 ) { // don't need to touch the m_getNode m_numNodesVisited++; return true; } if ( m_numNodesVisited < m_numPtsInPolygon ) { // traverse to the next node m_getNode = m_getLink->GetOther( m_getNode ); m_getLink = m_getLink->Forth( m_getNode ); m_numNodesVisited++; return true; } else { return false; } } void Bool_Engine::EndPolygonGet() { m_graphlist->removehead(); delete m_getGraph; } double Bool_Engine::GetPolygonXPoint() { return m_getNode->GetX() / m_GRID / m_DGRID; } double Bool_Engine::GetPolygonYPoint() { return m_getNode->GetY() / m_GRID / m_DGRID; } bool Bool_Engine::GetHoleSegment() { if ( m_getLink->GetHole() ) return true; return false; } bool Bool_Engine::GetHoleConnectionSegment() { if ( m_getLink->GetHoleLink() ) return true; return false; } kbEdgeType Bool_Engine::GetPolygonPointEdgeType() { // see if the point is the beginning of a false edge if ( m_getLink->GetHoleLink() ) return KB_FALSE_EDGE; else // it's either an outside or inside edge if ( m_getLink->GetHole() ) return KB_INSIDE_EDGE; else return KB_OUTSIDE_EDGE; } void Bool_Engine::Write_Log( string msg1 ) { if ( m_logfile == NULL ) return; fprintf( m_logfile, "%s \n", msg1.c_str() ); } void Bool_Engine::Write_Log( string msg1, string msg2 ) { if ( m_logfile == NULL ) return; fprintf( m_logfile, "%s %s\n", msg1.c_str(), msg2.c_str() ); } void Bool_Engine::Write_Log( string fmt, double dval ) { if ( m_logfile == NULL ) return; fprintf( m_logfile, fmt.c_str(), dval ); } void Bool_Engine::Write_Log( string fmt, B_INT bval ) { if ( m_logfile == NULL ) return; fprintf( m_logfile, fmt.c_str(), bval ); }