From 1f277fd66d046f2445df16133802710a4ed91543 Mon Sep 17 00:00:00 2001 From: jean-pierre charras Date: Sat, 4 Aug 2012 11:43:27 +0200 Subject: [PATCH] Remove Kbool from Kicad. Use Clipper instead. --- 3d-viewer/3d_draw.cpp | 8 +- bitmap2component/CMakeLists.txt | 2 +- common/footprint_info.cpp | 2 +- cvpcb/CMakeLists.txt | 1 - eeschema/CMakeLists.txt | 1 - gerbview/CMakeLists.txt | 2 +- kicad/CMakeLists.txt | 2 - pcb_calculator/CMakeLists.txt | 1 - pcbnew/CMakeLists.txt | 12 +- pcbnew/dialogs/dialog_gendrill.cpp | 2 +- pcbnew/eagle_plugin.cpp | 1 + pcbnew/zones_by_polygon.cpp | 42 +- pcbnew/zones_functions_for_undo_redo.cpp | 35 +- pcbnew/zones_test_and_combine_areas.cpp | 136 +- polygon/CMakeLists.txt | 1 + polygon/PolyLine.cpp | 534 +-- polygon/PolyLine.h | 37 +- polygon/clipper.cpp | 3424 +++++++++++++++++ polygon/clipper.hpp | 306 ++ polygon/kbool/CMakeLists.txt | 3 - polygon/kbool/include/kbool/_dl_itr.cpp | 2376 ------------ polygon/kbool/include/kbool/_dl_itr.h | 407 -- polygon/kbool/include/kbool/_lnk_itr.cpp | 257 -- polygon/kbool/include/kbool/_lnk_itr.h | 159 - polygon/kbool/include/kbool/booleng.h | 596 --- polygon/kbool/include/kbool/graph.h | 207 - polygon/kbool/include/kbool/graphlst.h | 65 - polygon/kbool/include/kbool/kboolmod.h | 15 - polygon/kbool/include/kbool/line.h | 107 - polygon/kbool/include/kbool/link.h | 230 -- polygon/kbool/include/kbool/lpoint.h | 60 - polygon/kbool/include/kbool/node.h | 87 - polygon/kbool/include/kbool/record.h | 78 - polygon/kbool/include/kbool/scanbeam.h | 58 - polygon/kbool/include/kbool/statusb.h | 54 - polygon/kbool/include/kbool/valuesvc.h | 9 - polygon/kbool/infos_kbool.txt | 7 - polygon/kbool/kboollicense.txt | 684 ---- polygon/kbool/samples/boolonly/CMakeLists.txt | 11 - polygon/kbool/samples/boolonly/boolonly.cpp | 373 -- polygon/kbool/samples/boolonly/boolonly.h | 28 - polygon/kbool/samples/boolonly/boolonly.rc | 2 - polygon/kbool/src/CMakeLists.txt | 21 - polygon/kbool/src/booleng.cpp | 585 --- polygon/kbool/src/graph.cpp | 2629 ------------- polygon/kbool/src/graphlst.cpp | 392 -- polygon/kbool/src/instonly.cpp | 38 - polygon/kbool/src/line.cpp | 1479 ------- polygon/kbool/src/link.cpp | 721 ---- polygon/kbool/src/lpoint.cpp | 199 - polygon/kbool/src/node.cpp | 620 --- polygon/kbool/src/record.cpp | 352 -- polygon/kbool/src/scanbeam.cpp | 1467 ------- polygon/math_for_graphics.cpp | 24 +- 54 files changed, 3956 insertions(+), 14993 deletions(-) create mode 100644 polygon/clipper.cpp create mode 100644 polygon/clipper.hpp delete mode 100644 polygon/kbool/CMakeLists.txt delete mode 100644 polygon/kbool/include/kbool/_dl_itr.cpp delete mode 100644 polygon/kbool/include/kbool/_dl_itr.h delete mode 100644 polygon/kbool/include/kbool/_lnk_itr.cpp delete mode 100644 polygon/kbool/include/kbool/_lnk_itr.h delete mode 100644 polygon/kbool/include/kbool/booleng.h delete mode 100644 polygon/kbool/include/kbool/graph.h delete mode 100644 polygon/kbool/include/kbool/graphlst.h delete mode 100644 polygon/kbool/include/kbool/kboolmod.h delete mode 100644 polygon/kbool/include/kbool/line.h delete mode 100644 polygon/kbool/include/kbool/link.h delete mode 100644 polygon/kbool/include/kbool/lpoint.h delete mode 100644 polygon/kbool/include/kbool/node.h delete mode 100644 polygon/kbool/include/kbool/record.h delete mode 100644 polygon/kbool/include/kbool/scanbeam.h delete mode 100644 polygon/kbool/include/kbool/statusb.h delete mode 100644 polygon/kbool/include/kbool/valuesvc.h delete mode 100644 polygon/kbool/infos_kbool.txt delete mode 100644 polygon/kbool/kboollicense.txt delete mode 100644 polygon/kbool/samples/boolonly/CMakeLists.txt delete mode 100644 polygon/kbool/samples/boolonly/boolonly.cpp delete mode 100644 polygon/kbool/samples/boolonly/boolonly.h delete mode 100644 polygon/kbool/samples/boolonly/boolonly.rc delete mode 100644 polygon/kbool/src/CMakeLists.txt delete mode 100644 polygon/kbool/src/booleng.cpp delete mode 100644 polygon/kbool/src/graph.cpp delete mode 100644 polygon/kbool/src/graphlst.cpp delete mode 100644 polygon/kbool/src/instonly.cpp delete mode 100644 polygon/kbool/src/line.cpp delete mode 100644 polygon/kbool/src/link.cpp delete mode 100644 polygon/kbool/src/lpoint.cpp delete mode 100644 polygon/kbool/src/node.cpp delete mode 100644 polygon/kbool/src/record.cpp delete mode 100644 polygon/kbool/src/scanbeam.cpp diff --git a/3d-viewer/3d_draw.cpp b/3d-viewer/3d_draw.cpp index 36e2bcea1c..a0100d005f 100644 --- a/3d-viewer/3d_draw.cpp +++ b/3d-viewer/3d_draw.cpp @@ -170,12 +170,8 @@ GLuint EDA_3D_CANVAS::CreateDrawGL_List() if( g_Parm_3D_Visu.m_Layers < 2 ) g_Parm_3D_Visu.m_Layers = 2; - g_Parm_3D_Visu.m_BoardScale = 2.0 / max( g_Parm_3D_Visu.m_BoardSize.x, - g_Parm_3D_Visu.m_BoardSize.y ); - - // @TODO: epoxy_width (board thickness) must be set by user, - // because all boards thickness no not match with this setup: - // double epoxy_width = 1.6; // epoxy width in mm + g_Parm_3D_Visu.m_BoardScale = 2.0 / std::max( g_Parm_3D_Visu.m_BoardSize.x, + g_Parm_3D_Visu.m_BoardSize.y ); g_Parm_3D_Visu.m_Epoxy_Width = pcb->GetDesignSettings().GetBoardThickness() * g_Parm_3D_Visu.m_BoardScale; diff --git a/bitmap2component/CMakeLists.txt b/bitmap2component/CMakeLists.txt index 4ab7b012c3..2c5c85eed9 100644 --- a/bitmap2component/CMakeLists.txt +++ b/bitmap2component/CMakeLists.txt @@ -46,7 +46,7 @@ endif(APPLE) target_link_libraries( bitmap2component common polygon bitmaps ${wxWidgets_LIBRARIES} potrace - kbool ) + ) install(TARGETS bitmap2component DESTINATION ${KICAD_BIN} diff --git a/common/footprint_info.cpp b/common/footprint_info.cpp index 9b0602e25d..5a5e415782 100644 --- a/common/footprint_info.cpp +++ b/common/footprint_info.cpp @@ -70,7 +70,7 @@ bool FOOTPRINT_LIST::ReadFootprintFiles( wxArrayString& aFootprintsLibNames ) for( unsigned i=0; i m( pi->FootprintLoad( libPath, fpnames[i] ) ); + std::auto_ptr m( pi->FootprintLoad( libPath, fpnames[i] ) ); // we're loading what we enumerated, all must be there. wxASSERT( m.get() ); diff --git a/cvpcb/CMakeLists.txt b/cvpcb/CMakeLists.txt index 64c10f9aa0..2a4e228e4e 100644 --- a/cvpcb/CMakeLists.txt +++ b/cvpcb/CMakeLists.txt @@ -98,7 +98,6 @@ target_link_libraries(cvpcb common bitmaps polygon - kbool ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${GDI_PLUS_LIBRARIES} diff --git a/eeschema/CMakeLists.txt b/eeschema/CMakeLists.txt index eaba2b8009..dc81ae474f 100644 --- a/eeschema/CMakeLists.txt +++ b/eeschema/CMakeLists.txt @@ -217,7 +217,6 @@ target_link_libraries(eeschema common bitmaps polygon - kbool ${wxWidgets_LIBRARIES} ${GDI_PLUS_LIBRARIES} ) diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt index bfdfaf3438..cc5d7a0b91 100644 --- a/gerbview/CMakeLists.txt +++ b/gerbview/CMakeLists.txt @@ -121,7 +121,7 @@ endif(APPLE) ### # Link executable target gerbview with correct libraries ### -target_link_libraries(gerbview common polygon bitmaps kbool +target_link_libraries(gerbview common polygon bitmaps ${OPENGL_LIBRARIES} ${wxWidgets_LIBRARIES} ${GDI_PLUS_LIBRARIES}) diff --git a/kicad/CMakeLists.txt b/kicad/CMakeLists.txt index 27b2cd20cf..eccd7356a5 100644 --- a/kicad/CMakeLists.txt +++ b/kicad/CMakeLists.txt @@ -51,7 +51,6 @@ if(APPLE) common bitmaps polygon - kbool ${wxWidgets_LIBRARIES} ) else(APPLE) @@ -59,7 +58,6 @@ else(APPLE) common bitmaps polygon - kbool ${wxWidgets_LIBRARIES} ${GDI_PLUS_LIBRARIES} ) diff --git a/pcb_calculator/CMakeLists.txt b/pcb_calculator/CMakeLists.txt index 02ef447d2c..30d44beba3 100644 --- a/pcb_calculator/CMakeLists.txt +++ b/pcb_calculator/CMakeLists.txt @@ -82,7 +82,6 @@ target_link_libraries( pcb_calculator common bitmaps polygon - kbool ${wxWidgets_LIBRARIES} ) diff --git a/pcbnew/CMakeLists.txt b/pcbnew/CMakeLists.txt index 17ccf619cb..6cd84b5da6 100644 --- a/pcbnew/CMakeLists.txt +++ b/pcbnew/CMakeLists.txt @@ -285,7 +285,7 @@ if (KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES) endif(KICAD_SCRIPTING OR KICAD_SCRIPTING_MODULES) if (KICAD_SCRIPTING) - + SET(SWIG_OPTS -python -c++ -outdir ${CMAKE_CURRENT_BINARY_DIR} ${SWIG_FLAGS} ) add_custom_command( @@ -325,7 +325,6 @@ if (KICAD_SCRIPTING_MODULES) common bitmaps polygon - kbool ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${GDI_PLUS_LIBRARIES} @@ -418,7 +417,6 @@ target_link_libraries(pcbnew common bitmaps polygon - kbool ${wxWidgets_LIBRARIES} ${OPENGL_LIBRARIES} ${GDI_PLUS_LIBRARIES} @@ -438,8 +436,8 @@ if(KICAD_SCRIPTING) ${CMAKE_CURRENT_SOURCE_DIR}/../scripting/fixswigimports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/pcbnew COMMENT "Fixing swig_import_helper" - ) - + ) + install(FILES ${CMAKE_BINARY_DIR}/pcbnew/pcbnew.py DESTINATION ${PYTHON_DEST}) @@ -450,8 +448,8 @@ if (KICAD_SCRIPTING_MODULES) ${CMAKE_CURRENT_SOURCE_DIR}/../scripting/fixswigimports.py ${CMAKE_CURRENT_BINARY_DIR}/pcbnew.py DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_pcbnew COMMENT "Fixing swig_import_helper" - ) - + ) + install(FILES ${CMAKE_BINARY_DIR}/pcbnew/pcbnew.py DESTINATION ${PYTHON_DEST}) diff --git a/pcbnew/dialogs/dialog_gendrill.cpp b/pcbnew/dialogs/dialog_gendrill.cpp index 17c4658644..aa57ad10d2 100644 --- a/pcbnew/dialogs/dialog_gendrill.cpp +++ b/pcbnew/dialogs/dialog_gendrill.cpp @@ -186,7 +186,7 @@ void DIALOG_GENDRILL::InitDisplayParams() } else { - if( min( pad->GetDrillSize().x, pad->GetDrillSize().y ) != 0 ) + if( std::min( pad->GetDrillSize().x, pad->GetDrillSize().y ) != 0 ) { if( pad->GetAttribute() == PAD_HOLE_NOT_PLATED ) m_notplatedPadsHoleCount++; diff --git a/pcbnew/eagle_plugin.cpp b/pcbnew/eagle_plugin.cpp index 72265679ff..9d9039ed93 100644 --- a/pcbnew/eagle_plugin.cpp +++ b/pcbnew/eagle_plugin.cpp @@ -76,6 +76,7 @@ Load() TODO's #include using namespace boost::property_tree; +using namespace std; typedef EAGLE_PLUGIN::BIU BIU; typedef PTREE::const_assoc_iterator CA_ITER; diff --git a/pcbnew/zones_by_polygon.cpp b/pcbnew/zones_by_polygon.cpp index 3a53d0389d..cb74e05bb4 100644 --- a/pcbnew/zones_by_polygon.cpp +++ b/pcbnew/zones_by_polygon.cpp @@ -63,7 +63,7 @@ static bool s_AddCutoutToCurrentZone; // if true, the next outline static ZONE_CONTAINER* s_CurrentZone; // if != NULL, these ZONE_CONTAINER params will be used for the next zone static wxPoint s_CursorLastPosition; // in move zone outline, last cursor position. Used to calculate the move vector static PICKED_ITEMS_LIST s_PickedList; // a picked list to save zones for undo/redo command -static PICKED_ITEMS_LIST _AuxiliaryList; // a picked list to store zones that are deleted or added when combined +static PICKED_ITEMS_LIST s_AuxiliaryList; // a picked list to store zones that are deleted or added when combined void PCB_EDIT_FRAME::Add_Similar_Zone( wxDC* DC, ZONE_CONTAINER* aZone ) @@ -128,7 +128,7 @@ void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ) zoneSettings.ExportSetting( *newZone ); newZone->m_Poly->Hatch(); - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); SaveCopyOfZones( s_PickedList, GetBoard(), newZone->GetNet(), newZone->GetLayer() ); GetBoard()->Add( newZone ); @@ -139,7 +139,7 @@ void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ) GetScreen()->SetCurItem( NULL ); // This outline may be deleted when merging outlines // Combine zones if possible - GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, newZone ); + GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, newZone ); // Redraw zones GetBoard()->RedrawAreasOutlines( m_canvas, aDC, GR_OR, newZone->GetLayer() ); @@ -151,7 +151,7 @@ void PCB_EDIT_FRAME::duplicateZone( wxDC* aDC, ZONE_CONTAINER* aZone ) DisplayError( this, _( "Duplicate Zone: The outline of the duplicated zone fails DRC check!" ) ); } - UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList( s_PickedList, UR_UNSPECIFIED ); s_PickedList.ClearItemsList(); @@ -245,7 +245,7 @@ void PCB_EDIT_FRAME::Start_Move_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone, if ( IsNewCorner ) aZone->m_Poly->DeleteCorner( corner_id ); - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNet(), @@ -277,7 +277,7 @@ void PCB_EDIT_FRAME::Start_Move_Zone_Drag_Outline_Edge( wxDC* DC, s_CurrentZone = NULL; s_PickedList.ClearListAndDeleteItems(); - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNet(), aZone->GetLayer() ); } @@ -302,7 +302,7 @@ void PCB_EDIT_FRAME::Start_Move_Zone_Outlines( wxDC* DC, ZONE_CONTAINER* aZone ) } s_PickedList.ClearListAndDeleteItems(); - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNet(), aZone->GetLayer() ); @@ -332,7 +332,7 @@ void PCB_EDIT_FRAME::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER* // Combine zones if possible wxBusyCursor dummy; - GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone ); + GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone ); m_canvas->Refresh(); @@ -341,7 +341,7 @@ void PCB_EDIT_FRAME::End_Move_Zone_Corner_Or_Outlines( wxDC* DC, ZONE_CONTAINER* if( ii < 0 ) aZone = NULL; // was removed by combining zones - UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items @@ -380,14 +380,14 @@ void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone ) GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer ); } - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList. ClearListAndDeleteItems(); SaveCopyOfZones( s_PickedList, GetBoard(), aZone->GetNet(), aZone->GetLayer() ); aZone->m_Poly->DeleteCorner( aZone->m_CornerSelection ); // modify zones outlines according to the new aZone shape - GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone ); + GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone ); if( DC ) { @@ -395,7 +395,7 @@ void PCB_EDIT_FRAME::Remove_Zone_Corner( wxDC* DC, ZONE_CONTAINER* aZone ) GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_OR, layer ); } - UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items @@ -448,7 +448,7 @@ void Abort_Zone_Move_Corner_Or_Outlines( EDA_DRAW_PANEL* Panel, wxDC* DC ) } Panel->SetMouseCapture( NULL, NULL ); - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList. ClearListAndDeleteItems(); Panel->Refresh(); @@ -733,7 +733,7 @@ bool PCB_EDIT_FRAME::End_Zone( wxDC* DC ) GetBoard()->RedrawFilledAreas( m_canvas, DC, GR_XOR, layer ); // Save initial zones configuration, for undo/redo, before adding new zone - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); SaveCopyOfZones(s_PickedList, GetBoard(), zone->GetNet(), zone->GetLayer() ); @@ -766,7 +766,7 @@ bool PCB_EDIT_FRAME::End_Zone( wxDC* DC ) GetScreen()->SetCurItem( NULL ); // This outline can be deleted when merging outlines // Combine zones if possible : - GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, zone ); + GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, zone ); // Redraw the real edge zone : GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, layer ); @@ -784,7 +784,7 @@ bool PCB_EDIT_FRAME::End_Zone( wxDC* DC ) DisplayError( this, _( "Area: DRC outline error" ) ); } - UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items @@ -838,7 +838,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) // Save initial zones configuration, for undo/redo, before adding new zone // note the net name and the layer can be changed, so we must save all zones - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); SaveCopyOfZones(s_PickedList, GetBoard(), -1, -1 ); @@ -866,7 +866,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) if( edited == ZONE_ABORT ) { - _AuxiliaryList.ClearListAndDeleteItems(); + s_AuxiliaryList.ClearListAndDeleteItems(); s_PickedList.ClearListAndDeleteItems(); return; } @@ -875,7 +875,7 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) if( edited == ZONE_EXPORT_VALUES ) { - UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no more owner of picked items return; @@ -896,12 +896,12 @@ void PCB_EDIT_FRAME::Edit_Zone_Params( wxDC* DC, ZONE_CONTAINER* aZone ) aZone->SetNetName( net->GetNetname() ); // Combine zones if possible - GetBoard()->OnAreaPolygonModified( &_AuxiliaryList, aZone ); + GetBoard()->OnAreaPolygonModified( &s_AuxiliaryList, aZone ); // Redraw the real new zone outlines GetBoard()->RedrawAreasOutlines( m_canvas, DC, GR_OR, -1 ); - UpdateCopyOfZonesList( s_PickedList, _AuxiliaryList, GetBoard() ); + UpdateCopyOfZonesList( s_PickedList, s_AuxiliaryList, GetBoard() ); SaveCopyInUndoList(s_PickedList, UR_UNSPECIFIED); s_PickedList.ClearItemsList(); // s_ItemsListPicker is no longer owner of picked items diff --git a/pcbnew/zones_functions_for_undo_redo.cpp b/pcbnew/zones_functions_for_undo_redo.cpp index 8a1e629476..c3254d0760 100644 --- a/pcbnew/zones_functions_for_undo_redo.cpp +++ b/pcbnew/zones_functions_for_undo_redo.cpp @@ -174,19 +174,26 @@ int SaveCopyOfZones( PICKED_ITEMS_LIST& aPickList, BOARD* aPcb, int aNetCode, in * @param aPcb = the Board * * aAuxiliaryList is a list of pickers updated by zone algorithms: - * This list cointains zones which were added or deleted during the zones combine process + * This list contains zones which were added or deleted during the zones combine process * aPickList :is a list of zones that can be modified (changed or deleted, or not modified) + * Typically, this is the list of existing zones on the layer of the edited zone, + * before any change. * >> if the picked zone is not changed, it is removed from list - * >> if the picked zone was deleted (i.e. not found in boad list), the picker is modified: - * - its status becomes UR_DELETED - * - the aAuxiliaryList corresponding picker is removed (if not found : set an error) - * >> if the picked zone was flagged as UR_NEW, and was deleted (i.e. not found in boad list), - * - the picker is removed - * - the zone itself if really deleted - * - the aAuxiliaryList corresponding picker is removed (if not found : set an error) + * >> if the picked zone was deleted (i.e. not found in board list), the picker is modified: + * its status becomes UR_DELETED + * the aAuxiliaryList corresponding picker is removed (if not found : set an error) + * >> if the picked zone was flagged as UR_NEW, and was after deleted , + * perhaps combined with an other zone (i.e. not found in board list): + * the picker is removed + * the zone itself if really deleted + * the aAuxiliaryList corresponding picker is removed (if not found : set an error) * After aPickList is cleaned, the aAuxiliaryList is read * All pickers flagged UR_NEW are moved to aPickList - * (the corresponding zones are zone that were created by the zone combine process, mainly when adding cutaout areas) + * (the corresponding zones are zone that were created by the zone normalize and combine process, + * mainly when adding cutout areas, or creating self intersecting contours) + * All pickers flagged UR_DELETED are removed, and the coresponding zones actually deleted + * (the corresponding zones are new zone that were created by the zone normalize process, + * when creating self intersecting contours, and after combined with an existing zone. * At the end of the update process the aAuxiliaryList must be void, * because all pickers created by the combine process * must have been removed (removed for new and deleted zones, or moved in aPickList.) @@ -274,15 +281,21 @@ void UpdateCopyOfZonesList( PICKED_ITEMS_LIST& aPickList, // Add new zones in main pick list, and remove pickers from Auxiliary List - for( unsigned ii = 0; ii < aAuxiliaryList.GetCount(); ii++ ) + for( unsigned ii = 0; ii < aAuxiliaryList.GetCount(); ) { if( aAuxiliaryList.GetPickedItemStatus( ii ) == UR_NEW ) { ITEM_PICKER picker = aAuxiliaryList.GetItemWrapper( ii ); aPickList.PushItem( picker ); aAuxiliaryList.RemovePicker( ii ); - ii--; } + else if( aAuxiliaryList.GetPickedItemStatus( ii ) == UR_DELETED ) + { + delete aAuxiliaryList.GetPickedItemLink( ii ); + aAuxiliaryList.RemovePicker( ii ); + } + else + ii++; } // Should not occur: diff --git a/pcbnew/zones_test_and_combine_areas.cpp b/pcbnew/zones_test_and_combine_areas.cpp index d6169a69ea..133bc4fcde 100644 --- a/pcbnew/zones_test_and_combine_areas.cpp +++ b/pcbnew/zones_test_and_combine_areas.cpp @@ -211,12 +211,12 @@ bool BOARD::OnAreaPolygonModified( PICKED_ITEMS_LIST* aModifiedZonesList, // Test for bad areas: all zones must have more than 2 corners: // Note: should not happen, but just in case. - for( unsigned ia1 = 0; ia1 < m_ZoneDescriptorList.size() - 1; ) + for( unsigned ii = 0; ii < m_ZoneDescriptorList.size(); ) { - ZONE_CONTAINER* zone = m_ZoneDescriptorList[ia1]; + ZONE_CONTAINER* zone = m_ZoneDescriptorList[ii]; if( zone->GetNumCorners() >= 3 ) - ia1++; + ii++; else // Remove zone because it is incorrect: RemoveArea( aModifiedZonesList, zone ); } @@ -267,25 +267,25 @@ bool BOARD::CombineAllAreasInNet( PICKED_ITEMS_LIST* aDeletedList, int aNetCode, if( curr_area->GetIsKeepout() != area2->GetIsKeepout() ) continue; - if( curr_area->GetLayer() == area2->GetLayer() ) + if( curr_area->GetLayer() != area2->GetLayer() ) + continue; + + CRect b2 = area2->m_Poly->GetCornerBounds(); + if( !( b1.left > b2.right || b1.right < b2.left + || b1.bottom > b2.top || b1.top < b2.bottom ) ) { - CRect b2 = area2->m_Poly->GetCornerBounds(); - if( !( b1.left > b2.right || b1.right < b2.left - || b1.bottom > b2.top || b1.top < b2.bottom ) ) + // check area2 against curr_area + if( curr_area->utility || area2->utility || aUseUtility == false ) { - // check area2 against curr_area - if( curr_area->utility || area2->utility || aUseUtility == false ) + bool ret = TestAreaIntersection( curr_area, area2 ); + + if( ret ) + ret = CombineAreas( aDeletedList, curr_area, area2 ); + + if( ret ) { - bool ret = TestAreaIntersection( curr_area, area2 ); - - if( ret ) - ret = CombineAreas( aDeletedList, curr_area, area2 ); - - if( ret ) - { - mod_ia1 = true; - modified = true; - } + mod_ia1 = true; + modified = true; } } } @@ -424,7 +424,7 @@ bool BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area if( poly1->TestPointInside( x, y ) ) { - return 1; + return true; } } @@ -435,11 +435,11 @@ bool BOARD::TestAreaIntersection( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area if( poly2->TestPointInside( x, y ) ) { - return 1; + return true; } } - return 0; + return false; } @@ -465,10 +465,6 @@ bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ } // polygons intersect, combine them - // TODO: test here if areas intersect and combine only if so - -#if 0 - // do not set to 1 (not fully working): only for me (JP. Charras) until this code is finished KI_POLYGON_WITH_HOLES areaRefPoly; KI_POLYGON_WITH_HOLES areaToMergePoly; CopyPolysListToKiPolygonWithHole( area_ref->m_Poly->m_CornersList, areaRefPoly ); @@ -478,10 +474,20 @@ bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ mergedOutlines.push_back( areaRefPoly ); mergedOutlines |= areaToMergePoly; - // We can have more than one polygon with holes in mergedOutlines - // depending on the complexity of outlines + // We should have one polygon with hole + // We can have 2 polygons with hole, if the 2 initial polygons have only one common corner + // and therefore cannot be merged (they are dectected as intersecting) + // but we should never have more than 2 polys + if( mergedOutlines.size() > 2 ) + { + wxLogMessage(wxT("BOARD::CombineAreas error: more than 2 polys after merging") ); + return false; + } - areaRefPoly = mergedOutlines[0]; // TODO: read and create all created polygons + if( mergedOutlines.size() > 1 ) + return false; + + areaRefPoly = mergedOutlines[0]; area_ref->m_Poly->RemoveAllContours(); KI_POLYGON_WITH_HOLES::iterator_type corner = areaRefPoly.begin(); @@ -509,76 +515,6 @@ bool BOARD::CombineAreas( PICKED_ITEMS_LIST* aDeletedList, ZONE_CONTAINER* area_ area_ref->m_Poly->CloseLastContour(); hole++; } -#else - void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); - Bool_Engine* booleng = new Bool_Engine(); - armBoolEng( booleng ); - - area_ref->m_Poly->AddPolygonsToBoolEng( booleng, GROUP_A ); - area_to_combine->m_Poly->AddPolygonsToBoolEng(booleng, GROUP_B ); - booleng->Do_Operation( BOOL_OR ); - - // create area with external contour: Recreate only area edges, NOT holes - if( booleng->StartPolygonGet() ) - { - if( booleng->GetPolygonPointEdgeType() == KB_INSIDE_EDGE ) - { - DisplayError( NULL, wxT( "BOARD::CombineAreas() error: unexpected hole descriptor" ) ); - } - - area_ref->m_Poly->RemoveAllContours(); - - // foreach point in the polygon - bool first = true; - - while( booleng->PolygonHasMorePoints() ) - { - int x = (int) booleng->GetPolygonXPoint(); - int y = (int) booleng->GetPolygonYPoint(); - - if( first ) - { - first = false; - area_ref->m_Poly->Start( area_ref->GetLayer( - ), x, y, area_ref->m_Poly->GetHatchStyle() ); - } - else - { - area_ref->m_Poly->AppendCorner( x, y ); - } - } - - booleng->EndPolygonGet(); - area_ref->m_Poly->CloseLastContour(); - } - - // add holes - bool show_error = true; - - while( booleng->StartPolygonGet() ) - { - // we expect all vertex are holes inside the main outline - if( booleng->GetPolygonPointEdgeType() != KB_INSIDE_EDGE ) - { - if( show_error ) // show this error only once, if happens - DisplayError( NULL, - wxT( "BOARD::CombineAreas() error: unexpected outside contour descriptor" ) ); - - show_error = false; - continue; - } - - while( booleng->PolygonHasMorePoints() ) - { - int x = (int) booleng->GetPolygonXPoint(); - int y = (int) booleng->GetPolygonYPoint(); - area_ref->m_Poly->AppendCorner( x, y ); - } - - area_ref->m_Poly->CloseLastContour(); - booleng->EndPolygonGet(); - } -#endif RemoveArea( aDeletedList, area_to_combine ); @@ -822,7 +758,7 @@ bool DRC::doEdgeZoneDrc( ZONE_CONTAINER* aArea, int aCornerIndex ) for( int ia2 = 0; ia2 < m_pcb->GetAreaCount(); ia2++ ) { ZONE_CONTAINER* area_to_test = m_pcb->GetArea( ia2 ); - int zone_clearance = max( area_to_test->m_ZoneClearance, + int zone_clearance = std::max( area_to_test->m_ZoneClearance, aArea->m_ZoneClearance ); // test for same layer diff --git a/polygon/CMakeLists.txt b/polygon/CMakeLists.txt index 77b08327d1..52068b52af 100644 --- a/polygon/CMakeLists.txt +++ b/polygon/CMakeLists.txt @@ -8,6 +8,7 @@ set(POLYGON_SRCS math_for_graphics.cpp PolyLine.cpp polygon_test_point_inside.cpp + clipper.cpp ) add_library(polygon STATIC ${POLYGON_SRCS}) diff --git a/polygon/PolyLine.cpp b/polygon/PolyLine.cpp index aee22e3cf0..665e6f74d8 100644 --- a/polygon/PolyLine.cpp +++ b/polygon/PolyLine.cpp @@ -16,16 +16,12 @@ #include #include -enum m_SideStyle { STRAIGHT }; // side styles - - CPolyLine::CPolyLine() { m_hatchStyle = NO_HATCH; m_hatchPitch = 0; m_layer = 0; m_utility = 0; - m_Kbool_Poly_Engine = NULL; } @@ -34,409 +30,6 @@ CPolyLine::CPolyLine() CPolyLine::~CPolyLine() { UnHatch(); - - if( m_Kbool_Poly_Engine ) - delete m_Kbool_Poly_Engine; -} - - -/** - * Function armBoolEng - * Initialise parameters used in kbool - * @param aBooleng = pointer to the Bool_Engine to initialise - * @param aConvertHoles = mode for holes when a boolean operation is made - * true: holes are linked into outer contours by double overlapping segments - * false: holes are not linked: in this mode contours are added clockwise - * and polygons added counter clockwise are holes (default) - */ -void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles = false ); - -/** - * Function NormalizeWithKbool - * Use the Kbool Library to clip contours: if outlines are crossing, the self-crossing polygon - * is converted to non self-crossing polygon by adding extra points at the crossing locations - * and reordering corners - * if more than one outside contour are found, extra CPolyLines will be created - * because copper areas have only one outside contour - * Therefore, if this results in new CPolyLines, return them as std::vector pa - * @param aExtraPolyList: pointer on a std::vector to store extra CPolyLines - * (when after normalization, there is more than one polygon with holes) - * @return number of external contours, or -1 if error - */ -int CPolyLine::NormalizeWithKbool( std::vector* aExtraPolyList ) -{ - std::vector hole_array; // list of holes - std::vector* hole; // used to store corners for a given hole - CPolyLine* polyline; - int n_ext_cont = 0; // CPolyLine count - - /* Creates a bool engine from this CPolyLine. - * Normalized outlines and holes will be in m_Kbool_Poly_Engine - * If some polygons are self crossing, after running the Kbool Engine, self crossing polygons - * will be converted in non self crossing polygons by inserting extra points at the crossing locations - * True holes are combined if possible - */ - MakeKboolPoly(); - - UnHatch(); - - /* now, recreate polys - * if more than one outside contour are found, extra CPolyLines will be created - * because copper areas have only one outside contour - * the first outside contour found is the new "this" outside contour - * if others outside contours are found we create new CPolyLines - * Note: if there are holes in polygons, we must store them - * and when all outside contours are found, search the corresponding outside contour for each hole - */ - while( m_Kbool_Poly_Engine->StartPolygonGet() ) - { - // See if the current polygon is flagged as a hole - if( m_Kbool_Poly_Engine->GetPolygonPointEdgeType() == KB_INSIDE_EDGE ) - { - hole = new std::vector; - hole_array.push_back( hole ); - - while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // store hole - { - int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); - int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); - hole->push_back( x ); - hole->push_back( y ); - } - - m_Kbool_Poly_Engine->EndPolygonGet(); - } - else if( n_ext_cont == 0 ) - { - // first external contour, replace this poly - m_CornersList.clear(); - bool first = true; - - while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) - { - // foreach point in the polygon - int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); - int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); - - if( first ) - { - first = false; - Start( GetLayer(), x, y, GetHatchStyle() ); - } - else - AppendCorner( x, y ); - } - - m_Kbool_Poly_Engine->EndPolygonGet(); - CloseLastContour(); - n_ext_cont++; - } - else if( aExtraPolyList ) // a new outside contour is found: create a new CPolyLine - { - polyline = new CPolyLine; - polyline->ImportSettings( this ); - aExtraPolyList->push_back( polyline ); // put it in array - bool first = true; - - while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) // read next external contour - { - int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); - int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); - - if( first ) - { - first = false; - polyline->Start( GetLayer(), x, y, GetHatchStyle() ); - } - else - polyline->AppendCorner( x, y ); - } - - m_Kbool_Poly_Engine->EndPolygonGet(); - polyline->CloseLastContour(); - n_ext_cont++; - } - } - - // now add cutouts to the corresponding CPolyLine(s) - for( unsigned ii = 0; ii < hole_array.size(); ii++ ) - { - hole = (std::vector*)hole_array[ii]; - polyline = NULL; - - if( n_ext_cont == 1 ) - { - polyline = this; - } - else - { - // find the polygon that contains this hole - // testing one corner inside is enought because a hole is entirely inside the polygon - // so we test only the first corner - int x = (*hole)[0]; - int y = (*hole)[1]; - - if( TestPointInside( x, y ) ) - polyline = this; - else if( aExtraPolyList ) - { - for( int ext_ic = 0; ext_icTestPointInside( x, y ) ) - { - polyline = (*aExtraPolyList)[ext_ic]; - break; - } - } - } - } - - if( !polyline ) - wxASSERT( 0 ); - else - { - for( unsigned ii = 0; ii< (*hole).size(); ii++ ) - { - int x = (*hole)[ii]; ii++; - int y = (*hole)[ii]; - polyline->AppendCorner( x, y ); - } - - polyline->CloseLastContour(); - } - } - - delete m_Kbool_Poly_Engine; - m_Kbool_Poly_Engine = NULL; - - // free hole list - for( unsigned ii = 0; ii < hole_array.size(); ii++ ) - delete (std::vector*)hole_array[ii]; - - return n_ext_cont; -} - - -/** - * Function AddPolygonsToBoolEng - * Add a CPolyLine to a kbool engine, preparing a boolean op between polygons - * @param aBooleng : pointer on a bool engine (handle a set of polygons) - * @param aGroup : group to fill (aGroup = GROUP_A or GROUP_B) operations are made between GROUP_A and GROUP_B - */ -int CPolyLine::AddPolygonsToBoolEng( Bool_Engine* aBooleng, GroupType aGroup ) -{ - int count = 0; - - /* Convert the current polyline contour to a kbool polygon: */ - MakeKboolPoly(); - - /* add the resulting kbool set of polygons to the current kcool engine */ - while( m_Kbool_Poly_Engine->StartPolygonGet() ) - { - if( aBooleng->StartPolygonAdd( GROUP_A ) ) - { - while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) - { - int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); - int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); - aBooleng->AddPoint( x, y ); - count++; - } - - aBooleng->EndPolygonAdd(); - } - m_Kbool_Poly_Engine->EndPolygonGet(); - } - - delete m_Kbool_Poly_Engine; - m_Kbool_Poly_Engine = NULL; - - return count; -} -/** - * Function MakeKboolPoly - * fill a kbool engine with a closed polyline contour - * normalize self-intersecting contours - * @return error: 0 if Ok, 1 if error - */ -int CPolyLine::MakeKboolPoly() -{ - if( m_Kbool_Poly_Engine ) - { - delete m_Kbool_Poly_Engine; - m_Kbool_Poly_Engine = NULL; - } - - if( !GetClosed() ) - return 1; // error - - int polycount = GetContoursCount(); - int last_contour = polycount - 1; - - for( int icont = 0; icont <= last_contour; icont++ ) - { - // Fill a kbool engine for this contour, - // and combine it with previous contours - Bool_Engine* booleng = new Bool_Engine(); - armBoolEng( booleng, false ); - - if( m_Kbool_Poly_Engine ) // a previous contour exists. Put it in new engine - { - while( m_Kbool_Poly_Engine->StartPolygonGet() ) - { - if( booleng->StartPolygonAdd( GROUP_A ) ) - { - while( m_Kbool_Poly_Engine->PolygonHasMorePoints() ) - { - int x = (int) m_Kbool_Poly_Engine->GetPolygonXPoint(); - int y = (int) m_Kbool_Poly_Engine->GetPolygonYPoint(); - booleng->AddPoint( x, y ); - } - - booleng->EndPolygonAdd(); - } - m_Kbool_Poly_Engine->EndPolygonGet(); - } - } - - int ic_st = GetContourStart( icont ); - int ic_end = GetContourEnd( icont ); - - if( !booleng->StartPolygonAdd( GROUP_B ) ) - { - wxASSERT( 0 ); - return 1; // error - } - - // Enter this contour to booleng - for( int ic = ic_st; ic <= ic_end; ic++ ) - { - int x1 = m_CornersList[ic].x; - int y1 = m_CornersList[ic].y; - booleng->AddPoint( x1, y1 ); - } - - // close list added to the bool engine - booleng->EndPolygonAdd(); - - /* now combine polygon to the previous polygons. - * note: the first polygon is the outline contour, and others are holes inside the first polygon - * The first polygon is ORed with nothing, but is is a trick to sort corners (vertex) - * clockwise with the kbool engine. - * Others polygons are substract to the outline and corners will be ordered counter clockwise - * by the kbool engine - */ - if( icont != 0 ) // substract hole to outside ( if the outline contour is take in account) - { - booleng->Do_Operation( BOOL_A_SUB_B ); - } - else // add outside or add holes if we do not use the outline contour - { - booleng->Do_Operation( BOOL_OR ); - } - - // now use result as new polygon (delete the old one if exists) - if( m_Kbool_Poly_Engine ) - delete m_Kbool_Poly_Engine; - - m_Kbool_Poly_Engine = booleng; - } - - return 0; -} - - -/** - * Function armBoolEng - * Initialise parameters used in kbool - * @param aBooleng = pointer to the Bool_Engine to initialise - * @param aConvertHoles = mode for holes when a boolean operation is made - * true: in resulting polygon, holes are linked into outer contours by double overlapping segments - * false: in resulting polygons, holes are not linked: they are separate polygons - */ -void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) -{ - // set some global vals to arm the boolean engine - - // input points are scaled up with GetDGrid() * GetGrid() - - // DGRID is only meant to make fractional parts of input data which - /* - * The input data scaled up with DGrid is related to the accuracy the user has in his input data. - * User data with a minimum accuracy of 0.001, means set the DGrid to 1000. - * The input data may contain data with a minimum accuracy much smaller, but by setting the DGrid - * everything smaller than 1/DGrid is rounded. - * - * DGRID is only meant to make fractional parts of input data which can be - * doubles, part of the integers used in vertexes within the boolean algorithm. - * And therefore DGRID bigger than 1 is not usefull, you would only loose accuracy. - * Within the algorithm all input data is multiplied with DGRID, and the result - * is rounded to an integer. - */ - double DGRID = 1000.0; // round coordinate X or Y value in calculations to this (initial value = 1000.0 in kbool example) - // kbool uses DGRID to convert float user units to integer - // kbool unit = (int)(user unit * DGRID) - // Note: in kicad, coordinates are already integer so DGRID could be set to 1 - // we can choose 1.0, - // but choose DGRID = 1000.0 solves some filling problems -// (perhaps because this allows a better precision in kbool internal calculations - - double MARGE = 1.0 / DGRID; // snap with in this range points to lines in the intersection routines - // should always be >= 1/DGRID a MARGE >= 10/DGRID is ok - // this is also used to remove small segments and to decide when - // two segments are in line. ( initial value = 0.001 ) - // For kicad we choose MARGE = 1/DGRID - - double CORRECTIONFACTOR = 0.0; // correct the polygons by this number: used in BOOL_CORRECTION operation - // this operation shrinks a polygon if CORRECTIONFACTOR < 0 - // or stretch it if CORRECTIONFACTOR > 0 - // the size change is CORRECTIONFACTOR (holes are correctly handled) - double CORRECTIONABER = 1.0; // the accuracy for the rounded shapes used in correction - double ROUNDFACTOR = 1.5; // when will we round the correction shape to a circle - double SMOOTHABER = 10.0; // accuracy when smoothing a polygon - double MAXLINEMERGE = 1000.0; // leave as is, segments of this length in smoothen - - - /* - * Grid makes sure that the integer data used within the algorithm has room for extra intersections - * smaller than the smallest number within the input data. - * The input data scaled up with DGrid is related to the accuracy the user has in his input data. - * Another scaling with Grid is applied on top of it to create space in the integer number for - * even smaller numbers. - */ - int GRID = (int) ( 10000.0 / DGRID ); // initial value = 10000 in kbool example but we use - - // 10000/DGRID because the scaling is made by DGRID - // on integer pcbnew units and the global scaling - // ( GRID*DGRID) must be < 30000 to avoid overflow - // in calculations (made in long long in kbool) - if( GRID <= 1 ) // Cannot be null! - GRID = 1; - - aBooleng->SetMarge( MARGE ); - aBooleng->SetGrid( GRID ); - aBooleng->SetDGrid( DGRID ); - aBooleng->SetCorrectionFactor( CORRECTIONFACTOR ); - aBooleng->SetCorrectionAber( CORRECTIONABER ); - aBooleng->SetSmoothAber( SMOOTHABER ); - aBooleng->SetMaxlinemerge( MAXLINEMERGE ); - aBooleng->SetRoundfactor( ROUNDFACTOR ); - aBooleng->SetWindingRule( true ); // This is the default kbool value - - if( aConvertHoles ) - { -#if 1 // Can be set to 1 for kbool version >= 2.1, must be set to 0 for previous versions - // SetAllowNonTopHoleLinking() exists only in kbool >= 2.1 - aBooleng->SetAllowNonTopHoleLinking( false ); // Default = true, but i have problems (filling errors) when true -#endif - aBooleng->SetLinkHoles( true ); // holes will be connected by double overlapping segments - aBooleng->SetOrientationEntryMode( false ); // all polygons are contours, not holes - } - else - { - aBooleng->SetLinkHoles( false ); // holes will not be connected by double overlapping segments - aBooleng->SetOrientationEntryMode( true ); // holes are entered counter clockwise - } } @@ -445,12 +38,119 @@ void armBoolEng( Bool_Engine* aBooleng, bool aConvertHoles ) * Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s) * @param aNewPolygonList = a std::vector reference where to store new CPolyLine * needed by the normalization - * @return the polygon count (always >= 1, becuse there is at lesat one polygon) + * @return the polygon count (always >= 1, because there is at least one polygon) * There are new polygons only if the polygon count is > 1 */ +#include "clipper.hpp" int CPolyLine::NormalizeAreaOutlines( std::vector* aNewPolygonList ) { - return NormalizeWithKbool( aNewPolygonList ); + ClipperLib::Polygon raw_polygon; + ClipperLib::Polygons normalized_polygons; + + unsigned corners_count = m_CornersList.size(); + + KI_POLYGON_SET polysholes; + KI_POLYGON_WITH_HOLES mainpoly; + std::vector cornerslist; + KI_POLYGON_WITH_HOLES_SET all_contours; + KI_POLYGON poly_tmp; + + // Normalize first contour + unsigned ic = 0; + while( ic < corners_count ) + { + const CPolyPt& corner = m_CornersList[ic++]; + raw_polygon.push_back( ClipperLib::IntPoint( corner.x, corner.y ) ); + + if( corner.end_contour ) + break; + } + ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons ); + + // enter main outline + for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ ) + { + ClipperLib::Polygon& polygon = normalized_polygons[ii]; + cornerslist.clear(); + for( unsigned jj = 0; jj < polygon.size(); jj++ ) + cornerslist.push_back( KI_POLY_POINT( (int)polygon[jj].X, (int)polygon[jj].Y ) ); + mainpoly.set( cornerslist.begin(), cornerslist.end() ); + all_contours.push_back( mainpoly ); + } + + // Enter holes + while( ic < corners_count ) + { + cornerslist.clear(); + raw_polygon.clear(); + normalized_polygons.clear(); + + // Normalize current hole and add it to hole list + while( ic < corners_count ) + { + const CPolyPt& corner = m_CornersList[ic++]; + raw_polygon.push_back( ClipperLib::IntPoint( corner.x, corner.y ) ); + + if( corner.end_contour ) + { + ClipperLib::SimplifyPolygon( raw_polygon, normalized_polygons ); + for( unsigned ii = 0; ii < normalized_polygons.size(); ii++ ) + { + ClipperLib::Polygon& polygon = normalized_polygons[ii]; + cornerslist.clear(); + for( unsigned jj = 0; jj < polygon.size(); jj++ ) + cornerslist.push_back( KI_POLY_POINT( (int)polygon[jj].X, (int)polygon[jj].Y ) ); + bpl::set_points( poly_tmp, cornerslist.begin(), cornerslist.end() ); + polysholes.push_back( poly_tmp ); + } + break; + } + } + } + all_contours -= polysholes; + + // copy polygon with holes to destination + RemoveAllContours(); + + #define outlines all_contours + + for( unsigned ii = 0; ii < outlines.size(); ii++ ) + { + CPolyLine* polyline = this; + if( ii > 0 ) + { + polyline = new CPolyLine; + polyline->ImportSettings( this ); + aNewPolygonList->push_back( polyline ); + } + + KI_POLYGON_WITH_HOLES& curr_poly = outlines[ii]; + KI_POLYGON_WITH_HOLES::iterator_type corner = curr_poly.begin(); + // enter main contour + while( corner != curr_poly.end() ) + { + polyline->AppendCorner( corner->x(), corner->y() ); + corner++; + } + polyline->CloseLastContour(); + + // add holes (set of polygons) + KI_POLYGON_WITH_HOLES::iterator_holes_type hole = curr_poly.begin_holes(); + while( hole != curr_poly.end_holes() ) + { + KI_POLYGON::iterator_type hole_corner = hole->begin(); + // create area with external contour: Recreate only area edges, NOT holes + while( hole_corner != hole->end() ) + { + polyline->AppendCorner( hole_corner->x(), hole_corner->y() ); + hole_corner++; + } + polyline->CloseLastContour(); + hole++; + } + } + + return outlines.size(); } /** @@ -862,10 +562,10 @@ CRect CPolyLine::GetCornerBounds() for( unsigned i = 0; i -#include +//#include #include #include // for wxPoint definition @@ -210,42 +210,11 @@ public: * Convert a self-intersecting polygon to one (or more) non self-intersecting polygon(s) * @param aNewPolygonList = a std::vector reference where to store new CPolyLine * needed by the normalization - * @return the polygon count (always >= 1, becuse there is at lesat one polygon) + * @return the polygon count (always >= 1, because there is at least one polygon) * There are new polygons only if the polygon count is > 1 */ int NormalizeAreaOutlines( std::vector* aNewPolygonList ); - // KBOOL functions - - /** - * Function AddPolygonsToBoolEng - * Add a CPolyLine to a kbool engine, preparing a boolean op between polygons - * @param aBooleng : pointer on a bool engine (handle a set of polygons) - * @param aGroup : group to fill (aGroup = GROUP_A or GROUP_B) operations are made between GROUP_A and GROUP_B - */ - int AddPolygonsToBoolEng( Bool_Engine* aBooleng, GroupType aGroup ); - - /** - * Function MakeKboolPoly - * fill a kbool engine with a closed polyline contour - * @return error: 0 if Ok, 1 if error - */ - int MakeKboolPoly(); - - /** - * Function NormalizeWithKbool - * Use the Kbool Library to clip contours: if outlines are crossing, the self-crossing polygon - * is converted to non self-crossing polygon by adding extra points at the crossing locations - * and reordering corners - * if more than one outside contour are found, extra CPolyLines will be created - * because copper areas have only one outside contour - * Therefore, if this results in new CPolyLines, return them as std::vector pa - * @param aExtraPolyList: pointer on a std::vector to store extra CPolyLines - * (when after normalization, there is more than one polygon with holes) - * @return number of contours, or -1 if error - */ - int NormalizeWithKbool( std::vector* aExtraPolyList ); - // Bezier Support void AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3 ); void AppendBezier( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 ); @@ -277,7 +246,7 @@ private: // and the len of eacvh segment // for DIAGONAL_FULL, the pitch is twice this value int m_utility; // a flag used in some calculations - Bool_Engine* m_Kbool_Poly_Engine; // polygons set in kbool engine data + public: std::vector m_CornersList; // array of points for corners std::vector m_HatchLines; // hatch lines showing the polygon area diff --git a/polygon/clipper.cpp b/polygon/clipper.cpp new file mode 100644 index 0000000000..621aa72b8f --- /dev/null +++ b/polygon/clipper.cpp @@ -0,0 +1,3424 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 4.8.5 * +* Date : 15 July 2012 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2012 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24–28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +/******************************************************************************* +* * +* This is a translation of the Delphi Clipper library and the naming style * +* used has retained a Delphi flavour. * +* * +*******************************************************************************/ + +#include "clipper.hpp" +#include +#include +#include +#include +#include +#include +#include + +namespace ClipperLib { + +static long64 const loRange = 1518500249; //sqrt(2^63 -1)/2 +static long64 const hiRange = 6521908912666391106LL; //sqrt(2^127 -1)/2 +static double const pi = 3.141592653589793238; +enum Direction { dRightToLeft, dLeftToRight }; + +#define HORIZONTAL (-1.0E+40) +#define TOLERANCE (1.0e-20) +#define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) +#define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b)) + +inline long64 Abs(long64 val) +{ + return val < 0 ? -val : val; +} +//------------------------------------------------------------------------------ + +//------------------------------------------------------------------------------ +// Int128 class (enables safe math on signed 64bit integers) +// eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1 +// Int128 val2((long64)9223372036854775807); +// Int128 val3 = val1 * val2; +// val3.AsString => "85070591730234615847396907784232501249" (8.5e+37) +//------------------------------------------------------------------------------ + +class Int128 +{ + public: + + Int128(long64 _lo = 0) + { + lo = _lo; + if (lo < 0) hi = -1; else hi = 0; + } + + Int128(const Int128 &val): hi(val.hi), lo(val.lo){} + + long64 operator = (const long64 &val) + { + lo = val; + if (lo < 0) hi = -1; else hi = 0; + return val; + } + + bool operator == (const Int128 &val) const + {return (hi == val.hi && lo == val.lo);} + + bool operator != (const Int128 &val) const + { return !(*this == val);} + + bool operator > (const Int128 &val) const + { + if (hi != val.hi) + return hi > val.hi; + else + return lo > val.lo; + } + + bool operator < (const Int128 &val) const + { + if (hi != val.hi) + return hi < val.hi; + else + return lo < val.lo; + } + + Int128& operator += (const Int128 &rhs) + { + hi += rhs.hi; + lo += rhs.lo; + if (ulong64(lo) < ulong64(rhs.lo)) hi++; + return *this; + } + + Int128 operator + (const Int128 &rhs) const + { + Int128 result(*this); + result+= rhs; + return result; + } + + Int128& operator -= (const Int128 &rhs) + { + Int128 tmp(rhs); + Negate(tmp); + *this += tmp; + return *this; + } + + //Int128 operator -() const + //{ + // Int128 result(*this); + // if (result.lo == 0) { + // if (result.hi != 0) result.hi = -1; + // } + // else { + // result.lo = -result.lo; + // result.hi = ~result.hi; + // } + // return result; + //} + + Int128 operator - (const Int128 &rhs) const + { + Int128 result(*this); + result -= rhs; + return result; + } + + Int128 operator * (const Int128 &rhs) const + { + if ( !(hi == 0 || hi == -1) || !(rhs.hi == 0 || rhs.hi == -1)) + throw "Int128 operator*: overflow error"; + bool negate = (hi < 0) != (rhs.hi < 0); + + Int128 tmp(*this); + if (tmp.hi < 0) Negate(tmp); + ulong64 int1Hi = ulong64(tmp.lo) >> 32; + ulong64 int1Lo = ulong64(tmp.lo & 0xFFFFFFFF); + + tmp = rhs; + if (tmp.hi < 0) Negate(tmp); + ulong64 int2Hi = ulong64(tmp.lo) >> 32; + ulong64 int2Lo = ulong64(tmp.lo & 0xFFFFFFFF); + + //nb: see comments in clipper.pas + ulong64 a = int1Hi * int2Hi; + ulong64 b = int1Lo * int2Lo; + ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; + + tmp.hi = long64(a + (c >> 32)); + tmp.lo = long64(c << 32); + tmp.lo += long64(b); + if (ulong64(tmp.lo) < b) tmp.hi++; + if (negate) Negate(tmp); + return tmp; + } + + Int128 operator/ (const Int128 &rhs) const + { + if (rhs.lo == 0 && rhs.hi == 0) + throw "Int128 operator/: divide by zero"; + bool negate = (rhs.hi < 0) != (hi < 0); + Int128 result(*this), denom(rhs); + if (result.hi < 0) Negate(result); + if (denom.hi < 0) Negate(denom); + if (denom > result) return Int128(0); //result is only a fraction of 1 + Negate(denom); + + Int128 p(0); + for (int i = 0; i < 128; ++i) + { + p.hi = p.hi << 1; + if (p.lo < 0) p.hi++; + p.lo = long64(p.lo) << 1; + if (result.hi < 0) p.lo++; + result.hi = result.hi << 1; + if (result.lo < 0) result.hi++; + result.lo = long64(result.lo) << 1; + Int128 p2(p); + p += denom; + if (p.hi < 0) p = p2; + else result.lo++; + } + if (negate) Negate(result); + return result; + } + + double AsDouble() const + { + const double shift64 = 18446744073709551616.0; //2^64 + const double bit64 = 9223372036854775808.0; + if (hi < 0) + { + Int128 tmp(*this); + Negate(tmp); + if (tmp.lo < 0) + return (double)tmp.lo - bit64 - tmp.hi * shift64; + else + return -(double)tmp.lo - tmp.hi * shift64; + } + else if (lo < 0) + return -(double)lo + bit64 + hi * shift64; + else + return (double)lo + (double)hi * shift64; + } + + //for bug testing ... + //std::string AsString() const + //{ + // std::string result; + // unsigned char r = 0; + // Int128 tmp(0), val(*this); + // if (hi < 0) Negate(val); + // result.resize(50); + // std::string::size_type i = result.size() -1; + // while (val.hi != 0 || val.lo != 0) + // { + // Div10(val, tmp, r); + // result[i--] = char('0' + r); + // val = tmp; + // } + // if (hi < 0) result[i--] = '-'; + // result.erase(0,i+1); + // if (result.size() == 0) result = "0"; + // return result; + //} + +private: + long64 hi; + long64 lo; + + static void Negate(Int128 &val) + { + if (val.lo == 0) { + if (val.hi != 0) val.hi = -val.hi;; + } + else { + val.lo = -val.lo; + val.hi = ~val.hi; + } + } + + //debugging only ... + //void Div10(const Int128 val, Int128& result, unsigned char & remainder) const + //{ + // remainder = 0; + // result = 0; + // for (int i = 63; i >= 0; --i) + // { + // if ((val.hi & ((long64)1 << i)) != 0) + // remainder = char((remainder * 2) + 1); else + // remainder *= char(2); + // if (remainder >= 10) + // { + // result.hi += ((long64)1 << i); + // remainder -= char(10); + // } + // } + // for (int i = 63; i >= 0; --i) + // { + // if ((val.lo & ((long64)1 << i)) != 0) + // remainder = char((remainder * 2) + 1); else + // remainder *= char(2); + // if (remainder >= 10) + // { + // result.lo += ((long64)1 << i); + // remainder -= char(10); + // } + // } + //} +}; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +bool FullRangeNeeded(const Polygon &pts) +{ + bool result = false; + for (Polygon::size_type i = 0; i < pts.size(); ++i) + { + if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange) + throw "Coordinate exceeds range bounds."; + else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange) + result = true; + } + return result; +} +//------------------------------------------------------------------------------ + +bool Orientation(const Polygon &poly) +{ + int highI = (int)poly.size() -1; + if (highI < 2) return false; + + int j = 0, jplus, jminus; + for (int i = 0; i <= highI; ++i) + { + if (poly[i].Y < poly[j].Y) continue; + if ((poly[i].Y > poly[j].Y || poly[i].X < poly[j].X)) j = i; + }; + if (j == highI) jplus = 0; + else jplus = j +1; + if (j == 0) jminus = highI; + else jminus = j -1; + + IntPoint vec1, vec2; + //get cross product of vectors of the edges adjacent to highest point ... + vec1.X = poly[j].X - poly[jminus].X; + vec1.Y = poly[j].Y - poly[jminus].Y; + vec2.X = poly[jplus].X - poly[j].X; + vec2.Y = poly[jplus].Y - poly[j].Y; + + if (Abs(vec1.X) > loRange || Abs(vec1.Y) > loRange || + Abs(vec2.X) > loRange || Abs(vec2.Y) > loRange) + { + if (Abs(vec1.X) > hiRange || Abs(vec1.Y) > hiRange || + Abs(vec2.X) > hiRange || Abs(vec2.Y) > hiRange) + throw "Coordinate exceeds range bounds."; + Int128 cross = Int128(vec1.X) * Int128(vec2.Y) - + Int128(vec2.X) * Int128(vec1.Y); + return cross > 0; + } + else + return (vec1.X * vec2.Y - vec2.X * vec1.Y) > 0; +} +//------------------------------------------------------------------------------ + +inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2) +{ + return ( pt1.X == pt2.X && pt1.Y == pt2.Y ); +} +//------------------------------------------------------------------------------ + +bool Orientation(OutRec *outRec, bool UseFullInt64Range) +{ + //first make sure bottomPt is correctly assigned ... + OutPt *opBottom = outRec->pts, *op = outRec->pts->next; + while (op != outRec->pts) + { + if (op->pt.Y >= opBottom->pt.Y) + { + if (op->pt.Y > opBottom->pt.Y || op->pt.X < opBottom->pt.X) + opBottom = op; + } + op = op->next; + } + outRec->bottomPt = opBottom; + opBottom->idx = outRec->idx; + + op = opBottom; + //find vertices either side of bottomPt (skipping duplicate points) .... + OutPt *opPrev = op->prev; + OutPt *opNext = op->next; + while (op != opPrev && PointsEqual(op->pt, opPrev->pt)) + opPrev = opPrev->prev; + while (op != opNext && PointsEqual(op->pt, opNext->pt)) + opNext = opNext->next; + + IntPoint ip1, ip2; + ip1.X = op->pt.X - opPrev->pt.X; + ip1.Y = op->pt.Y - opPrev->pt.Y; + ip2.X = opNext->pt.X - op->pt.X; + ip2.Y = opNext->pt.Y - op->pt.Y; + + if (UseFullInt64Range) + return Int128(ip1.X) * Int128(ip2.Y) - Int128(ip2.X) * Int128(ip1.Y) > 0; + else + return (ip1.X * ip2.Y - ip2.X * ip1.Y) > 0; +} +//------------------------------------------------------------------------------ + +double Area(const Polygon &poly) +{ + int highI = (int)poly.size() -1; + if (highI < 2) return 0; + + if (FullRangeNeeded(poly)) { + Int128 a; + a = (Int128(poly[highI].X) * Int128(poly[0].Y)) - + Int128(poly[0].X) * Int128(poly[highI].Y); + for (int i = 0; i < highI; ++i) + a += Int128(poly[i].X) * Int128(poly[i+1].Y) - + Int128(poly[i+1].X) * Int128(poly[i].Y); + return a.AsDouble() / 2; + } + else + { + double a; + a = (double)poly[highI].X * poly[0].Y - (double)poly[0].X * poly[highI].Y; + for (int i = 0; i < highI; ++i) + a += (double)poly[i].X * poly[i+1].Y - (double)poly[i+1].X * poly[i].Y; + return a/2; + } +} +//------------------------------------------------------------------------------ + +double Area(const OutRec &outRec, bool UseFullInt64Range) +{ + OutPt *op = outRec.pts; + if (UseFullInt64Range) { + Int128 a(0); + do { + a += (Int128(op->prev->pt.X) * Int128(op->pt.Y)) - + Int128(op->pt.X) * Int128(op->prev->pt.Y); + op = op->next; + } while (op != outRec.pts); + return a.AsDouble() / 2; + } + else + { + double a = 0; + do { + a += (op->prev->pt.X * op->pt.Y) - (op->pt.X * op->prev->pt.Y); + op = op->next; + } while (op != outRec.pts); + return a/2; + } +} +//------------------------------------------------------------------------------ + +bool PointIsVertex(const IntPoint &pt, OutPt *pp) +{ + OutPt *pp2 = pp; + do + { + if (PointsEqual(pp2->pt, pt)) return true; + pp2 = pp2->next; + } + while (pp2 != pp); + return false; +} +//------------------------------------------------------------------------------ + +bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range) +{ + OutPt *pp2 = pp; + bool result = false; + if (UseFullInt64Range) { + do + { + if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) || + ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) && + Int128(pt.X - pp2->pt.X) < (Int128(pp2->prev->pt.X - pp2->pt.X) * + Int128(pt.Y - pp2->pt.Y)) / Int128(pp2->prev->pt.Y - pp2->pt.Y)) + result = !result; + pp2 = pp2->next; + } + while (pp2 != pp); + } + else + { + do + { + if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) || + ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) && + (pt.X < (pp2->prev->pt.X - pp2->pt.X) * (pt.Y - pp2->pt.Y) / + (pp2->prev->pt.Y - pp2->pt.Y) + pp2->pt.X )) result = !result; + pp2 = pp2->next; + } + while (pp2 != pp); + } + return result; +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range) +{ + if (UseFullInt64Range) + return Int128(e1.ytop - e1.ybot) * Int128(e2.xtop - e2.xbot) == + Int128(e1.xtop - e1.xbot) * Int128(e2.ytop - e2.ybot); + else return (e1.ytop - e1.ybot)*(e2.xtop - e2.xbot) == + (e1.xtop - e1.xbot)*(e2.ytop - e2.ybot); +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, bool UseFullInt64Range) +{ + if (UseFullInt64Range) + return Int128(pt1.Y-pt2.Y) * Int128(pt2.X-pt3.X) == + Int128(pt1.X-pt2.X) * Int128(pt2.Y-pt3.Y); + else return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); +} +//------------------------------------------------------------------------------ + +bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, + const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range) +{ + if (UseFullInt64Range) + return Int128(pt1.Y-pt2.Y) * Int128(pt3.X-pt4.X) == + Int128(pt1.X-pt2.X) * Int128(pt3.Y-pt4.Y); + else return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); +} +//------------------------------------------------------------------------------ + +double GetDx(const IntPoint pt1, const IntPoint pt2) +{ + return (pt1.Y == pt2.Y) ? + HORIZONTAL : (double)(pt2.X - pt1.X) / (double)(pt2.Y - pt1.Y); +} +//--------------------------------------------------------------------------- + +void SetDx(TEdge &e) +{ + if (e.ybot == e.ytop) e.dx = HORIZONTAL; + else e.dx = (double)(e.xtop - e.xbot) / (double)(e.ytop - e.ybot); +} +//--------------------------------------------------------------------------- + +void SwapSides(TEdge &edge1, TEdge &edge2) +{ + EdgeSide side = edge1.side; + edge1.side = edge2.side; + edge2.side = side; +} +//------------------------------------------------------------------------------ + +void SwapPolyIndexes(TEdge &edge1, TEdge &edge2) +{ + int outIdx = edge1.outIdx; + edge1.outIdx = edge2.outIdx; + edge2.outIdx = outIdx; +} +//------------------------------------------------------------------------------ + +inline long64 Round(double val) +{ + return (val < 0) ? + static_cast(val - 0.5) : static_cast(val + 0.5); +} +//------------------------------------------------------------------------------ + +long64 TopX(TEdge &edge, const long64 currentY) +{ + return ( currentY == edge.ytop ) ? + edge.xtop : edge.xbot + Round(edge.dx *(currentY - edge.ybot)); +} +//------------------------------------------------------------------------------ + +long64 TopX(const IntPoint pt1, const IntPoint pt2, const long64 currentY) +{ + //preconditions: pt1.Y <> pt2.Y and pt1.Y > pt2.Y + if (currentY >= pt1.Y) return pt1.X; + else if (currentY == pt2.Y) return pt2.X; + else if (pt1.X == pt2.X) return pt1.X; + else + { + double q = (double)(pt1.X-pt2.X)/(double)(pt1.Y-pt2.Y); + return Round(pt1.X + (currentY - pt1.Y) *q); + } +} +//------------------------------------------------------------------------------ + +bool IntersectPoint(TEdge &edge1, TEdge &edge2, + IntPoint &ip, bool UseFullInt64Range) +{ + double b1, b2; + if (SlopesEqual(edge1, edge2, UseFullInt64Range)) return false; + else if (NEAR_ZERO(edge1.dx)) + { + ip.X = edge1.xbot; + if (NEAR_EQUAL(edge2.dx, HORIZONTAL)) + { + ip.Y = edge2.ybot; + } else + { + b2 = edge2.ybot - (edge2.xbot/edge2.dx); + ip.Y = Round(ip.X/edge2.dx + b2); + } + } + else if (NEAR_ZERO(edge2.dx)) + { + ip.X = edge2.xbot; + if (NEAR_EQUAL(edge1.dx, HORIZONTAL)) + { + ip.Y = edge1.ybot; + } else + { + b1 = edge1.ybot - (edge1.xbot/edge1.dx); + ip.Y = Round(ip.X/edge1.dx + b1); + } + } else + { + b1 = edge1.xbot - edge1.ybot * edge1.dx; + b2 = edge2.xbot - edge2.ybot * edge2.dx; + b2 = (b2-b1)/(edge1.dx - edge2.dx); + ip.Y = Round(b2); + ip.X = Round(edge1.dx * b2 + b1); + } + + return + //can be *so close* to the top of one edge that the rounded Y equals one ytop ... + (ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > edge2.tmpX) || + (ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > edge2.tmpX) || + (ip.Y > edge1.ytop && ip.Y > edge2.ytop); +} +//------------------------------------------------------------------------------ + +void ReversePolyPtLinks(OutPt &pp) +{ + OutPt *pp1, *pp2; + pp1 = &pp; + do { + pp2 = pp1->next; + pp1->next = pp1->prev; + pp1->prev = pp2; + pp1 = pp2; + } while( pp1 != &pp ); +} +//------------------------------------------------------------------------------ + +void DisposeOutPts(OutPt*& pp) +{ + if (pp == 0) return; + pp->prev->next = 0; + while( pp ) + { + OutPt *tmpPp = pp; + pp = pp->next; + delete tmpPp ; + } +} +//------------------------------------------------------------------------------ + +void InitEdge(TEdge *e, TEdge *eNext, + TEdge *ePrev, const IntPoint &pt, PolyType polyType) +{ + std::memset( e, 0, sizeof( TEdge )); + + e->next = eNext; + e->prev = ePrev; + e->xcurr = pt.X; + e->ycurr = pt.Y; + if (e->ycurr >= e->next->ycurr) + { + e->xbot = e->xcurr; + e->ybot = e->ycurr; + e->xtop = e->next->xcurr; + e->ytop = e->next->ycurr; + e->windDelta = 1; + } else + { + e->xtop = e->xcurr; + e->ytop = e->ycurr; + e->xbot = e->next->xcurr; + e->ybot = e->next->ycurr; + e->windDelta = -1; + } + SetDx(*e); + e->polyType = polyType; + e->outIdx = -1; +} +//------------------------------------------------------------------------------ + +inline void SwapX(TEdge &e) +{ + //swap horizontal edges' top and bottom x's so they follow the natural + //progression of the bounds - ie so their xbots will align with the + //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] + e.xcurr = e.xtop; + e.xtop = e.xbot; + e.xbot = e.xcurr; +} +//------------------------------------------------------------------------------ + +void SwapPoints(IntPoint &pt1, IntPoint &pt2) +{ + IntPoint tmp = pt1; + pt1 = pt2; + pt2 = tmp; +} +//------------------------------------------------------------------------------ + +bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, + IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) +{ + //precondition: segments are colinear. + if ( pt1a.Y == pt1b.Y || Abs((pt1a.X - pt1b.X)/(pt1a.Y - pt1b.Y)) > 1 ) + { + if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b); + if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b); + if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b; + return pt1.X < pt2.X; + } else + { + if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b); + if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b); + if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a; + if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b; + return pt1.Y > pt2.Y; + } +} +//------------------------------------------------------------------------------ + +bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) +{ + OutPt *p = btmPt1->prev; + while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->prev; + double dx1p = std::fabs(GetDx(btmPt1->pt, p->pt)); + p = btmPt1->next; + while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->next; + double dx1n = std::fabs(GetDx(btmPt1->pt, p->pt)); + + p = btmPt2->prev; + while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->prev; + double dx2p = std::fabs(GetDx(btmPt2->pt, p->pt)); + p = btmPt2->next; + while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->next; + double dx2n = std::fabs(GetDx(btmPt2->pt, p->pt)); + return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); +} +//------------------------------------------------------------------------------ + +OutPt* GetBottomPt(OutPt *pp) +{ + OutPt* dups = 0; + OutPt* p = pp->next; + while (p != pp) + { + if (p->pt.Y > pp->pt.Y) + { + pp = p; + dups = 0; + } + else if (p->pt.Y == pp->pt.Y && p->pt.X <= pp->pt.X) + { + if (p->pt.X < pp->pt.X) + { + dups = 0; + pp = p; + } else + { + if (p->next != pp && p->prev != pp) dups = p; + } + } + p = p->next; + } + if (dups) + { + //there appears to be at least 2 vertices at bottomPt so ... + while (dups != p) + { + if (!FirstIsBottomPt(p, dups)) pp = dups; + dups = dups->next; + while (!PointsEqual(dups->pt, pp->pt)) dups = dups->next; + } + } + return pp; +} +//------------------------------------------------------------------------------ + +bool FindSegment(OutPt* &pp, IntPoint &pt1, IntPoint &pt2) +{ + //outPt1 & outPt2 => the overlap segment (if the function returns true) + if (!pp) return false; + OutPt* pp2 = pp; + IntPoint pt1a = pt1, pt2a = pt2; + do + { + if (SlopesEqual(pt1a, pt2a, pp->pt, pp->prev->pt, true) && + SlopesEqual(pt1a, pt2a, pp->pt, true) && + GetOverlapSegment(pt1a, pt2a, pp->pt, pp->prev->pt, pt1, pt2)) + return true; + pp = pp->next; + } + while (pp != pp2); + return false; +} +//------------------------------------------------------------------------------ + +bool Pt3IsBetweenPt1AndPt2(const IntPoint pt1, + const IntPoint pt2, const IntPoint pt3) +{ + if (PointsEqual(pt1, pt3) || PointsEqual(pt2, pt3)) return true; + else if (pt1.X != pt2.X) return (pt1.X < pt3.X) == (pt3.X < pt2.X); + else return (pt1.Y < pt3.Y) == (pt3.Y < pt2.Y); +} +//------------------------------------------------------------------------------ + +OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint pt) +{ + if (p1 == p2) throw "JoinError"; + OutPt* result = new OutPt; + result->pt = pt; + if (p2 == p1->next) + { + p1->next = result; + p2->prev = result; + result->next = p2; + result->prev = p1; + } else + { + p2->next = result; + p1->prev = result; + result->next = p1; + result->prev = p2; + } + return result; +} + +//------------------------------------------------------------------------------ +// ClipperBase class methods ... +//------------------------------------------------------------------------------ + +ClipperBase::ClipperBase() //constructor +{ + m_MinimaList = 0; + m_CurrentLM = 0; + m_UseFullRange = true; +} +//------------------------------------------------------------------------------ + +ClipperBase::~ClipperBase() //destructor +{ + Clear(); +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType) +{ + int len = (int)pg.size(); + if (len < 3) return false; + Polygon p(len); + p[0] = pg[0]; + int j = 0; + + long64 maxVal; + if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange; + + for (int i = 0; i < len; ++i) + { + if (Abs(pg[i].X) > maxVal || Abs(pg[i].Y) > maxVal) + { + if (Abs(pg[i].X) > hiRange || Abs(pg[i].Y) > hiRange) + throw "Coordinate exceeds range bounds"; + maxVal = hiRange; + m_UseFullRange = true; + } + + if (i == 0 || PointsEqual(p[j], pg[i])) continue; + else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange)) + { + if (PointsEqual(p[j-1], pg[i])) j--; + } else j++; + p[j] = pg[i]; + } + if (j < 2) return false; + + len = j+1; + while (len > 2) + { + //nb: test for point equality before testing slopes ... + if (PointsEqual(p[j], p[0])) j--; + else if (PointsEqual(p[0], p[1]) || + SlopesEqual(p[j], p[0], p[1], m_UseFullRange)) + p[0] = p[j--]; + else if (SlopesEqual(p[j-1], p[j], p[0], m_UseFullRange)) j--; + else if (SlopesEqual(p[0], p[1], p[2], m_UseFullRange)) + { + for (int i = 2; i <= j; ++i) p[i-1] = p[i]; + j--; + } + else break; + len--; + } + if (len < 3) return false; + + //create a new edge array ... + TEdge *edges = new TEdge [len]; + m_edges.push_back(edges); + + //convert vertices to a double-linked-list of edges and initialize ... + edges[0].xcurr = p[0].X; + edges[0].ycurr = p[0].Y; + InitEdge(&edges[len-1], &edges[0], &edges[len-2], p[len-1], polyType); + for (int i = len-2; i > 0; --i) + InitEdge(&edges[i], &edges[i+1], &edges[i-1], p[i], polyType); + InitEdge(&edges[0], &edges[1], &edges[len-1], p[0], polyType); + + //reset xcurr & ycurr and find 'eHighest' (given the Y axis coordinates + //increase downward so the 'highest' edge will have the smallest ytop) ... + TEdge *e = &edges[0]; + TEdge *eHighest = e; + do + { + e->xcurr = e->xbot; + e->ycurr = e->ybot; + if (e->ytop < eHighest->ytop) eHighest = e; + e = e->next; + } + while ( e != &edges[0]); + + //make sure eHighest is positioned so the following loop works safely ... + if (eHighest->windDelta > 0) eHighest = eHighest->next; + if (NEAR_EQUAL(eHighest->dx, HORIZONTAL)) eHighest = eHighest->next; + + //finally insert each local minima ... + e = eHighest; + do { + e = AddBoundsToLML(e); + } + while( e != eHighest ); + return true; +} +//------------------------------------------------------------------------------ + +void ClipperBase::InsertLocalMinima(LocalMinima *newLm) +{ + if( ! m_MinimaList ) + { + m_MinimaList = newLm; + } + else if( newLm->Y >= m_MinimaList->Y ) + { + newLm->next = m_MinimaList; + m_MinimaList = newLm; + } else + { + LocalMinima* tmpLm = m_MinimaList; + while( tmpLm->next && ( newLm->Y < tmpLm->next->Y ) ) + tmpLm = tmpLm->next; + newLm->next = tmpLm->next; + tmpLm->next = newLm; + } +} +//------------------------------------------------------------------------------ + +TEdge* ClipperBase::AddBoundsToLML(TEdge *e) +{ + //Starting at the top of one bound we progress to the bottom where there's + //a local minima. We then go to the top of the next bound. These two bounds + //form the left and right (or right and left) bounds of the local minima. + e->nextInLML = 0; + e = e->next; + for (;;) + { + if (NEAR_EQUAL(e->dx, HORIZONTAL)) + { + //nb: proceed through horizontals when approaching from their right, + // but break on horizontal minima if approaching from their left. + // This ensures 'local minima' are always on the left of horizontals. + if (e->next->ytop < e->ytop && e->next->xbot > e->prev->xbot) break; + if (e->xtop != e->prev->xbot) SwapX(*e); + e->nextInLML = e->prev; + } + else if (e->ycurr == e->prev->ycurr) break; + else e->nextInLML = e->prev; + e = e->next; + } + + //e and e.prev are now at a local minima ... + LocalMinima* newLm = new LocalMinima; + newLm->next = 0; + newLm->Y = e->prev->ybot; + + if ( NEAR_EQUAL(e->dx, HORIZONTAL) ) //horizontal edges never start a left bound + { + if (e->xbot != e->prev->xbot) SwapX(*e); + newLm->leftBound = e->prev; + newLm->rightBound = e; + } else if (e->dx < e->prev->dx) + { + newLm->leftBound = e->prev; + newLm->rightBound = e; + } else + { + newLm->leftBound = e; + newLm->rightBound = e->prev; + } + newLm->leftBound->side = esLeft; + newLm->rightBound->side = esRight; + InsertLocalMinima( newLm ); + + for (;;) + { + if ( e->next->ytop == e->ytop && !NEAR_EQUAL(e->next->dx, HORIZONTAL) ) break; + e->nextInLML = e->next; + e = e->next; + if ( NEAR_EQUAL(e->dx, HORIZONTAL) && e->xbot != e->prev->xtop) SwapX(*e); + } + return e->next; +} +//------------------------------------------------------------------------------ + +bool ClipperBase::AddPolygons(const Polygons &ppg, PolyType polyType) +{ + bool result = false; + for (Polygons::size_type i = 0; i < ppg.size(); ++i) + if (AddPolygon(ppg[i], polyType)) result = true; + return result; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Clear() +{ + DisposeLocalMinimaList(); + for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) delete [] m_edges[i]; + m_edges.clear(); + m_UseFullRange = false; +} +//------------------------------------------------------------------------------ + +void ClipperBase::Reset() +{ + m_CurrentLM = m_MinimaList; + if( !m_CurrentLM ) return; //ie nothing to process + + //reset all edges ... + LocalMinima* lm = m_MinimaList; + while( lm ) + { + TEdge* e = lm->leftBound; + while( e ) + { + e->xcurr = e->xbot; + e->ycurr = e->ybot; + e->side = esLeft; + e->outIdx = -1; + e = e->nextInLML; + } + e = lm->rightBound; + while( e ) + { + e->xcurr = e->xbot; + e->ycurr = e->ybot; + e->side = esRight; + e->outIdx = -1; + e = e->nextInLML; + } + lm = lm->next; + } +} +//------------------------------------------------------------------------------ + +void ClipperBase::DisposeLocalMinimaList() +{ + while( m_MinimaList ) + { + LocalMinima* tmpLm = m_MinimaList->next; + delete m_MinimaList; + m_MinimaList = tmpLm; + } + m_CurrentLM = 0; +} +//------------------------------------------------------------------------------ + +void ClipperBase::PopLocalMinima() +{ + if( ! m_CurrentLM ) return; + m_CurrentLM = m_CurrentLM->next; +} +//------------------------------------------------------------------------------ + +IntRect ClipperBase::GetBounds() +{ + IntRect result; + LocalMinima* lm = m_MinimaList; + if (!lm) + { + result.left = result.top = result.right = result.bottom = 0; + return result; + } + result.left = lm->leftBound->xbot; + result.top = lm->leftBound->ybot; + result.right = lm->leftBound->xbot; + result.bottom = lm->leftBound->ybot; + while (lm) + { + if (lm->leftBound->ybot > result.bottom) + result.bottom = lm->leftBound->ybot; + TEdge* e = lm->leftBound; + for (;;) { + TEdge* bottomE = e; + while (e->nextInLML) + { + if (e->xbot < result.left) result.left = e->xbot; + if (e->xbot > result.right) result.right = e->xbot; + e = e->nextInLML; + } + if (e->xbot < result.left) result.left = e->xbot; + if (e->xbot > result.right) result.right = e->xbot; + if (e->xtop < result.left) result.left = e->xtop; + if (e->xtop > result.right) result.right = e->xtop; + if (e->ytop < result.top) result.top = e->ytop; + + if (bottomE == lm->leftBound) e = lm->rightBound; + else break; + } + lm = lm->next; + } + return result; +} + + +//------------------------------------------------------------------------------ +// TClipper methods ... +//------------------------------------------------------------------------------ + +Clipper::Clipper() : ClipperBase() //constructor +{ + m_Scanbeam = 0; + m_ActiveEdges = 0; + m_SortedEdges = 0; + m_IntersectNodes = 0; + m_ExecuteLocked = false; + m_UseFullRange = false; + m_ReverseOutput = false; +} +//------------------------------------------------------------------------------ + +Clipper::~Clipper() //destructor +{ + Clear(); + DisposeScanbeamList(); +} +//------------------------------------------------------------------------------ + +void Clipper::Clear() +{ + if (m_edges.size() == 0) return; //avoids problems with ClipperBase destructor + DisposeAllPolyPts(); + ClipperBase::Clear(); +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeScanbeamList() +{ + while ( m_Scanbeam ) { + Scanbeam* sb2 = m_Scanbeam->next; + delete m_Scanbeam; + m_Scanbeam = sb2; + } +} +//------------------------------------------------------------------------------ + +void Clipper::Reset() +{ + ClipperBase::Reset(); + m_Scanbeam = 0; + m_ActiveEdges = 0; + m_SortedEdges = 0; + DisposeAllPolyPts(); + LocalMinima* lm = m_MinimaList; + while (lm) + { + InsertScanbeam(lm->Y); + InsertScanbeam(lm->leftBound->ytop); + lm = lm->next; + } +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, Polygons &solution, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + m_ExecuteLocked = true; + solution.resize(0); + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + bool succeeded = ExecuteInternal(false); + if (succeeded) BuildResult(solution); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +bool Clipper::Execute(ClipType clipType, ExPolygons &solution, + PolyFillType subjFillType, PolyFillType clipFillType) +{ + if( m_ExecuteLocked ) return false; + m_ExecuteLocked = true; + solution.resize(0); + m_SubjFillType = subjFillType; + m_ClipFillType = clipFillType; + m_ClipType = clipType; + bool succeeded = ExecuteInternal(true); + if (succeeded) BuildResultEx(solution); + m_ExecuteLocked = false; + return succeeded; +} +//------------------------------------------------------------------------------ + +bool PolySort(OutRec *or1, OutRec *or2) +{ + if (or1 == or2) return false; + if (!or1->pts || !or2->pts) + { + if (or1->pts != or2->pts) + { + return or1->pts ? true : false; + } + else return false; + } + int i1, i2; + if (or1->isHole) + i1 = or1->FirstLeft->idx; else + i1 = or1->idx; + if (or2->isHole) + i2 = or2->FirstLeft->idx; else + i2 = or2->idx; + int result = i1 - i2; + if (result == 0 && (or1->isHole != or2->isHole)) + { + return or1->isHole ? false : true; + } + else return result < 0; +} +//------------------------------------------------------------------------------ + +OutRec* FindAppendLinkEnd(OutRec *outRec) +{ + while (outRec->AppendLink) outRec = outRec->AppendLink; + return outRec; +} +//------------------------------------------------------------------------------ + +void Clipper::FixHoleLinkage(OutRec *outRec) +{ + OutRec *tmp; + if (outRec->bottomPt) + tmp = m_PolyOuts[outRec->bottomPt->idx]->FirstLeft; + else + tmp = outRec->FirstLeft; + if (outRec == tmp) throw clipperException("HoleLinkage error"); + + if (tmp) + { + if (tmp->AppendLink) tmp = FindAppendLinkEnd(tmp); + if (tmp == outRec) tmp = 0; + else if (tmp->isHole) + { + FixHoleLinkage(tmp); + tmp = tmp->FirstLeft; + } + } + outRec->FirstLeft = tmp; + if (!tmp) outRec->isHole = false; + outRec->AppendLink = 0; +} +//------------------------------------------------------------------------------ + +bool Clipper::ExecuteInternal(bool fixHoleLinkages) +{ + bool succeeded; + try { + Reset(); + if (!m_CurrentLM ) return true; + long64 botY = PopScanbeam(); + do { + InsertLocalMinimaIntoAEL(botY); + ClearHorzJoins(); + ProcessHorizontals(); + long64 topY = PopScanbeam(); + succeeded = ProcessIntersections(botY, topY); + if (!succeeded) break; + ProcessEdgesAtTopOfScanbeam(topY); + botY = topY; + } while( m_Scanbeam ); + } + catch(...) { + succeeded = false; + } + + if (succeeded) + { + //tidy up output polygons and fix orientations where necessary ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *outRec = m_PolyOuts[i]; + if (!outRec->pts) continue; + FixupOutPolygon(*outRec); + if (!outRec->pts) continue; + if (outRec->isHole && fixHoleLinkages) FixHoleLinkage(outRec); + + if (outRec->bottomPt == outRec->bottomFlag && + (Orientation(outRec, m_UseFullRange) != (Area(*outRec, m_UseFullRange) > 0))) + { + DisposeBottomPt(*outRec); + FixupOutPolygon(*outRec); + }; + + if (outRec->isHole == + (m_ReverseOutput ^ Orientation(outRec, m_UseFullRange))) + ReversePolyPtLinks(*outRec->pts); + } + + JoinCommonEdges(fixHoleLinkages); + if (fixHoleLinkages) + std::sort(m_PolyOuts.begin(), m_PolyOuts.end(), PolySort); + } + + ClearJoins(); + ClearHorzJoins(); + return succeeded; +} +//------------------------------------------------------------------------------ + +void Clipper::InsertScanbeam(const long64 Y) +{ + if( !m_Scanbeam ) + { + m_Scanbeam = new Scanbeam; + m_Scanbeam->next = 0; + m_Scanbeam->Y = Y; + } + else if( Y > m_Scanbeam->Y ) + { + Scanbeam* newSb = new Scanbeam; + newSb->Y = Y; + newSb->next = m_Scanbeam; + m_Scanbeam = newSb; + } else + { + Scanbeam* sb2 = m_Scanbeam; + while( sb2->next && ( Y <= sb2->next->Y ) ) sb2 = sb2->next; + if( Y == sb2->Y ) return; //ie ignores duplicates + Scanbeam* newSb = new Scanbeam; + newSb->Y = Y; + newSb->next = sb2->next; + sb2->next = newSb; + } +} +//------------------------------------------------------------------------------ + +long64 Clipper::PopScanbeam() +{ + long64 Y = m_Scanbeam->Y; + Scanbeam* sb2 = m_Scanbeam; + m_Scanbeam = m_Scanbeam->next; + delete sb2; + return Y; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeAllPolyPts(){ + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + DisposeOutRec(i); + m_PolyOuts.clear(); +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeOutRec(PolyOutList::size_type index) +{ + OutRec *outRec = m_PolyOuts[index]; + if (outRec->pts) DisposeOutPts(outRec->pts); + delete outRec; + m_PolyOuts[index] = 0; +} +//------------------------------------------------------------------------------ + +void Clipper::SetWindingCount(TEdge &edge) +{ + TEdge *e = edge.prevInAEL; + //find the edge of the same polytype that immediately preceeds 'edge' in AEL + while ( e && e->polyType != edge.polyType ) e = e->prevInAEL; + if ( !e ) + { + edge.windCnt = edge.windDelta; + edge.windCnt2 = 0; + e = m_ActiveEdges; //ie get ready to calc windCnt2 + } else if ( IsEvenOddFillType(edge) ) + { + //EvenOdd filling ... + edge.windCnt = 1; + edge.windCnt2 = e->windCnt2; + e = e->nextInAEL; //ie get ready to calc windCnt2 + } else + { + //nonZero, Positive or Negative filling ... + if ( e->windCnt * e->windDelta < 0 ) + { + if (Abs(e->windCnt) > 1) + { + if (e->windDelta * edge.windDelta < 0) edge.windCnt = e->windCnt; + else edge.windCnt = e->windCnt + edge.windDelta; + } else + edge.windCnt = e->windCnt + e->windDelta + edge.windDelta; + } else + { + if ( Abs(e->windCnt) > 1 && e->windDelta * edge.windDelta < 0) + edge.windCnt = e->windCnt; + else if ( e->windCnt + edge.windDelta == 0 ) + edge.windCnt = e->windCnt; + else edge.windCnt = e->windCnt + edge.windDelta; + } + edge.windCnt2 = e->windCnt2; + e = e->nextInAEL; //ie get ready to calc windCnt2 + } + + //update windCnt2 ... + if ( IsEvenOddAltFillType(edge) ) + { + //EvenOdd filling ... + while ( e != &edge ) + { + edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0; + e = e->nextInAEL; + } + } else + { + //nonZero, Positive or Negative filling ... + while ( e != &edge ) + { + edge.windCnt2 += e->windDelta; + e = e->nextInAEL; + } + } +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddFillType(const TEdge& edge) const +{ + if (edge.polyType == ptSubject) + return m_SubjFillType == pftEvenOdd; else + return m_ClipFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const +{ + if (edge.polyType == ptSubject) + return m_ClipFillType == pftEvenOdd; else + return m_SubjFillType == pftEvenOdd; +} +//------------------------------------------------------------------------------ + +bool Clipper::IsContributing(const TEdge& edge) const +{ + PolyFillType pft, pft2; + if (edge.polyType == ptSubject) + { + pft = m_SubjFillType; + pft2 = m_ClipFillType; + } else + { + pft = m_ClipFillType; + pft2 = m_SubjFillType; + } + + switch(pft) + { + case pftEvenOdd: + case pftNonZero: + if (Abs(edge.windCnt) != 1) return false; + break; + case pftPositive: + if (edge.windCnt != 1) return false; + break; + default: //pftNegative + if (edge.windCnt != -1) return false; + } + + switch(m_ClipType) + { + case ctIntersection: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.windCnt2 != 0); + case pftPositive: + return (edge.windCnt2 > 0); + default: + return (edge.windCnt2 < 0); + } + case ctUnion: + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.windCnt2 == 0); + case pftPositive: + return (edge.windCnt2 <= 0); + default: + return (edge.windCnt2 >= 0); + } + case ctDifference: + if (edge.polyType == ptSubject) + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.windCnt2 == 0); + case pftPositive: + return (edge.windCnt2 <= 0); + default: + return (edge.windCnt2 >= 0); + } + else + switch(pft2) + { + case pftEvenOdd: + case pftNonZero: + return (edge.windCnt2 != 0); + case pftPositive: + return (edge.windCnt2 > 0); + default: + return (edge.windCnt2 < 0); + } + default: + return true; + } +} +//------------------------------------------------------------------------------ + +void Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt) +{ + TEdge *e, *prevE; + if( NEAR_EQUAL(e2->dx, HORIZONTAL) || ( e1->dx > e2->dx ) ) + { + AddOutPt( e1, pt ); + e2->outIdx = e1->outIdx; + e1->side = esLeft; + e2->side = esRight; + e = e1; + if (e->prevInAEL == e2) + prevE = e2->prevInAEL; + else + prevE = e->prevInAEL; + } else + { + AddOutPt( e2, pt ); + e1->outIdx = e2->outIdx; + e1->side = esRight; + e2->side = esLeft; + e = e2; + if (e->prevInAEL == e1) + prevE = e1->prevInAEL; + else + prevE = e->prevInAEL; + } + if (prevE && prevE->outIdx >= 0 && + (TopX(*prevE, pt.Y) == TopX(*e, pt.Y)) && + SlopesEqual(*e, *prevE, m_UseFullRange)) + AddJoin(e, prevE, -1, -1); +} +//------------------------------------------------------------------------------ + +void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt) +{ + AddOutPt( e1, pt ); + if( e1->outIdx == e2->outIdx ) + { + e1->outIdx = -1; + e2->outIdx = -1; + } + else if (e1->outIdx < e2->outIdx) + AppendPolygon(e1, e2); + else + AppendPolygon(e2, e1); +} +//------------------------------------------------------------------------------ + +void Clipper::AddEdgeToSEL(TEdge *edge) +{ + //SEL pointers in PEdge are reused to build a list of horizontal edges. + //However, we don't need to worry about order with horizontal edge processing. + if( !m_SortedEdges ) + { + m_SortedEdges = edge; + edge->prevInSEL = 0; + edge->nextInSEL = 0; + } + else + { + edge->nextInSEL = m_SortedEdges; + edge->prevInSEL = 0; + m_SortedEdges->prevInSEL = edge; + m_SortedEdges = edge; + } +} +//------------------------------------------------------------------------------ + +void Clipper::CopyAELToSEL() +{ + TEdge* e = m_ActiveEdges; + m_SortedEdges = e; + if (!m_ActiveEdges) return; + m_SortedEdges->prevInSEL = 0; + e = e->nextInAEL; + while ( e ) + { + e->prevInSEL = e->prevInAEL; + e->prevInSEL->nextInSEL = e; + e->nextInSEL = 0; + e = e->nextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx, int e2OutIdx) +{ + JoinRec* jr = new JoinRec; + if (e1OutIdx >= 0) + jr->poly1Idx = e1OutIdx; else + jr->poly1Idx = e1->outIdx; + jr->pt1a = IntPoint(e1->xcurr, e1->ycurr); + jr->pt1b = IntPoint(e1->xtop, e1->ytop); + if (e2OutIdx >= 0) + jr->poly2Idx = e2OutIdx; else + jr->poly2Idx = e2->outIdx; + jr->pt2a = IntPoint(e2->xcurr, e2->ycurr); + jr->pt2b = IntPoint(e2->xtop, e2->ytop); + m_Joins.push_back(jr); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearJoins() +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + delete m_Joins[i]; + m_Joins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::AddHorzJoin(TEdge *e, int idx) +{ + HorzJoinRec* hj = new HorzJoinRec; + hj->edge = e; + hj->savedIdx = idx; + m_HorizJoins.push_back(hj); +} +//------------------------------------------------------------------------------ + +void Clipper::ClearHorzJoins() +{ + for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); i++) + delete m_HorizJoins[i]; + m_HorizJoins.resize(0); +} +//------------------------------------------------------------------------------ + +void Clipper::InsertLocalMinimaIntoAEL( const long64 botY) +{ + while( m_CurrentLM && ( m_CurrentLM->Y == botY ) ) + { + TEdge* lb = m_CurrentLM->leftBound; + TEdge* rb = m_CurrentLM->rightBound; + + InsertEdgeIntoAEL( lb ); + InsertScanbeam( lb->ytop ); + InsertEdgeIntoAEL( rb ); + + if (IsEvenOddFillType(*lb)) + { + lb->windDelta = 1; + rb->windDelta = 1; + } + else + { + rb->windDelta = -lb->windDelta; + } + SetWindingCount( *lb ); + rb->windCnt = lb->windCnt; + rb->windCnt2 = lb->windCnt2; + + if( NEAR_EQUAL(rb->dx, HORIZONTAL) ) + { + //nb: only rightbounds can have a horizontal bottom edge + AddEdgeToSEL( rb ); + InsertScanbeam( rb->nextInLML->ytop ); + } + else + InsertScanbeam( rb->ytop ); + + if( IsContributing(*lb) ) + AddLocalMinPoly( lb, rb, IntPoint(lb->xcurr, m_CurrentLM->Y) ); + + //if any output polygons share an edge, they'll need joining later ... + if (rb->outIdx >= 0) + { + if (NEAR_EQUAL(rb->dx, HORIZONTAL)) + { + for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i) + { + IntPoint pt, pt2; //returned by GetOverlapSegment() but unused here. + HorzJoinRec* hj = m_HorizJoins[i]; + //if horizontals rb and hj.edge overlap, flag for joining later ... + if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot), + IntPoint(hj->edge->xtop, hj->edge->ytop), + IntPoint(rb->xbot, rb->ybot), + IntPoint(rb->xtop, rb->ytop), pt, pt2)) + AddJoin(hj->edge, rb, hj->savedIdx); + } + } + } + + if( lb->nextInAEL != rb ) + { + if (rb->outIdx >= 0 && rb->prevInAEL->outIdx >= 0 && + SlopesEqual(*rb->prevInAEL, *rb, m_UseFullRange)) + AddJoin(rb, rb->prevInAEL); + + TEdge* e = lb->nextInAEL; + IntPoint pt = IntPoint(lb->xcurr, lb->ycurr); + while( e != rb ) + { + if(!e) throw clipperException("InsertLocalMinimaIntoAEL: missing rightbound!"); + //nb: For calculating winding counts etc, IntersectEdges() assumes + //that param1 will be to the right of param2 ABOVE the intersection ... + IntersectEdges( rb , e , pt , ipNone); //order important here + e = e->nextInAEL; + } + } + PopLocalMinima(); + } +} +//------------------------------------------------------------------------------ + +void Clipper::DeleteFromAEL(TEdge *e) +{ + TEdge* AelPrev = e->prevInAEL; + TEdge* AelNext = e->nextInAEL; + if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted + if( AelPrev ) AelPrev->nextInAEL = AelNext; + else m_ActiveEdges = AelNext; + if( AelNext ) AelNext->prevInAEL = AelPrev; + e->nextInAEL = 0; + e->prevInAEL = 0; +} +//------------------------------------------------------------------------------ + +void Clipper::DeleteFromSEL(TEdge *e) +{ + TEdge* SelPrev = e->prevInSEL; + TEdge* SelNext = e->nextInSEL; + if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted + if( SelPrev ) SelPrev->nextInSEL = SelNext; + else m_SortedEdges = SelNext; + if( SelNext ) SelNext->prevInSEL = SelPrev; + e->nextInSEL = 0; + e->prevInSEL = 0; +} +//------------------------------------------------------------------------------ + +void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, + const IntPoint &pt, IntersectProtects protects) +{ + //e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before + //e2 in AEL except when e1 is being inserted at the intersection point ... + bool e1stops = !(ipLeft & protects) && !e1->nextInLML && + e1->xtop == pt.X && e1->ytop == pt.Y; + bool e2stops = !(ipRight & protects) && !e2->nextInLML && + e2->xtop == pt.X && e2->ytop == pt.Y; + bool e1Contributing = ( e1->outIdx >= 0 ); + bool e2contributing = ( e2->outIdx >= 0 ); + + //update winding counts... + //assumes that e1 will be to the right of e2 ABOVE the intersection + if ( e1->polyType == e2->polyType ) + { + if ( IsEvenOddFillType( *e1) ) + { + int oldE1WindCnt = e1->windCnt; + e1->windCnt = e2->windCnt; + e2->windCnt = oldE1WindCnt; + } else + { + if (e1->windCnt + e2->windDelta == 0 ) e1->windCnt = -e1->windCnt; + else e1->windCnt += e2->windDelta; + if ( e2->windCnt - e1->windDelta == 0 ) e2->windCnt = -e2->windCnt; + else e2->windCnt -= e1->windDelta; + } + } else + { + if (!IsEvenOddFillType(*e2)) e1->windCnt2 += e2->windDelta; + else e1->windCnt2 = ( e1->windCnt2 == 0 ) ? 1 : 0; + if (!IsEvenOddFillType(*e1)) e2->windCnt2 -= e1->windDelta; + else e2->windCnt2 = ( e2->windCnt2 == 0 ) ? 1 : 0; + } + + PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; + if (e1->polyType == ptSubject) + { + e1FillType = m_SubjFillType; + e1FillType2 = m_ClipFillType; + } else + { + e1FillType = m_ClipFillType; + e1FillType2 = m_SubjFillType; + } + if (e2->polyType == ptSubject) + { + e2FillType = m_SubjFillType; + e2FillType2 = m_ClipFillType; + } else + { + e2FillType = m_ClipFillType; + e2FillType2 = m_SubjFillType; + } + + long64 e1Wc, e2Wc; + switch (e1FillType) + { + case pftPositive: e1Wc = e1->windCnt; break; + case pftNegative: e1Wc = -e1->windCnt; break; + default: e1Wc = Abs(e1->windCnt); + } + switch(e2FillType) + { + case pftPositive: e2Wc = e2->windCnt; break; + case pftNegative: e2Wc = -e2->windCnt; break; + default: e2Wc = Abs(e2->windCnt); + } + + if ( e1Contributing && e2contributing ) + { + if ( e1stops || e2stops || + (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || + (e1->polyType != e2->polyType && m_ClipType != ctXor) ) + AddLocalMaxPoly(e1, e2, pt); + else + DoBothEdges( e1, e2, pt ); + } + else if ( e1Contributing ) + { + if ((e2Wc == 0 || e2Wc == 1) && + (m_ClipType != ctIntersection || + e2->polyType == ptSubject || (e2->windCnt2 != 0))) + DoEdge1(e1, e2, pt); + } + else if ( e2contributing ) + { + if ((e1Wc == 0 || e1Wc == 1) && + (m_ClipType != ctIntersection || + e1->polyType == ptSubject || (e1->windCnt2 != 0))) + DoEdge2(e1, e2, pt); + } + else if ( (e1Wc == 0 || e1Wc == 1) && + (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops ) + { + //neither edge is currently contributing ... + + long64 e1Wc2, e2Wc2; + switch (e1FillType2) + { + case pftPositive: e1Wc2 = e1->windCnt2; break; + case pftNegative : e1Wc2 = -e1->windCnt2; break; + default: e1Wc2 = Abs(e1->windCnt2); + } + switch (e2FillType2) + { + case pftPositive: e2Wc2 = e2->windCnt2; break; + case pftNegative: e2Wc2 = -e2->windCnt2; break; + default: e2Wc2 = Abs(e2->windCnt2); + } + + if (e1->polyType != e2->polyType) + AddLocalMinPoly(e1, e2, pt); + else if (e1Wc == 1 && e2Wc == 1) + switch( m_ClipType ) { + case ctIntersection: + if (e1Wc2 > 0 && e2Wc2 > 0) + AddLocalMinPoly(e1, e2, pt); + break; + case ctUnion: + if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) + AddLocalMinPoly(e1, e2, pt); + break; + case ctDifference: + if (((e1->polyType == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || + ((e1->polyType == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) + AddLocalMinPoly(e1, e2, pt); + break; + case ctXor: + AddLocalMinPoly(e1, e2, pt); + } + else + SwapSides( *e1, *e2 ); + } + + if( (e1stops != e2stops) && + ( (e1stops && (e1->outIdx >= 0)) || (e2stops && (e2->outIdx >= 0)) ) ) + { + SwapSides( *e1, *e2 ); + SwapPolyIndexes( *e1, *e2 ); + } + + //finally, delete any non-contributing maxima edges ... + if( e1stops ) DeleteFromAEL( e1 ); + if( e2stops ) DeleteFromAEL( e2 ); +} +//------------------------------------------------------------------------------ + +void Clipper::SetHoleState(TEdge *e, OutRec *outRec) +{ + bool isHole = false; + TEdge *e2 = e->prevInAEL; + while (e2) + { + if (e2->outIdx >= 0) + { + isHole = !isHole; + if (! outRec->FirstLeft) + outRec->FirstLeft = m_PolyOuts[e2->outIdx]; + } + e2 = e2->prevInAEL; + } + if (isHole) outRec->isHole = true; +} +//------------------------------------------------------------------------------ + +OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) +{ + //work out which polygon fragment has the correct hole state ... + OutPt *outPt1 = outRec1->bottomPt; + OutPt *outPt2 = outRec2->bottomPt; + if (outPt1->pt.Y > outPt2->pt.Y) return outRec1; + else if (outPt1->pt.Y < outPt2->pt.Y) return outRec2; + else if (outPt1->pt.X < outPt2->pt.X) return outRec1; + else if (outPt1->pt.X > outPt2->pt.X) return outRec2; + else if (outPt1->next == outPt1) return outRec2; + else if (outPt2->next == outPt2) return outRec1; + else if (FirstIsBottomPt(outPt1, outPt2)) return outRec1; + else return outRec2; +} +//------------------------------------------------------------------------------ + +void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) +{ + //get the start and ends of both output polygons ... + OutRec *outRec1 = m_PolyOuts[e1->outIdx]; + OutRec *outRec2 = m_PolyOuts[e2->outIdx]; + + OutRec *holeStateRec; + if (outRec1->FirstLeft == outRec2) holeStateRec = outRec2; + else if (outRec2->FirstLeft == outRec1) holeStateRec = outRec1; + else holeStateRec = GetLowermostRec(outRec1, outRec2); + + OutPt* p1_lft = outRec1->pts; + OutPt* p1_rt = p1_lft->prev; + OutPt* p2_lft = outRec2->pts; + OutPt* p2_rt = p2_lft->prev; + + EdgeSide side; + //join e2 poly onto e1 poly and delete pointers to e2 ... + if( e1->side == esLeft ) + { + if( e2->side == esLeft ) + { + //z y x a b c + ReversePolyPtLinks(*p2_lft); + p2_lft->next = p1_lft; + p1_lft->prev = p2_lft; + p1_rt->next = p2_rt; + p2_rt->prev = p1_rt; + outRec1->pts = p2_rt; + } else + { + //x y z a b c + p2_rt->next = p1_lft; + p1_lft->prev = p2_rt; + p2_lft->prev = p1_rt; + p1_rt->next = p2_lft; + outRec1->pts = p2_lft; + } + side = esLeft; + } else + { + if( e2->side == esRight ) + { + //a b c z y x + ReversePolyPtLinks( *p2_lft ); + p1_rt->next = p2_rt; + p2_rt->prev = p1_rt; + p2_lft->next = p1_lft; + p1_lft->prev = p2_lft; + } else + { + //a b c x y z + p1_rt->next = p2_lft; + p2_lft->prev = p1_rt; + p1_lft->prev = p2_rt; + p2_rt->next = p1_lft; + } + side = esRight; + } + + if (holeStateRec == outRec2) + { + outRec1->bottomPt = outRec2->bottomPt; + outRec1->bottomPt->idx = outRec1->idx; + if (outRec2->FirstLeft != outRec1) + outRec1->FirstLeft = outRec2->FirstLeft; + outRec1->isHole = outRec2->isHole; + } + outRec2->pts = 0; + outRec2->bottomPt = 0; + outRec2->AppendLink = outRec1; + int OKIdx = e1->outIdx; + int ObsoleteIdx = e2->outIdx; + + e1->outIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly + e2->outIdx = -1; + + TEdge* e = m_ActiveEdges; + while( e ) + { + if( e->outIdx == ObsoleteIdx ) + { + e->outIdx = OKIdx; + e->side = side; + break; + } + e = e->nextInAEL; + } + + for (JoinList::size_type i = 0; i < m_Joins.size(); ++i) + { + if (m_Joins[i]->poly1Idx == ObsoleteIdx) m_Joins[i]->poly1Idx = OKIdx; + if (m_Joins[i]->poly2Idx == ObsoleteIdx) m_Joins[i]->poly2Idx = OKIdx; + } + + for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i) + { + if (m_HorizJoins[i]->savedIdx == ObsoleteIdx) + m_HorizJoins[i]->savedIdx = OKIdx; + } + +} +//------------------------------------------------------------------------------ + +OutRec* Clipper::CreateOutRec() +{ + OutRec* result = new OutRec; + result->isHole = false; + result->FirstLeft = 0; + result->AppendLink = 0; + result->pts = 0; + result->bottomPt = 0; + result->sides = esNeither; + result->bottomFlag = 0; + + return result; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeBottomPt(OutRec &outRec) +{ + OutPt* next = outRec.bottomPt->next; + OutPt* prev = outRec.bottomPt->prev; + if (outRec.pts == outRec.bottomPt) outRec.pts = next; + delete outRec.bottomPt; + next->prev = prev; + prev->next = next; + outRec.bottomPt = next; +} +//------------------------------------------------------------------------------ + +void Clipper::AddOutPt(TEdge *e, const IntPoint &pt) +{ + bool ToFront = (e->side == esLeft); + if( e->outIdx < 0 ) + { + OutRec *outRec = CreateOutRec(); + m_PolyOuts.push_back(outRec); + outRec->idx = (int)m_PolyOuts.size()-1; + e->outIdx = outRec->idx; + OutPt* op = new OutPt; + outRec->pts = op; + outRec->bottomPt = op; + op->pt = pt; + op->idx = outRec->idx; + op->next = op; + op->prev = op; + SetHoleState(e, outRec); + } else + { + OutRec *outRec = m_PolyOuts[e->outIdx]; + OutPt* op = outRec->pts; + if ((ToFront && PointsEqual(pt, op->pt)) || + (!ToFront && PointsEqual(pt, op->prev->pt))) return; + + if ((e->side | outRec->sides) != outRec->sides) + { + //check for 'rounding' artefacts ... + if (outRec->sides == esNeither && pt.Y == op->pt.Y) + { + if (ToFront) + { + if (pt.X == op->pt.X +1) return; //ie wrong side of bottomPt + } + else if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt + } + + outRec->sides = (EdgeSide)(outRec->sides | e->side); + if (outRec->sides == esBoth) + { + //A vertex from each side has now been added. + //Vertices of one side of an output polygon are quite commonly close to + //or even 'touching' edges of the other side of the output polygon. + //Very occasionally vertices from one side can 'cross' an edge on the + //the other side. The distance 'crossed' is always less that a unit + //and is purely an artefact of coordinate rounding. Nevertheless, this + //results in very tiny self-intersections. Because of the way + //orientation is calculated, even tiny self-intersections can cause + //the Orientation function to return the wrong result. Therefore, it's + //important to ensure that any self-intersections close to BottomPt are + //detected and removed before orientation is assigned. + + OutPt *opBot, *op2; + if (ToFront) + { + opBot = outRec->pts; + op2 = opBot->next; //op2 == right side + if (opBot->pt.Y != op2->pt.Y && opBot->pt.Y != pt.Y && + ((opBot->pt.X - pt.X)/(opBot->pt.Y - pt.Y) < + (opBot->pt.X - op2->pt.X)/(opBot->pt.Y - op2->pt.Y))) + outRec->bottomFlag = opBot; + } else + { + opBot = outRec->pts->prev; + op2 = opBot->prev; //op2 == left side + if (opBot->pt.Y != op2->pt.Y && opBot->pt.Y != pt.Y && + ((opBot->pt.X - pt.X)/(opBot->pt.Y - pt.Y) > + (opBot->pt.X - op2->pt.X)/(opBot->pt.Y - op2->pt.Y))) + outRec->bottomFlag = opBot; + } + } + } + + OutPt* op2 = new OutPt; + op2->pt = pt; + op2->idx = outRec->idx; + if (op2->pt.Y == outRec->bottomPt->pt.Y && + op2->pt.X < outRec->bottomPt->pt.X) + outRec->bottomPt = op2; + op2->next = op; + op2->prev = op->prev; + op2->prev->next = op2; + op->prev = op2; + if (ToFront) outRec->pts = op2; + } +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessHorizontals() +{ + TEdge* horzEdge = m_SortedEdges; + while( horzEdge ) + { + DeleteFromSEL( horzEdge ); + ProcessHorizontal( horzEdge ); + horzEdge = m_SortedEdges; + } +} +//------------------------------------------------------------------------------ + +bool Clipper::IsTopHorz(const long64 XPos) +{ + TEdge* e = m_SortedEdges; + while( e ) + { + if( ( XPos >= std::min(e->xcurr, e->xtop) ) && + ( XPos <= std::max(e->xcurr, e->xtop) ) ) return false; + e = e->nextInSEL; + } + return true; +} +//------------------------------------------------------------------------------ + +bool IsMinima(TEdge *e) +{ + return e && (e->prev->nextInLML != e) && (e->next->nextInLML != e); +} +//------------------------------------------------------------------------------ + +bool IsMaxima(TEdge *e, const long64 Y) +{ + return e && e->ytop == Y && !e->nextInLML; +} +//------------------------------------------------------------------------------ + +bool IsIntermediate(TEdge *e, const long64 Y) +{ + return e->ytop == Y && e->nextInLML; +} +//------------------------------------------------------------------------------ + +TEdge *GetMaximaPair(TEdge *e) +{ + if( !IsMaxima(e->next, e->ytop) || e->next->xtop != e->xtop ) + return e->prev; else + return e->next; +} +//------------------------------------------------------------------------------ + +void Clipper::SwapPositionsInAEL(TEdge *edge1, TEdge *edge2) +{ + if( !edge1->nextInAEL && !edge1->prevInAEL ) return; + if( !edge2->nextInAEL && !edge2->prevInAEL ) return; + + if( edge1->nextInAEL == edge2 ) + { + TEdge* next = edge2->nextInAEL; + if( next ) next->prevInAEL = edge1; + TEdge* prev = edge1->prevInAEL; + if( prev ) prev->nextInAEL = edge2; + edge2->prevInAEL = prev; + edge2->nextInAEL = edge1; + edge1->prevInAEL = edge2; + edge1->nextInAEL = next; + } + else if( edge2->nextInAEL == edge1 ) + { + TEdge* next = edge1->nextInAEL; + if( next ) next->prevInAEL = edge2; + TEdge* prev = edge2->prevInAEL; + if( prev ) prev->nextInAEL = edge1; + edge1->prevInAEL = prev; + edge1->nextInAEL = edge2; + edge2->prevInAEL = edge1; + edge2->nextInAEL = next; + } + else + { + TEdge* next = edge1->nextInAEL; + TEdge* prev = edge1->prevInAEL; + edge1->nextInAEL = edge2->nextInAEL; + if( edge1->nextInAEL ) edge1->nextInAEL->prevInAEL = edge1; + edge1->prevInAEL = edge2->prevInAEL; + if( edge1->prevInAEL ) edge1->prevInAEL->nextInAEL = edge1; + edge2->nextInAEL = next; + if( edge2->nextInAEL ) edge2->nextInAEL->prevInAEL = edge2; + edge2->prevInAEL = prev; + if( edge2->prevInAEL ) edge2->prevInAEL->nextInAEL = edge2; + } + + if( !edge1->prevInAEL ) m_ActiveEdges = edge1; + else if( !edge2->prevInAEL ) m_ActiveEdges = edge2; +} +//------------------------------------------------------------------------------ + +void Clipper::SwapPositionsInSEL(TEdge *edge1, TEdge *edge2) +{ + if( !( edge1->nextInSEL ) && !( edge1->prevInSEL ) ) return; + if( !( edge2->nextInSEL ) && !( edge2->prevInSEL ) ) return; + + if( edge1->nextInSEL == edge2 ) + { + TEdge* next = edge2->nextInSEL; + if( next ) next->prevInSEL = edge1; + TEdge* prev = edge1->prevInSEL; + if( prev ) prev->nextInSEL = edge2; + edge2->prevInSEL = prev; + edge2->nextInSEL = edge1; + edge1->prevInSEL = edge2; + edge1->nextInSEL = next; + } + else if( edge2->nextInSEL == edge1 ) + { + TEdge* next = edge1->nextInSEL; + if( next ) next->prevInSEL = edge2; + TEdge* prev = edge2->prevInSEL; + if( prev ) prev->nextInSEL = edge1; + edge1->prevInSEL = prev; + edge1->nextInSEL = edge2; + edge2->prevInSEL = edge1; + edge2->nextInSEL = next; + } + else + { + TEdge* next = edge1->nextInSEL; + TEdge* prev = edge1->prevInSEL; + edge1->nextInSEL = edge2->nextInSEL; + if( edge1->nextInSEL ) edge1->nextInSEL->prevInSEL = edge1; + edge1->prevInSEL = edge2->prevInSEL; + if( edge1->prevInSEL ) edge1->prevInSEL->nextInSEL = edge1; + edge2->nextInSEL = next; + if( edge2->nextInSEL ) edge2->nextInSEL->prevInSEL = edge2; + edge2->prevInSEL = prev; + if( edge2->prevInSEL ) edge2->prevInSEL->nextInSEL = edge2; + } + + if( !edge1->prevInSEL ) m_SortedEdges = edge1; + else if( !edge2->prevInSEL ) m_SortedEdges = edge2; +} +//------------------------------------------------------------------------------ + +TEdge* GetNextInAEL(TEdge *e, Direction dir) +{ + return dir == dLeftToRight ? e->nextInAEL : e->prevInAEL; +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessHorizontal(TEdge *horzEdge) +{ + Direction dir; + long64 horzLeft, horzRight; + + if( horzEdge->xcurr < horzEdge->xtop ) + { + horzLeft = horzEdge->xcurr; + horzRight = horzEdge->xtop; + dir = dLeftToRight; + } else + { + horzLeft = horzEdge->xtop; + horzRight = horzEdge->xcurr; + dir = dRightToLeft; + } + + TEdge* eMaxPair; + if( horzEdge->nextInLML ) eMaxPair = 0; + else eMaxPair = GetMaximaPair(horzEdge); + + TEdge* e = GetNextInAEL( horzEdge , dir ); + while( e ) + { + TEdge* eNext = GetNextInAEL( e, dir ); + + if (eMaxPair || + ((dir == dLeftToRight) && (e->xcurr <= horzRight)) || + ((dir == dRightToLeft) && (e->xcurr >= horzLeft))) + { + //ok, so far it looks like we're still in range of the horizontal edge + if ( e->xcurr == horzEdge->xtop && !eMaxPair ) + { + if (SlopesEqual(*e, *horzEdge->nextInLML, m_UseFullRange)) + { + //if output polygons share an edge, they'll need joining later ... + if (horzEdge->outIdx >= 0 && e->outIdx >= 0) + AddJoin(horzEdge->nextInLML, e, horzEdge->outIdx); + break; //we've reached the end of the horizontal line + } + else if (e->dx < horzEdge->nextInLML->dx) + //we really have got to the end of the intermediate horz edge so quit. + //nb: More -ve slopes follow more +ve slopes ABOVE the horizontal. + break; + } + + if( e == eMaxPair ) + { + //horzEdge is evidently a maxima horizontal and we've arrived at its end. + if (dir == dLeftToRight) + IntersectEdges(horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr), ipNone); + else + IntersectEdges(e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), ipNone); + if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error"); + return; + } + else if( NEAR_EQUAL(e->dx, HORIZONTAL) && !IsMinima(e) && !(e->xcurr > e->xtop) ) + { + //An overlapping horizontal edge. Overlapping horizontal edges are + //processed as if layered with the current horizontal edge (horizEdge) + //being infinitesimally lower that the next (e). Therfore, we + //intersect with e only if e.xcurr is within the bounds of horzEdge ... + if( dir == dLeftToRight ) + IntersectEdges( horzEdge , e, IntPoint(e->xcurr, horzEdge->ycurr), + (IsTopHorz( e->xcurr ))? ipLeft : ipBoth ); + else + IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), + (IsTopHorz( e->xcurr ))? ipRight : ipBoth ); + } + else if( dir == dLeftToRight ) + { + IntersectEdges( horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr), + (IsTopHorz( e->xcurr ))? ipLeft : ipBoth ); + } + else + { + IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), + (IsTopHorz( e->xcurr ))? ipRight : ipBoth ); + } + SwapPositionsInAEL( horzEdge, e ); + } + else if( (dir == dLeftToRight && e->xcurr > horzRight && m_SortedEdges) || + (dir == dRightToLeft && e->xcurr < horzLeft && m_SortedEdges) ) break; + e = eNext; + } //end while + + if( horzEdge->nextInLML ) + { + if( horzEdge->outIdx >= 0 ) + AddOutPt( horzEdge, IntPoint(horzEdge->xtop, horzEdge->ytop)); + UpdateEdgeIntoAEL( horzEdge ); + } + else + { + if ( horzEdge->outIdx >= 0 ) + IntersectEdges( horzEdge, eMaxPair, + IntPoint(horzEdge->xtop, horzEdge->ycurr), ipBoth); + if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error"); + DeleteFromAEL(eMaxPair); + DeleteFromAEL(horzEdge); + } +} +//------------------------------------------------------------------------------ + +void Clipper::UpdateEdgeIntoAEL(TEdge *&e) +{ + if( !e->nextInLML ) throw + clipperException("UpdateEdgeIntoAEL: invalid call"); + TEdge* AelPrev = e->prevInAEL; + TEdge* AelNext = e->nextInAEL; + e->nextInLML->outIdx = e->outIdx; + if( AelPrev ) AelPrev->nextInAEL = e->nextInLML; + else m_ActiveEdges = e->nextInLML; + if( AelNext ) AelNext->prevInAEL = e->nextInLML; + e->nextInLML->side = e->side; + e->nextInLML->windDelta = e->windDelta; + e->nextInLML->windCnt = e->windCnt; + e->nextInLML->windCnt2 = e->windCnt2; + e = e->nextInLML; + e->prevInAEL = AelPrev; + e->nextInAEL = AelNext; + if( !NEAR_EQUAL(e->dx, HORIZONTAL) ) InsertScanbeam( e->ytop ); +} +//------------------------------------------------------------------------------ + +bool Clipper::ProcessIntersections(const long64 botY, const long64 topY) +{ + if( !m_ActiveEdges ) return true; + try { + BuildIntersectList(botY, topY); + if ( !m_IntersectNodes) return true; + if ( FixupIntersections() ) ProcessIntersectList(); + else return false; + } + catch(...) { + m_SortedEdges = 0; + DisposeIntersectNodes(); + throw clipperException("ProcessIntersections error"); + } + return true; +} +//------------------------------------------------------------------------------ + +void Clipper::DisposeIntersectNodes() +{ + while ( m_IntersectNodes ) + { + IntersectNode* iNode = m_IntersectNodes->next; + delete m_IntersectNodes; + m_IntersectNodes = iNode; + } +} +//------------------------------------------------------------------------------ + +void Clipper::BuildIntersectList(const long64 botY, const long64 topY) +{ + if ( !m_ActiveEdges ) return; + + //prepare for sorting ... + TEdge* e = m_ActiveEdges; + e->tmpX = TopX( *e, topY ); + m_SortedEdges = e; + m_SortedEdges->prevInSEL = 0; + e = e->nextInAEL; + while( e ) + { + e->prevInSEL = e->prevInAEL; + e->prevInSEL->nextInSEL = e; + e->nextInSEL = 0; + e->tmpX = TopX( *e, topY ); + e = e->nextInAEL; + } + + //bubblesort ... + bool isModified = true; + while( isModified && m_SortedEdges ) + { + isModified = false; + e = m_SortedEdges; + while( e->nextInSEL ) + { + TEdge *eNext = e->nextInSEL; + IntPoint pt; + if(e->tmpX > eNext->tmpX && + IntersectPoint(*e, *eNext, pt, m_UseFullRange)) + { + if (pt.Y > botY) + { + pt.Y = botY; + pt.X = TopX(*e, pt.Y); + } + AddIntersectNode( e, eNext, pt ); + SwapPositionsInSEL(e, eNext); + isModified = true; + } + else + e = eNext; + } + if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0; + else break; + } + m_SortedEdges = 0; +} +//------------------------------------------------------------------------------ + +bool Process1Before2(IntersectNode &node1, IntersectNode &node2) +{ + bool result; + if (node1.pt.Y == node2.pt.Y) + { + if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1) + { + result = node2.pt.X > node1.pt.X; + return node2.edge1->dx > 0 ? !result : result; + } + else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2) + { + result = node2.pt.X > node1.pt.X; + return node2.edge2->dx > 0 ? !result : result; + } + else return node2.pt.X > node1.pt.X; + } + else return node1.pt.Y > node2.pt.Y; +} +//------------------------------------------------------------------------------ + +void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt) +{ + IntersectNode* newNode = new IntersectNode; + newNode->edge1 = e1; + newNode->edge2 = e2; + newNode->pt = pt; + newNode->next = 0; + if( !m_IntersectNodes ) m_IntersectNodes = newNode; + else if( Process1Before2(*newNode, *m_IntersectNodes) ) + { + newNode->next = m_IntersectNodes; + m_IntersectNodes = newNode; + } + else + { + IntersectNode* iNode = m_IntersectNodes; + while( iNode->next && Process1Before2(*iNode->next, *newNode) ) + iNode = iNode->next; + newNode->next = iNode->next; + iNode->next = newNode; + } +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessIntersectList() +{ + while( m_IntersectNodes ) + { + IntersectNode* iNode = m_IntersectNodes->next; + { + IntersectEdges( m_IntersectNodes->edge1 , + m_IntersectNodes->edge2 , m_IntersectNodes->pt, ipBoth ); + SwapPositionsInAEL( m_IntersectNodes->edge1 , m_IntersectNodes->edge2 ); + } + delete m_IntersectNodes; + m_IntersectNodes = iNode; + } +} +//------------------------------------------------------------------------------ + +void Clipper::DoMaxima(TEdge *e, long64 topY) +{ + TEdge* eMaxPair = GetMaximaPair(e); + long64 X = e->xtop; + TEdge* eNext = e->nextInAEL; + while( eNext != eMaxPair ) + { + if (!eNext) throw clipperException("DoMaxima error"); + IntersectEdges( e, eNext, IntPoint(X, topY), ipBoth ); + eNext = eNext->nextInAEL; + } + if( e->outIdx < 0 && eMaxPair->outIdx < 0 ) + { + DeleteFromAEL( e ); + DeleteFromAEL( eMaxPair ); + } + else if( e->outIdx >= 0 && eMaxPair->outIdx >= 0 ) + { + IntersectEdges( e, eMaxPair, IntPoint(X, topY), ipNone ); + } + else throw clipperException("DoMaxima error"); +} +//------------------------------------------------------------------------------ + +void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY) +{ + TEdge* e = m_ActiveEdges; + while( e ) + { + //1. process maxima, treating them as if they're 'bent' horizontal edges, + // but exclude maxima with horizontal edges. nb: e can't be a horizontal. + if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, HORIZONTAL) ) + { + //'e' might be removed from AEL, as may any following edges so ... + TEdge* ePrior = e->prevInAEL; + DoMaxima(e, topY); + if( !ePrior ) e = m_ActiveEdges; + else e = ePrior->nextInAEL; + } + else + { + //2. promote horizontal edges, otherwise update xcurr and ycurr ... + if( IsIntermediate(e, topY) && NEAR_EQUAL(e->nextInLML->dx, HORIZONTAL) ) + { + if (e->outIdx >= 0) + { + AddOutPt(e, IntPoint(e->xtop, e->ytop)); + + for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i) + { + IntPoint pt, pt2; + HorzJoinRec* hj = m_HorizJoins[i]; + if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot), + IntPoint(hj->edge->xtop, hj->edge->ytop), + IntPoint(e->nextInLML->xbot, e->nextInLML->ybot), + IntPoint(e->nextInLML->xtop, e->nextInLML->ytop), pt, pt2)) + AddJoin(hj->edge, e->nextInLML, hj->savedIdx, e->outIdx); + } + + AddHorzJoin(e->nextInLML, e->outIdx); + } + UpdateEdgeIntoAEL(e); + AddEdgeToSEL(e); + } else + { + //this just simplifies horizontal processing ... + e->xcurr = TopX( *e, topY ); + e->ycurr = topY; + } + e = e->nextInAEL; + } + } + + //3. Process horizontals at the top of the scanbeam ... + ProcessHorizontals(); + + //4. Promote intermediate vertices ... + e = m_ActiveEdges; + while( e ) + { + if( IsIntermediate( e, topY ) ) + { + if( e->outIdx >= 0 ) AddOutPt(e, IntPoint(e->xtop,e->ytop)); + UpdateEdgeIntoAEL(e); + + //if output polygons share an edge, they'll need joining later ... + if (e->outIdx >= 0 && e->prevInAEL && e->prevInAEL->outIdx >= 0 && + e->prevInAEL->xcurr == e->xbot && e->prevInAEL->ycurr == e->ybot && + SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop), + IntPoint(e->xbot,e->ybot), + IntPoint(e->prevInAEL->xtop, e->prevInAEL->ytop), m_UseFullRange)) + { + AddOutPt(e->prevInAEL, IntPoint(e->xbot, e->ybot)); + AddJoin(e, e->prevInAEL); + } + else if (e->outIdx >= 0 && e->nextInAEL && e->nextInAEL->outIdx >= 0 && + e->nextInAEL->ycurr > e->nextInAEL->ytop && + e->nextInAEL->ycurr <= e->nextInAEL->ybot && + e->nextInAEL->xcurr == e->xbot && e->nextInAEL->ycurr == e->ybot && + SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop), + IntPoint(e->xbot,e->ybot), + IntPoint(e->nextInAEL->xtop, e->nextInAEL->ytop), m_UseFullRange)) + { + AddOutPt(e->nextInAEL, IntPoint(e->xbot, e->ybot)); + AddJoin(e, e->nextInAEL); + } + } + e = e->nextInAEL; + } +} +//------------------------------------------------------------------------------ + +void Clipper::FixupOutPolygon(OutRec &outRec) +{ + //FixupOutPolygon() - removes duplicate points and simplifies consecutive + //parallel edges by removing the middle vertex. + OutPt *lastOK = 0; + outRec.pts = outRec.bottomPt; + OutPt *pp = outRec.bottomPt; + + for (;;) + { + if (pp->prev == pp || pp->prev == pp->next ) + { + DisposeOutPts(pp); + outRec.pts = 0; + outRec.bottomPt = 0; + return; + } + //test for duplicate points and for same slope (cross-product) ... + if ( PointsEqual(pp->pt, pp->next->pt) || + SlopesEqual(pp->prev->pt, pp->pt, pp->next->pt, m_UseFullRange) ) + { + lastOK = 0; + OutPt *tmp = pp; + if (pp == outRec.bottomPt) + outRec.bottomPt = 0; //flags need for updating + pp->prev->next = pp->next; + pp->next->prev = pp->prev; + pp = pp->prev; + delete tmp; + } + else if (pp == lastOK) break; + else + { + if (!lastOK) lastOK = pp; + pp = pp->next; + } + } + if (!outRec.bottomPt) { + outRec.bottomPt = GetBottomPt(pp); + outRec.bottomPt->idx = outRec.idx; + outRec.pts = outRec.bottomPt; + } +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResult(Polygons &polys) +{ + int k = 0; + polys.resize(m_PolyOuts.size()); + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + if (m_PolyOuts[i]->pts) + { + Polygon* pg = &polys[k]; + pg->clear(); + OutPt* p = m_PolyOuts[i]->pts; + do + { + pg->push_back(p->pt); + p = p->next; + } while (p != m_PolyOuts[i]->pts); + //make sure each polygon has at least 3 vertices ... + if (pg->size() < 3) pg->clear(); else k++; + } + } + polys.resize(k); +} +//------------------------------------------------------------------------------ + +void Clipper::BuildResultEx(ExPolygons &polys) +{ + PolyOutList::size_type i = 0; + int k = 0; + polys.resize(0); + polys.reserve(m_PolyOuts.size()); + while (i < m_PolyOuts.size() && m_PolyOuts[i]->pts) + { + ExPolygon epg; + OutPt* p = m_PolyOuts[i]->pts; + do { + epg.outer.push_back(p->pt); + p = p->next; + } while (p != m_PolyOuts[i]->pts); + i++; + //make sure polygons have at least 3 vertices ... + if (epg.outer.size() < 3) continue; + while (i < m_PolyOuts.size() + && m_PolyOuts[i]->pts && m_PolyOuts[i]->isHole) + { + Polygon pg; + p = m_PolyOuts[i]->pts; + do { + pg.push_back(p->pt); + p = p->next; + } while (p != m_PolyOuts[i]->pts); + epg.holes.push_back(pg); + i++; + } + polys.push_back(epg); + k++; + } + polys.resize(k); +} +//------------------------------------------------------------------------------ + +void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) +{ + TEdge *e1 = int1.edge1; + TEdge *e2 = int1.edge2; + IntPoint p = int1.pt; + + int1.edge1 = int2.edge1; + int1.edge2 = int2.edge2; + int1.pt = int2.pt; + + int2.edge1 = e1; + int2.edge2 = e2; + int2.pt = p; +} +//------------------------------------------------------------------------------ + +bool Clipper::FixupIntersections() +{ + if ( !m_IntersectNodes->next ) return true; + + CopyAELToSEL(); + IntersectNode *int1 = m_IntersectNodes; + IntersectNode *int2 = m_IntersectNodes->next; + while (int2) + { + TEdge *e1 = int1->edge1; + TEdge *e2; + if (e1->prevInSEL == int1->edge2) e2 = e1->prevInSEL; + else if (e1->nextInSEL == int1->edge2) e2 = e1->nextInSEL; + else + { + //The current intersection is out of order, so try and swap it with + //a subsequent intersection ... + while (int2) + { + if (int2->edge1->nextInSEL == int2->edge2 || + int2->edge1->prevInSEL == int2->edge2) break; + else int2 = int2->next; + } + if ( !int2 ) return false; //oops!!! + + //found an intersect node that can be swapped ... + SwapIntersectNodes(*int1, *int2); + e1 = int1->edge1; + e2 = int1->edge2; + } + SwapPositionsInSEL(e1, e2); + int1 = int1->next; + int2 = int1->next; + } + + m_SortedEdges = 0; + + //finally, check the last intersection too ... + return (int1->edge1->prevInSEL == int1->edge2 || + int1->edge1->nextInSEL == int1->edge2); +} +//------------------------------------------------------------------------------ + +bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) +{ + return e2.xcurr == e1.xcurr ? e2.dx > e1.dx : e2.xcurr < e1.xcurr; +} +//------------------------------------------------------------------------------ + +void Clipper::InsertEdgeIntoAEL(TEdge *edge) +{ + edge->prevInAEL = 0; + edge->nextInAEL = 0; + if( !m_ActiveEdges ) + { + m_ActiveEdges = edge; + } + else if( E2InsertsBeforeE1(*m_ActiveEdges, *edge) ) + { + edge->nextInAEL = m_ActiveEdges; + m_ActiveEdges->prevInAEL = edge; + m_ActiveEdges = edge; + } else + { + TEdge* e = m_ActiveEdges; + while( e->nextInAEL && !E2InsertsBeforeE1(*e->nextInAEL , *edge) ) + e = e->nextInAEL; + edge->nextInAEL = e->nextInAEL; + if( e->nextInAEL ) e->nextInAEL->prevInAEL = edge; + edge->prevInAEL = e; + e->nextInAEL = edge; + } +} +//---------------------------------------------------------------------- + +void Clipper::DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt) +{ + AddOutPt(edge1, pt); + SwapSides(*edge1, *edge2); + SwapPolyIndexes(*edge1, *edge2); +} +//---------------------------------------------------------------------- + +void Clipper::DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt) +{ + AddOutPt(edge2, pt); + SwapSides(*edge1, *edge2); + SwapPolyIndexes(*edge1, *edge2); +} +//---------------------------------------------------------------------- + +void Clipper::DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt) +{ + AddOutPt(edge1, pt); + AddOutPt(edge2, pt); + SwapSides( *edge1 , *edge2 ); + SwapPolyIndexes( *edge1 , *edge2 ); +} +//---------------------------------------------------------------------- + +void Clipper::CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2) +{ + //when a polygon is split into 2 polygons, make sure any holes the original + //polygon contained link to the correct polygon ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + { + OutRec *orec = m_PolyOuts[i]; + if (orec->isHole && orec->bottomPt && orec->FirstLeft == outRec1 && + !PointInPolygon(orec->bottomPt->pt, outRec1->pts, m_UseFullRange)) + orec->FirstLeft = outRec2; + } +} +//---------------------------------------------------------------------- + +void Clipper::CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2) +{ + //if a hole is owned by outRec2 then make it owned by outRec1 ... + for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) + if (m_PolyOuts[i]->isHole && m_PolyOuts[i]->bottomPt && + m_PolyOuts[i]->FirstLeft == outRec2) + m_PolyOuts[i]->FirstLeft = outRec1; +} +//---------------------------------------------------------------------- + +void Clipper::JoinCommonEdges(bool fixHoleLinkages) +{ + for (JoinList::size_type i = 0; i < m_Joins.size(); i++) + { + JoinRec* j = m_Joins[i]; + OutRec *outRec1 = m_PolyOuts[j->poly1Idx]; + OutPt *pp1a = outRec1->pts; + OutRec *outRec2 = m_PolyOuts[j->poly2Idx]; + OutPt *pp2a = outRec2->pts; + IntPoint pt1 = j->pt2a, pt2 = j->pt2b; + IntPoint pt3 = j->pt1a, pt4 = j->pt1b; + if (!FindSegment(pp1a, pt1, pt2)) continue; + if (j->poly1Idx == j->poly2Idx) + { + //we're searching the same polygon for overlapping segments so + //segment 2 mustn't be the same as segment 1 ... + pp2a = pp1a->next; + if (!FindSegment(pp2a, pt3, pt4) || (pp2a == pp1a)) continue; + } + else if (!FindSegment(pp2a, pt3, pt4)) continue; + + if (!GetOverlapSegment(pt1, pt2, pt3, pt4, pt1, pt2)) continue; + + OutPt *p1, *p2, *p3, *p4; + OutPt *prev = pp1a->prev; + //get p1 & p2 polypts - the overlap start & endpoints on poly1 + if (PointsEqual(pp1a->pt, pt1)) p1 = pp1a; + else if (PointsEqual(prev->pt, pt1)) p1 = prev; + else p1 = InsertPolyPtBetween(pp1a, prev, pt1); + + if (PointsEqual(pp1a->pt, pt2)) p2 = pp1a; + else if (PointsEqual(prev->pt, pt2)) p2 = prev; + else if ((p1 == pp1a) || (p1 == prev)) + p2 = InsertPolyPtBetween(pp1a, prev, pt2); + else if (Pt3IsBetweenPt1AndPt2(pp1a->pt, p1->pt, pt2)) + p2 = InsertPolyPtBetween(pp1a, p1, pt2); else + p2 = InsertPolyPtBetween(p1, prev, pt2); + + //get p3 & p4 polypts - the overlap start & endpoints on poly2 + prev = pp2a->prev; + if (PointsEqual(pp2a->pt, pt1)) p3 = pp2a; + else if (PointsEqual(prev->pt, pt1)) p3 = prev; + else p3 = InsertPolyPtBetween(pp2a, prev, pt1); + + if (PointsEqual(pp2a->pt, pt2)) p4 = pp2a; + else if (PointsEqual(prev->pt, pt2)) p4 = prev; + else if ((p3 == pp2a) || (p3 == prev)) + p4 = InsertPolyPtBetween(pp2a, prev, pt2); + else if (Pt3IsBetweenPt1AndPt2(pp2a->pt, p3->pt, pt2)) + p4 = InsertPolyPtBetween(pp2a, p3, pt2); else + p4 = InsertPolyPtBetween(p3, prev, pt2); + + //p1.pt == p3.pt and p2.pt == p4.pt so join p1 to p3 and p2 to p4 ... + if (p1->next == p2 && p3->prev == p4) + { + p1->next = p3; + p3->prev = p1; + p2->prev = p4; + p4->next = p2; + } + else if (p1->prev == p2 && p3->next == p4) + { + p1->prev = p3; + p3->next = p1; + p2->next = p4; + p4->prev = p2; + } + else + continue; //an orientation is probably wrong + + if (j->poly2Idx == j->poly1Idx) + { + //instead of joining two polygons, we've just created a new one by + //splitting one polygon into two. + outRec1->pts = GetBottomPt(p1); + outRec1->bottomPt = outRec1->pts; + outRec1->bottomPt->idx = outRec1->idx; + outRec2 = CreateOutRec(); + m_PolyOuts.push_back(outRec2); + outRec2->idx = (int)m_PolyOuts.size()-1; + j->poly2Idx = outRec2->idx; + outRec2->pts = GetBottomPt(p2); + outRec2->bottomPt = outRec2->pts; + outRec2->bottomPt->idx = outRec2->idx; + + if (PointInPolygon(outRec2->pts->pt, outRec1->pts, m_UseFullRange)) + { + //outRec2 is contained by outRec1 ... + outRec2->isHole = !outRec1->isHole; + outRec2->FirstLeft = outRec1; + if (outRec2->isHole == Orientation(outRec2, m_UseFullRange)) + ReversePolyPtLinks(*outRec2->pts); + } else if (PointInPolygon(outRec1->pts->pt, outRec2->pts, m_UseFullRange)) + { + //outRec1 is contained by outRec2 ... + outRec2->isHole = outRec1->isHole; + outRec1->isHole = !outRec2->isHole; + outRec2->FirstLeft = outRec1->FirstLeft; + outRec1->FirstLeft = outRec2; + if (outRec1->isHole == Orientation(outRec1, m_UseFullRange)) + ReversePolyPtLinks(*outRec1->pts); + //make sure any contained holes now link to the correct polygon ... + if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2); + } else + { + outRec2->isHole = outRec1->isHole; + outRec2->FirstLeft = outRec1->FirstLeft; + //make sure any contained holes now link to the correct polygon ... + if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2); + } + + //now fixup any subsequent joins that match this polygon + for (JoinList::size_type k = i+1; k < m_Joins.size(); k++) + { + JoinRec* j2 = m_Joins[k]; + if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, p2)) + j2->poly1Idx = j->poly2Idx; + if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, p2)) + j2->poly2Idx = j->poly2Idx; + } + + //now cleanup redundant edges too ... + FixupOutPolygon(*outRec1); + FixupOutPolygon(*outRec2); + } else + { + //joined 2 polygons together ... + + //make sure any holes contained by outRec2 now link to outRec1 ... + if (fixHoleLinkages) CheckHoleLinkages2(outRec1, outRec2); + + //now cleanup redundant edges too ... + FixupOutPolygon(*outRec1); + + if (outRec1->pts) + { + outRec1->isHole = !Orientation(outRec1, m_UseFullRange); + if (outRec1->isHole && !outRec1->FirstLeft) + outRec1->FirstLeft = outRec2->FirstLeft; + } + + //delete the obsolete pointer ... + int OKIdx = outRec1->idx; + int ObsoleteIdx = outRec2->idx; + outRec2->pts = 0; + outRec2->bottomPt = 0; + outRec2->AppendLink = outRec1; + + //now fixup any subsequent Joins that match this polygon + for (JoinList::size_type k = i+1; k < m_Joins.size(); k++) + { + JoinRec* j2 = m_Joins[k]; + if (j2->poly1Idx == ObsoleteIdx) j2->poly1Idx = OKIdx; + if (j2->poly2Idx == ObsoleteIdx) j2->poly2Idx = OKIdx; + } + } + } +} +//------------------------------------------------------------------------------ + +void ReversePoints(Polygon& p) +{ + std::reverse(p.begin(), p.end()); +} +//------------------------------------------------------------------------------ + +void ReversePoints(Polygons& p) +{ + for (Polygons::size_type i = 0; i < p.size(); ++i) + ReversePoints(p[i]); +} + +//------------------------------------------------------------------------------ +// OffsetPolygon functions ... +//------------------------------------------------------------------------------ + +struct DoublePoint +{ + double X; + double Y; + DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} +}; +//------------------------------------------------------------------------------ + +Polygon BuildArc(const IntPoint &pt, + const double a1, const double a2, const double r) +{ + long64 steps = std::max(6, int(std::sqrt(std::fabs(r)) * std::fabs(a2 - a1))); + if (steps > 0x100000) steps = 0x100000; + int n = (unsigned)steps; + Polygon result(n); + double da = (a2 - a1) / (n -1); + double a = a1; + for (int i = 0; i < n; ++i) + { + result[i].X = pt.X + Round(std::cos(a)*r); + result[i].Y = pt.Y + Round(std::sin(a)*r); + a += da; + } + return result; +} +//------------------------------------------------------------------------------ + +DoublePoint GetUnitNormal( const IntPoint &pt1, const IntPoint &pt2) +{ + if(pt2.X == pt1.X && pt2.Y == pt1.Y) + return DoublePoint(0, 0); + + double dx = (double)(pt2.X - pt1.X); + double dy = (double)(pt2.Y - pt1.Y); + double f = 1 *1.0/ std::sqrt( dx*dx + dy*dy ); + dx *= f; + dy *= f; + return DoublePoint(dy, -dx); +} + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +class PolyOffsetBuilder +{ +private: + Polygons m_p; + Polygon* m_curr_poly; + std::vector normals; + double m_delta, m_RMin, m_R; + size_t m_i, m_j, m_k; + static const int buffLength = 128; + JoinType m_jointype; + +public: + +PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys, + double delta, JoinType jointype, double MiterLimit) +{ + //nb precondition - out_polys != ptsin_polys + if (NEAR_ZERO(delta)) + { + out_polys = in_polys; + return; + } + + this->m_p = in_polys; + this->m_delta = delta; + this->m_jointype = jointype; + if (MiterLimit <= 1) MiterLimit = 1; + m_RMin = 2/(MiterLimit*MiterLimit); + + double deltaSq = delta*delta; + out_polys.clear(); + out_polys.resize(in_polys.size()); + for (m_i = 0; m_i < in_polys.size(); m_i++) + { + m_curr_poly = &out_polys[m_i]; + size_t len = in_polys[m_i].size(); + if (len > 1 && m_p[m_i][0].X == m_p[m_i][len - 1].X && + m_p[m_i][0].Y == m_p[m_i][len-1].Y) len--; + + //when 'shrinking' polygons - to minimize artefacts + //strip those polygons that have an area < pi * delta^2 ... + double a1 = Area(in_polys[m_i]); + if (delta < 0) { if (a1 > 0 && a1 < deltaSq *pi) len = 0; } + else if (a1 < 0 && -a1 < deltaSq *pi) len = 0; //holes have neg. area + + if (len == 0 || (len < 3 && delta <= 0)) + continue; + else if (len == 1) + { + Polygon arc; + arc = BuildArc(in_polys[m_i][len-1], 0, 2 * pi, delta); + out_polys[m_i] = arc; + continue; + } + + //build normals ... + normals.clear(); + normals.resize(len); + normals[len-1] = GetUnitNormal(in_polys[m_i][len-1], in_polys[m_i][0]); + for (m_j = 0; m_j < len -1; ++m_j) + normals[m_j] = GetUnitNormal(in_polys[m_i][m_j], in_polys[m_i][m_j+1]); + + m_k = len -1; + for (m_j = 0; m_j < len; ++m_j) + { + switch (jointype) + { + case jtMiter: + { + m_R = 1 + (normals[m_j].X*normals[m_k].X + + normals[m_j].Y*normals[m_k].Y); + if (m_R >= m_RMin) DoMiter(); else DoSquare(MiterLimit); + break; + } + case jtSquare: DoSquare(); break; + case jtRound: DoRound(); break; + } + m_k = m_j; + } + } + + //finally, clean up untidy corners using Clipper ... + Clipper clpr; + clpr.AddPolygons(out_polys, ptSubject); + if (delta > 0) + { + if (!clpr.Execute(ctUnion, out_polys, pftPositive, pftPositive)) + out_polys.clear(); + } + else + { + IntRect r = clpr.GetBounds(); + Polygon outer(4); + outer[0] = IntPoint(r.left - 10, r.bottom + 10); + outer[1] = IntPoint(r.right + 10, r.bottom + 10); + outer[2] = IntPoint(r.right + 10, r.top - 10); + outer[3] = IntPoint(r.left - 10, r.top - 10); + + clpr.AddPolygon(outer, ptSubject); + if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative)) + { + out_polys.erase(out_polys.begin()); + ReversePoints(out_polys); + + } else + out_polys.clear(); + } +} +//------------------------------------------------------------------------------ + +private: + +void AddPoint(const IntPoint& pt) +{ + Polygon::size_type len = m_curr_poly->size(); + if (len == m_curr_poly->capacity()) + m_curr_poly->reserve(len + buffLength); + m_curr_poly->push_back(pt); +} +//------------------------------------------------------------------------------ + +void DoSquare(double mul = 1.0) +{ + IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), + (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); + IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), + (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); + double sinAngle = normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y; + if (sinAngle * m_delta >= 0) + { + //occasionally (due to floating point math) sinAngle can be > 1 so ... + if (sinAngle > 1) sinAngle = 1; else if (sinAngle < -1) sinAngle = -1; + double dx = tan((pi - asin(sinAngle))/4) * abs(m_delta*mul); + pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx), + (long64)(pt1.Y + normals[m_k].X * dx)); + AddPoint(pt1); + pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx), + (long64)(pt2.Y -normals[m_j].X * dx)); + AddPoint(pt2); + } + else + { + AddPoint(pt1); + AddPoint(m_p[m_i][m_j]); + AddPoint(pt2); + } +} +//------------------------------------------------------------------------------ + +void DoMiter() +{ + if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0) + { + double q = m_delta / m_R; + AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X + + (normals[m_k].X + normals[m_j].X) * q), + (long64)Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q))); + } + else + { + IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * + m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); + IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * + m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); + AddPoint(pt1); + AddPoint(m_p[m_i][m_j]); + AddPoint(pt2); + } +} +//------------------------------------------------------------------------------ + +void DoRound() +{ + IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), + (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); + IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), + (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); + AddPoint(pt1); + //round off reflex angles (ie > 180 deg) unless almost flat (ie < ~10deg). + if ((normals[m_k].X*normals[m_j].Y - normals[m_j].X*normals[m_k].Y) * m_delta >= 0) + { + if (normals[m_j].X * normals[m_k].X + normals[m_j].Y * normals[m_k].Y < 0.985) + { + double a1 = std::atan2(normals[m_k].Y, normals[m_k].X); + double a2 = std::atan2(normals[m_j].Y, normals[m_j].X); + if (m_delta > 0 && a2 < a1) a2 += pi *2; + else if (m_delta < 0 && a2 > a1) a2 -= pi *2; + Polygon arc = BuildArc(m_p[m_i][m_j], a1, a2, m_delta); + for (Polygon::size_type m = 0; m < arc.size(); m++) + AddPoint(arc[m]); + } + } + else + AddPoint(m_p[m_i][m_j]); + AddPoint(pt2); +} +//-------------------------------------------------------------------------- + +}; //end PolyOffsetBuilder + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys, + double delta, JoinType jointype, double MiterLimit) +{ + if (&out_polys == &in_polys) + { + Polygons poly2(in_polys); + PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit); + } + else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys) +{ + Clipper c; + c.AddPolygon(in_poly, ptSubject); + c.Execute(ctUnion, out_polys); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys) +{ + Clipper c; + c.AddPolygons(in_polys, ptSubject); + c.Execute(ctUnion, out_polys); +} +//------------------------------------------------------------------------------ + +void SimplifyPolygons(Polygons &polys) +{ + SimplifyPolygons(polys, polys); +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, IntPoint& p) +{ + s << p.X << ' ' << p.Y << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, Polygon &p) +{ + for (Polygon::size_type i = 0; i < p.size(); i++) + s << p[i]; + s << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +std::ostream& operator <<(std::ostream &s, Polygons &p) +{ + for (Polygons::size_type i = 0; i < p.size(); i++) + s << p[i]; + s << "\n"; + return s; +} +//------------------------------------------------------------------------------ + +} //ClipperLib namespace diff --git a/polygon/clipper.hpp b/polygon/clipper.hpp new file mode 100644 index 0000000000..26ad6281e6 --- /dev/null +++ b/polygon/clipper.hpp @@ -0,0 +1,306 @@ +/******************************************************************************* +* * +* Author : Angus Johnson * +* Version : 4.8.5 * +* Date : 15 July 2012 * +* Website : http://www.angusj.com * +* Copyright : Angus Johnson 2010-2012 * +* * +* License: * +* Use, modification & distribution is subject to Boost Software License Ver 1. * +* http://www.boost.org/LICENSE_1_0.txt * +* * +* Attributions: * +* The code in this library is an extension of Bala Vatti's clipping algorithm: * +* "A generic solution to polygon clipping" * +* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * +* http://portal.acm.org/citation.cfm?id=129906 * +* * +* Computer graphics and geometric modeling: implementation and algorithms * +* By Max K. Agoston * +* Springer; 1 edition (January 4, 2005) * +* http://books.google.com/books?q=vatti+clipping+agoston * +* * +* See also: * +* "Polygon Offsetting by Computing Winding Numbers" * +* Paper no. DETC2005-85513 pp. 565-575 * +* ASME 2005 International Design Engineering Technical Conferences * +* and Computers and Information in Engineering Conference (IDETC/CIE2005) * +* September 24–28, 2005 , Long Beach, California, USA * +* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * +* * +*******************************************************************************/ + +#ifndef clipper_hpp +#define clipper_hpp + +#include +#include +#include +#include +#include + +namespace ClipperLib { + +enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; +enum PolyType { ptSubject, ptClip }; +//By far the most widely used winding rules for polygon filling are +//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) +//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) +//see http://glprogramming.com/red/chapter11.html +enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; + +typedef signed long long long64; +typedef unsigned long long ulong64; + +struct IntPoint { +public: + long64 X; + long64 Y; + IntPoint(long64 x = 0, long64 y = 0): X(x), Y(y) {}; + friend std::ostream& operator <<(std::ostream &s, IntPoint &p); +}; + +typedef std::vector< IntPoint > Polygon; +typedef std::vector< Polygon > Polygons; + +std::ostream& operator <<(std::ostream &s, Polygon &p); +std::ostream& operator <<(std::ostream &s, Polygons &p); + +struct ExPolygon { + Polygon outer; + Polygons holes; +}; +typedef std::vector< ExPolygon > ExPolygons; + +enum JoinType { jtSquare, jtRound, jtMiter }; + +bool Orientation(const Polygon &poly); +double Area(const Polygon &poly); +void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys, + double delta, JoinType jointype = jtSquare, double MiterLimit = 2); +void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys); +void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys); +void SimplifyPolygons(Polygons &polys); + +void ReversePoints(Polygon& p); +void ReversePoints(Polygons& p); + +//used internally ... +enum EdgeSide { esNeither = 0, esLeft = 1, esRight = 2, esBoth = 3 }; +enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 }; + +struct TEdge { + long64 xbot; + long64 ybot; + long64 xcurr; + long64 ycurr; + long64 xtop; + long64 ytop; + double dx; + long64 tmpX; + PolyType polyType; + EdgeSide side; + int windDelta; //1 or -1 depending on winding direction + int windCnt; + int windCnt2; //winding count of the opposite polytype + int outIdx; + TEdge *next; + TEdge *prev; + TEdge *nextInLML; + TEdge *nextInAEL; + TEdge *prevInAEL; + TEdge *nextInSEL; + TEdge *prevInSEL; +}; + +struct IntersectNode { + TEdge *edge1; + TEdge *edge2; + IntPoint pt; + IntersectNode *next; +}; + +struct LocalMinima { + long64 Y; + TEdge *leftBound; + TEdge *rightBound; + LocalMinima *next; +}; + +struct Scanbeam { + long64 Y; + Scanbeam *next; +}; + +struct OutPt; //forward declaration + +struct OutRec { + int idx; + bool isHole; + OutRec *FirstLeft; + OutRec *AppendLink; + OutPt *pts; + OutPt *bottomPt; + OutPt *bottomFlag; + EdgeSide sides; +}; + +struct OutPt { + int idx; + IntPoint pt; + OutPt *next; + OutPt *prev; +}; + +struct JoinRec { + IntPoint pt1a; + IntPoint pt1b; + int poly1Idx; + IntPoint pt2a; + IntPoint pt2b; + int poly2Idx; +}; + +struct HorzJoinRec { + TEdge *edge; + int savedIdx; +}; + +struct IntRect { long64 left; long64 top; long64 right; long64 bottom; }; + +typedef std::vector < OutRec* > PolyOutList; +typedef std::vector < TEdge* > EdgeList; +typedef std::vector < JoinRec* > JoinList; +typedef std::vector < HorzJoinRec* > HorzJoinList; + +//ClipperBase is the ancestor to the Clipper class. It should not be +//instantiated directly. This class simply abstracts the conversion of sets of +//polygon coordinates into edge objects that are stored in a LocalMinima list. +class ClipperBase +{ +public: + ClipperBase(); + virtual ~ClipperBase(); + bool AddPolygon(const Polygon &pg, PolyType polyType); + bool AddPolygons( const Polygons &ppg, PolyType polyType); + virtual void Clear(); + IntRect GetBounds(); +protected: + void DisposeLocalMinimaList(); + TEdge* AddBoundsToLML(TEdge *e); + void PopLocalMinima(); + virtual void Reset(); + void InsertLocalMinima(LocalMinima *newLm); + LocalMinima *m_CurrentLM; + LocalMinima *m_MinimaList; + bool m_UseFullRange; + EdgeList m_edges; +}; + +class Clipper : public virtual ClipperBase +{ +public: + Clipper(); + ~Clipper(); + bool Execute(ClipType clipType, + Polygons &solution, + PolyFillType subjFillType = pftEvenOdd, + PolyFillType clipFillType = pftEvenOdd); + bool Execute(ClipType clipType, + ExPolygons &solution, + PolyFillType subjFillType = pftEvenOdd, + PolyFillType clipFillType = pftEvenOdd); + void Clear(); + bool ReverseSolution() {return m_ReverseOutput;}; + void ReverseSolution(bool value) {m_ReverseOutput = value;}; +protected: + void Reset(); + virtual bool ExecuteInternal(bool fixHoleLinkages); +private: + PolyOutList m_PolyOuts; + JoinList m_Joins; + HorzJoinList m_HorizJoins; + ClipType m_ClipType; + Scanbeam *m_Scanbeam; + TEdge *m_ActiveEdges; + TEdge *m_SortedEdges; + IntersectNode *m_IntersectNodes; + bool m_ExecuteLocked; + PolyFillType m_ClipFillType; + PolyFillType m_SubjFillType; + bool m_ReverseOutput; + void DisposeScanbeamList(); + void SetWindingCount(TEdge& edge); + bool IsEvenOddFillType(const TEdge& edge) const; + bool IsEvenOddAltFillType(const TEdge& edge) const; + void InsertScanbeam(const long64 Y); + long64 PopScanbeam(); + void InsertLocalMinimaIntoAEL(const long64 botY); + void InsertEdgeIntoAEL(TEdge *edge); + void AddEdgeToSEL(TEdge *edge); + void CopyAELToSEL(); + void DeleteFromSEL(TEdge *e); + void DeleteFromAEL(TEdge *e); + void UpdateEdgeIntoAEL(TEdge *&e); + void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); + bool IsContributing(const TEdge& edge) const; + bool IsTopHorz(const long64 XPos); + void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); + void DoMaxima(TEdge *e, long64 topY); + void ProcessHorizontals(); + void ProcessHorizontal(TEdge *horzEdge); + void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + void AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); + void AppendPolygon(TEdge *e1, TEdge *e2); + void DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt); + void DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt); + void DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt); + void IntersectEdges(TEdge *e1, TEdge *e2, + const IntPoint &pt, IntersectProtects protects); + OutRec* CreateOutRec(); + void AddOutPt(TEdge *e, const IntPoint &pt); + void DisposeBottomPt(OutRec &outRec); + void DisposeAllPolyPts(); + void DisposeOutRec(PolyOutList::size_type index); + bool ProcessIntersections(const long64 botY, const long64 topY); + void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt); + void BuildIntersectList(const long64 botY, const long64 topY); + void ProcessIntersectList(); + void ProcessEdgesAtTopOfScanbeam(const long64 topY); + void BuildResult(Polygons& polys); + void BuildResultEx(ExPolygons& polys); + void SetHoleState(TEdge *e, OutRec *OutRec); + void DisposeIntersectNodes(); + bool FixupIntersections(); + void FixupOutPolygon(OutRec &outRec); + bool IsHole(TEdge *e); + void FixHoleLinkage(OutRec *outRec); + void CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2); + void CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2); + void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx = -1); + void ClearJoins(); + void AddHorzJoin(TEdge *e, int idx); + void ClearHorzJoins(); + void JoinCommonEdges(bool fixHoleLinkages); +}; + +//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ + +class clipperException : public std::exception +{ + public: + clipperException(const char* description): m_descr(description) {} + virtual ~clipperException() throw() {} + virtual const char* what() const throw() {return m_descr.c_str();} + private: + std::string m_descr; +}; +//------------------------------------------------------------------------------ + +} //ClipperLib namespace + +#endif //clipper_hpp + + diff --git a/polygon/kbool/CMakeLists.txt b/polygon/kbool/CMakeLists.txt deleted file mode 100644 index bd20e13cf9..0000000000 --- a/polygon/kbool/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -project(kbool) - -subdirs(src) diff --git a/polygon/kbool/include/kbool/_dl_itr.cpp b/polygon/kbool/include/kbool/_dl_itr.cpp deleted file mode 100644 index 0f988fdd9a..0000000000 --- a/polygon/kbool/include/kbool/_dl_itr.cpp +++ /dev/null @@ -1,2376 +0,0 @@ -/*! \file _dl_itr.cpp - \brief Double Linked list with Iterators on list - \author Probably Klaas Holwerda - - Copyright: 2001-2004 (C) Probably Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: _dl_itr.cpp,v 1.5 2009/04/23 19:35:24 titato Exp $ -*/ - -#ifdef __UNIX__ -#include "kbool/_dl_itr.h" -#endif - -//======================================================================= -// implementation class DL_Node -//======================================================================= -/*! \class DL_Node -* This class is used in the class DL_List to contain the items of the list. This can be a -* pointer to an object or the object itself. The class contains a next and a previous pointer -* to connect the nodes in the list. \n -* class Dtype | Object stored at the node -*/ - - - -/*! -Construct a node for a list object -\param it Item the node will contain -*/ -template -DL_Node::DL_Node( Dtype it ) // + init nodeitem - : _item( it ) -{} - -/*! - Template constructor no contents - Construct a node for a list object -*/ -template -DL_Node::DL_Node() - : _item( 0 ) -{} - -/*! -Destruct a node object -*/ -template -DL_Node::~DL_Node() -{} - - -//======================================================================= -// implementation class DL_List -//======================================================================= -/*! \class DL_List -* class is the base class for implementing a double linked list. The Root node marks the begining and end of the list. The -* lists consists of nodes double linked with a next and previous pointer DL_Node The nodes are cyclic connected to the root -* node. The list is meant to be used with an iterator class, to traverse the nodes. More then 1 iterator can be attached to the -* list. The list keeps track of the number of iterators that are attached to it. Depending on this certain operations are allowed -* are not. For instance a node can only be deleted if there is only one iterator attached to the list. -* class | Dtype | Object contaning List Nodes -*/ - -/*! -Construct a node object -\par Example: - How to construct a list of type integer: -\code - DL_List * a_list = new DL_List(); -\endcode -*/ -template -DL_List::DL_List() - : _nbitems( 0 ), _iterlevel( 0 ) -{ - _root = new DL_Node(); - _root->_next = _root; - _root->_prev = _root; -} - - -/*! -//Destruct a list object -\par Example: - How to construct a list of type integer: -\code - DL_List * a_list = new DL_List(); # declaration and allocation - delete a_list; #delete it (must have no iterators attached to it) -\endcode -*/ -template -DL_List::~DL_List() -{ - if ( _iterlevel != 0 ) - throw Bool_Engine_Error( "DL_List::~DL_List()\n_iterlevel > 0 ", "list error", 0, 1 ); - - remove_all( false ); - delete _root; - _root = 0;_nbitems = 0; //reset memory used (no lost pointers) -} - -/*! -Error report for list error inside DL_List class -the error function is used internally in the list class to report errors, -the function will generate a message based on the error code. -Then an exeption will be generated using the global booleng class instance. \n -tcarg: class | Dtype | item object in list -\par Example - to call error from inside an DL_List class -\code -Error("remove_all",ITER_GT_O); -\endcode -\param function string that generated this error -\param error code to generate a message for -*/ -template -void DL_List::Error( string function, Lerror a_error ) -{ - string buf; - buf += "DL_List::"; - buf += function; - switch ( a_error ) - { - case NO_MES: buf += ""; break; - case EMPTY: buf += "list is empty"; break; - case ITER_GT_0: buf += "more then zero iter"; break; - case NO_LIST: buf += "no list attached"; break; - case SAME_LIST: buf += "same list not allowed"; break; - case AC_ITER_LIST_OTHER: buf += "iter not allowed on other list"; break; - default: buf += "unhandled error"; break; - } - - throw Bool_Engine_Error( buf, "list error", 0, 1 ); -} - -/*! -is list empty (contains items or not)? \n -class | Dtype | item object in list -\return returns true is list is empty else false -\par Example - too see if list is empty -\code -DL_List _intlist; #create a list of integers - - if (_intlist.Empty()) - - cout << "empty"; -\endcode -*/ -template -bool DL_List::empty() -{ - return( bool )( _nbitems == 0 ); -} - -/*! - number of items in list \n - class | Dtype | item object in list -\return return number of items in the list -\par Example - too see if list contains only one object -\code -DL_List _intlist; #create a list of integers - - if (_intlist.count() == 1) - - cout << "one object in list"; -\endcode -*/ -template -int DL_List::count() -{ - return _nbitems; -} - -/*! - remove all objects from the list\n - class | Dtype | item object in list -\note - The objects itself are not deleted, only removed from the list. - The user is responsible for memory management. - -\note - The iterator level must be zero to be able to use this function, - else an error will be generated - -\note - Use this function if an iterator is not needed to do more complex things. - This will save time, since the iterator does not have to be created. -\par Example - too insert integer a and b into list and remove_all directly -\code - DL_List _intlist; #create a list of integers - int a=123; - - int b=345; - - _intlist.insbegin(a); - - _intlist.insbegin(b); - - _intlist.remove_all(); -\endcode -*/ -template -void DL_List::remove_all( bool deleteObject ) -{ - if ( _iterlevel > 0 ) - Error( "remove_all()", ITER_GT_0 ); - - Dtype* obj; - - DL_Node *node; - for ( int i = 0; i < _nbitems; i++ ) - { - node = _root->_next; - _root->_next = node->_next; - if ( deleteObject == true ) - { - obj = ( Dtype* )( node->_item ); - delete obj; - } - delete node; - } - _nbitems = 0;_iterlevel = 0; //reset memory used (no lost pointers) - _root->_prev = _root; -} - -/*! -remove the object at the begin of the list (head). -\note - The object itself is not deleted, only removed from the list. - The user is responsible for memory management. - -\note - The iterator level must be zero to be able to use this function, else an error will be generated - -\note - The list must contain objects, else an error will be generated. - -\note -Use this function if an iterator is not needed to do more complex things. This will save time, since the iterator does not -have to be created. - -\par Example: - too insert integer a at begin of list and remove it directly. -\code -DL_List _intlist; #create a list of integers - - int a=123; - - _intlist.insbegin(a) - - _intlist.removehead(); - -\endcode -*/ -template -void DL_List::removehead() -{ - if ( _iterlevel > 0 ) - Error( "removehead()", ITER_GT_0 ); - if( _nbitems == 0 ) - Error( "removehead()", EMPTY ); - - DL_Node* node = _root->_next; - - node->_prev->_next = node->_next; // update forward link - node->_next->_prev = node->_prev; // update backward link - - _nbitems--; - delete node; // delete list node -} - - -/*! -remove the object at the begin of the list (head). - -\note - - The object itself is not deleted, only removed from the list. - The user is responsible for memory management. - - The iterator level must be zero to be able to use this function, - else an error will be generated - - The list must contain objects, else an error will be generated. - - Use this function if an iterator is not needed to do more complex things. - This will save time, since the iterator does not have to be created. - -\par Example: - too insert integer a at end of list and remove it directly. -\code -DL_List _intlist; #create a list of integers - - int a=123; - - _intlist.insend(a) - - _intlist.removetail(); - -\endcode -*/ -template -void DL_List::removetail() -{ - if ( _iterlevel > 0 ) - Error( "removetail()", ITER_GT_0 ); - if ( _nbitems == 0 ) - Error( "removehead()", EMPTY ); - - DL_Node* node = _root->_prev; - - node->_prev->_next = node->_next; // update forward link - node->_next->_prev = node->_prev; // update backward link - - _nbitems--; - delete node; // delete list node -} - -/*! -insert the object given at the end of the list, after tail -\note -The iterator level must be zero to be able to use this function, -else an error will be generated - -\note -Use this function if an iterator is not needed to do more complex things. -This will save time, since the iterator does not have to be created. -\par Example: -too insert integer a at end of list -\code - DL_List _intlist; #create a list of integers - - int a=123; - - _intlist.insend(a) -\endcode -\param newitem an object for which the template list was generated -*/ -template -DL_Node* DL_List::insend( Dtype newitem ) -{ - if ( _iterlevel > 0 ) - Error( "insend()", ITER_GT_0 ); - - DL_Node* newnode = new DL_Node( newitem ); - - newnode ->_next = _root; - newnode ->_prev = _root->_prev; - _root->_prev->_next = newnode; - _root->_prev = newnode; - - _nbitems++; - - return newnode; -} - -/*! -insert the object given at the begin of the list, before head -\note -The iterator level must be zero to be able to use this function, -else an error will be generated - -\note -Use this function if an iterator is not needed to do more complex things. -This will save time, since the iterator does not have to be created. - -\par Example: -too insert integer a at begin of list -\code - DL_List _intlist; #create a list of integers - - int a=123; - - _intlist.insbegin(a) -\endcode -\param newitem an object for which the template list was generated -*/ -template -DL_Node* DL_List::insbegin( Dtype newitem ) -{ - if ( _iterlevel > 0 ) - Error( "insbegin()", ITER_GT_0 ); - - DL_Node* newnode = new DL_Node( newitem ); - - newnode ->_prev = _root; - newnode ->_next = _root->_next; - _root->_next->_prev = newnode; - _root->_next = newnode; - - _nbitems++; - return newnode; -} - -/*! -get head item -\return returns the object at the head of the list. -\par Example: - too insert integer a and b into list and make c be the value of b - which is at head of list| -\code - DL_List _intlist; #create a list of integers - - int a=123; - - int b=345; - - int c; - - _intlist.insbegin(a) - - _intlist.insbegin(b) - c=_intlist.headitem() -\endcode -*/ -template -Dtype DL_List::headitem() -{ - return _root->_next->_item; -} - -/*! -get tail item -\return returns the object at the tail/end of the list. -\par Example: - too insert integer a and b into list and make c be the value of b which - is at the tail of list -\code - DL_List _intlist; #create a list of integers - - int a=123; - - int b=345; - - int c; - _intlist.insbegin(a) - _intlist.insbegin(b) - - c=_intlist.headitem() -\endcode -*/ -template -Dtype DL_List::tailitem() -{ - return _root->_prev->_item; -} - -/*! -* \note - The iterator level must be zero to be able to use this function, else an error will be generated - -* \note The list may not be the same list as this list -* \param otherlist the list to take the items from -*/ -template -void DL_List::takeover( DL_List* otherlist ) -{ - if ( otherlist == 0 ) - Error( "takeover(DL_List*)", NO_LIST ); - // no iterators allowed on otherlist - if ( otherlist->_iterlevel > 0 ) - Error( "takeover(DL_List*)", AC_ITER_LIST_OTHER ); - // otherlist not this list - else if ( otherlist == this ) - Error( "takeover(DL_List*)", SAME_LIST ); - - if ( otherlist->_nbitems == 0 ) - return; - - //link other list into this list at the end - _root->_prev->_next = otherlist->_root->_next; - otherlist->_root->_next->_prev = _root->_prev; - otherlist->_root->_prev->_next = _root; - _root->_prev = otherlist->_root->_prev; - - //empty other list - _nbitems += otherlist->_nbitems; - otherlist->_nbitems = 0; - otherlist->_root->_next = otherlist->_root; - otherlist->_root->_prev = otherlist->_root; -} - -//======================================================================= -// implementation class DL_Iter -//======================================================================= -/*! \class DL_Iter - template iterator for any list/node type\n - This class is the base class to attach/instantiate an iterator on a double linked list. \n - DL_List The iterator is used to traverse and perform functions on the nodes of a list. \n - More then 1 iterator can be attached to a list. The list keeps track of the - number of iterators that are attached to it. \n - Depending on this certain operations are allowed are not. For instance a node can - only be deleted if there is only one iterator attached to the list. \n - class | Dtype | Object for traversing a DL_List of the same Dtype -// \par Example - to insert integer a and b into list and remove_all directly using an iterator -\code - DL_List* a_list = new DL_List(); // declaration and allocation - - int a=123; - - int b=345; - - { - - DL_Iter* a_listiter=new DL_Iter(a_list); - - a_listiter->insbegin(a) - - a_listiter->insbegin(b) - - a_listiter->remove_all() - - } //to destruct the iterator before the list is deleted - - delete a_list; #delete it (must have no iterators attached to it) -\endcode -*/ - -/*! - Error report for list error inside DL_Iter class - the error function is used internally in the iterator class to report errors, - the function will generate a message based on the error code. - Then an exception will be generated using the global booleng class instance.| - \par Example - to call error from inside an DL_List class| - \code - Error("remove_all",ITER_GT_O); - \endcode - \param function: function string that generated this error - \param a_error: error code to generate a message for -*/ -template -void DL_Iter::Error( string function, Lerror a_error ) -{ - string buf; - buf = "DL_Iter::"; - buf += function; - switch ( a_error ) - { - case NO_MES: buf += ""; break; - case NO_LIST: buf += "no list attached"; break; - case NO_LIST_OTHER: buf += "no list on other iter"; break; - case AC_ITER_LIST_OTHER: buf += "iter not allowed on other list"; break; - case SAME_LIST: buf += "same list not allowed"; break; - case NOT_SAME_LIST: buf += "must be same list"; break; - case ITER_GT_1: buf += "more then one iter"; break; - case ITER_HITROOT: buf += "iter at root"; break; - case NO_ITEM: buf += "no item at current"; break; - case NO_NEXT: buf += "no next after current"; break; - case NO_PREV: buf += "no prev before current"; break; - case EMPTY: buf += "list is empty"; break; - case NOT_ALLOW: buf += "not allowed"; break; - case ITER_NEG: buf += "to much iters deleted"; break; - default: buf += "unhandled error"; break; - } - throw Bool_Engine_Error( buf, "list error", 0, 1 ); -} - -/*! - Construct an iterator object for a given list of type Dtype \n - tcarg: class | Dtype | list item object -\par Example - How to construct a list of type integer and an iterator for it: -\code - DL_List* IntegerList; - IntegerList = new DL_List(); - DL_Iter* a_listiter=new DL_Iter(IntegerList); -\endcode -\param newlist: list for the iterator -*/ -template -DL_Iter:: DL_Iter( DL_List* newlist ) - : _list( newlist ), _current( RT ) -{ - _list->_iterlevel++; // add 1 to DL_Iters on list -} - -/*! -This constructs an iterator for a list using an other iterator on the same list, -The new iterator will be pointing to the same list item as the other iterator.\n -tcarg: class | Dtype | list item object -\par Example - How to construct a list of type integer and a second iterator for it:| -\code - DL_List* IntegerList; - - IntegerList = new DL_List(); - - DL_Iter* a_listiter=new DL_Iter(IntegerList); - - DL_Iter* a_secondlistiter=new DL_Iter(a_listiter); -\endcode -\param otheriter other iterator on same list -*/ -template -DL_Iter:: DL_Iter( DL_Iter* otheriter ) -{ - if ( otheriter->_current == 0 ) - Error( "DL_Iter(otheriter)", NO_LIST_OTHER ); - _list = otheriter->_list; - _list->_iterlevel++; // add 1 to DL_Iters on List - _current = otheriter->_current; -} - -/*! -This constructs an iterator for a list of a given type, the list does not have to exist. -Later on when a list is constructed,the iterator can be attached to it. -This way an iterator to a specific list can be made static to a class, and can be used -for several lists at the same time. \n -tcarg: class | Dtype | list item object - -\par Example - How to construct an iterator, without having a list first. - This constructs an iterator for a list of the given type, but the list thus not yet exist. -\code - DL_Iter* a_iter=new DL_Iter(); - - DL_List* IntegerList; - - IntegerList = new DL_List(); - - a_iter.Attach(IntegerList); - - a_iter.insend(123); - - a_iter.Detach(); -\endcode -*/ -template -DL_Iter:: DL_Iter() - : _list( 0 ), _current( 0 ) -{} - -/*! -destruct an iterator for a list of a given type. -*/ -template -DL_Iter::~DL_Iter() -{ - if ( _current == 0 ) - return; - _list->_iterlevel--; // decrease iterators - if ( _list->_iterlevel < 0 ) - Error( "~DL_Iter()", ITER_NEG ); -} - -/*! -This attaches an iterator to a list of a given type, the list must exist. -This way an iterator to a specific list can be made -static to a class, and can be used for several lists at the same time.\n -!tcarg: class | Dtype | list item object -\par Example - How to construct an iterator, without having a list first, and attach an iterator later:| -\code -DL_Iter* a_iter=new DL_Iter(); - -DL_List* IntegerList; - -IntegerList = new DL_List(); - -a_iter.Attach(IntegerList); - -a_iter.insend(123); - -a_iter.Detach(); -\endcode -\param newlist the list to attached the iterator to -*/ -template -void DL_Iter::Attach( DL_List* newlist ) -{ - if ( _current != 0 ) - Error( "Attach(list)", NOT_ALLOW ); - _list = newlist; - _current = HD; - _list->_iterlevel++; // add 1 to DL_Iters on list -} - -/*! -This detaches an iterator from a list of a given type, the list must exist. -This way an iterator to a specific list can be made static to a class, -and can be used for several lists at the same time. \n -!tcarg: class | Dtype | list item object -\par Example: -How to construct an iterator, without having a list first, and attach an iterator later: -\code -DL_Iter* a_iter=new DL_Iter(); - -DL_List* IntegerList; - -IntegerList = new DL_List(); - -a_iter.Attach(IntegerList); - -a_iter.insend(123); - -a_iter.Detach(); -\endcode -\param newlist: the list to attached the iterator to -*/ -template -void DL_Iter::Detach() -{ - if ( _current == 0 ) - Error( "Attach()", NO_LIST ); - _list->_iterlevel--; // subtract 1 from DL_Iters on list - _list = 0; - _current = 0; -} - -/* -// copy pointers to items from other list -template void DL_Iter::merge(DL_List* otherlist) -{ - DL_Node* node=otherlist->HD; //can be 0 if empty - for(int i=0; iNB; i++) - { - insend(node->new_item); // insert item at end - node=node->_next; // next item of otherlist - } -} -*/ -/* -//call Dtype::mfp for each item -template -void DL_Iter::foreach_mf(void (Dtype::*mfp)()) -{ - DL_Node* node=HD; //can be 0 if empty - for(int i=0; i< NB; i++) - { - ((node->_item).*mfp)(); - node=node->_next; - } -} -*/ - - -/*! call given function for each item*/ -template -void DL_Iter::foreach_f( void ( *fp ) ( Dtype n ) ) -{ - DL_Node* node = HD; //can be 0 if empty - for( int i = 0; i < NB; i++ ) - { - fp ( node->_item ); - node = node->_next; - } -} - - -/*! -to move all objects in a list to the list of the iterator. -\note - The iterator level must be one to be able to use this function, - else an error will be generated - -\note - The list may not be the same list as the iterator list -\par Example - to take over all items in _intlist| -\code -DL_List _intlist; #create a list of integers - -DL_List _intlist2; #create a list of integers - -int a=123; - -DL_Iter* a_listiter2=new DL_Iter(&_intlist2); - -_intlist->insend(a) // insert at end - -a_listiter2->takeover(_intlist) -\endcode -\param otherlist the list to take the items from -*/ -template -void DL_Iter::takeover( DL_List* otherlist ) -{ - if ( _current == 0 ) - Error( "takeover(DL_List*)", NO_LIST ); - // no iterators allowed on otherlist - if ( otherlist->_iterlevel > 0 ) - Error( "takeover(DL_List*)", AC_ITER_LIST_OTHER ); - // otherlist not this list - else if ( otherlist == _list ) - Error( "takeover(DL_List*)", SAME_LIST ); - - if ( otherlist->_nbitems == 0 ) - return; - - //link other list into this list at the end - TL->_next = otherlist->_root->_next; - otherlist->_root->_next->_prev = TL; - otherlist->_root->_prev->_next = RT; - TL = otherlist->_root->_prev; - - //empty other list - NB += otherlist->_nbitems; - otherlist->_nbitems = 0; - otherlist->_root->_next = otherlist->_root; - otherlist->_root->_prev = otherlist->_root; -} - - -/*! -to move all objects in a list (using iterator of that list) to the list of the iterator. -\note - The iterator level for both iterators must be one to be able to use this function, - -\note - else an error will be generated - -\note - The list may not be the same list as the iterator list - -\par Example - to take over all items in a_listiter1 it's list| -\code -DL_List _intlist; #create a list of integers - -DL_List _intlist2; #create a list of integers - -int a=123; - -DL_Iter* a_listiter1=new DL_Iter(&_intlist); - -DL_Iter* a_listiter2=new DL_Iter(&_intlist2); - -a_listiter1->insend(a) // insert at end - -a_listiter2->takeover(a_listiter1) -\\!to move all objects in a list (using iterator of that list) to the list of the iterator -\endcode -\param otheriter: the iterator to take the items from -*/ -template -void DL_Iter::takeover( DL_Iter* otheriter ) -{ - if ( otheriter->_current == 0 ) - Error( " DL_Iter", NO_LIST_OTHER ); - if ( _current == 0 ) - Error( " DL_Iter", NO_LIST ); - - // only one iterator allowed on other list? - if ( otheriter->_list->_iterlevel > 1 ) - Error( "takeover(DL_Iter*)", AC_ITER_LIST_OTHER ); - // otherlist not this list? - else if ( otheriter->_list == _list ) - Error( "takeover(DL_Iter*)", SAME_LIST ); - - if ( otheriter->NB == 0 ) - return; - - //link other list into this list at the end - TL->_next = otheriter->HD; - otheriter->HD->_prev = TL; - otheriter->TL->_next = RT; - TL = otheriter->TL; - - //empty other iter & list - NB += otheriter->NB; - otheriter->NB = 0; - otheriter->HD = otheriter->RT; - otheriter->TL = otheriter->RT; - otheriter->_current = otheriter->RT; -} - -/*! -to move maxcount objects in a list (using iterator of that list) -to the list of the iterator. -\note The iterator level for both iterators must be one to be able to use this function, - else an error will be generated - -\note The list may not be the same list as the iterator list - -\note If less then maxcount objects are available in the source iterator, - all of them are taken and no error will accur - -\par Example - to take over 1 item from a_listiter1 it's list -\code -DL_List _intlist; #create a list of integers - -DL_List _intlist2; #create a list of integers - -int a=123; - -DL_Iter* a_listiter1=new DL_Iter(&_intlist); - -DL_Iter* a_listiter2=new DL_Iter(&_intlist2); - -a_listiter1->insend(a) // insert at end - -a_listiter2->takeover(a_listiter1,1); -//! to move maxcount objects in a list (using iterator of that list) to the list of the iterator -\endcode -\param otheriter the iterator to take the items from -\param maxcount maximum number of objects to take over -*/ -template -void DL_Iter::takeover( DL_Iter* otheriter, int maxcount ) -{ - if ( otheriter->_current == 0 ) - Error( "takeover(DL_Iter*,int)", NO_LIST_OTHER ); - if ( _current == 0 ) - Error( "takeover(DL_Iter*,int)", NO_LIST ); - - if ( otheriter->_list->_iterlevel > 1 ) - Error( "takeover(DL_Iter*,int)", AC_ITER_LIST_OTHER ); - else if ( otheriter->_list == _list ) - Error( "takeover(DL_Iter*,int)", SAME_LIST ); - - if ( maxcount < 0 ) - Error( "takeover(DL_Iter*,int), maxcount < 0", NO_MES ); - - if ( otheriter->NB == 0 ) - return; - - - if ( otheriter->NB <= maxcount ) - { //take it all - //link other list into this list at the end - TL->_next = otheriter->HD; - otheriter->HD->_prev = TL; - otheriter->TL->_next = RT; - TL = otheriter->TL; - - //empty other iter & list - NB += otheriter->NB; - otheriter->NB = 0; - otheriter->HD = otheriter->RT; - otheriter->TL = otheriter->RT; - otheriter->_current = otheriter->RT; - } - else - { //take maxcount elements from otheriter - //set cursor in otherlist to element maxcount - DL_Node* node; - - if ( NB / 2 < maxcount ) - { // this is faster (1st half) - node = otheriter->HD; - for( int i = 1; i < maxcount; i++ ) - node = node->_next; - } - else - { // no, this is faster (2nd half) - node = otheriter->TL; - for( int i = NB; i > maxcount + 1; i-- ) - node = node->_prev; - } - - // link this->tail to other->head - if ( NB > 0 ) - { - TL->_next = otheriter->HD; - otheriter->HD->_prev = TL; - } - else // target is empty - { - HD = otheriter->HD; - otheriter->HD->_prev = RT; - } - - // set other root to node-> next (after last to copy) - otheriter->HD = node->_next; - otheriter->HD->_prev = otheriter->RT; - - // set this->tail to other->item()->prev (last element to be copied) - TL = node; - node->_next = RT; - - // still need to update element counter - NB += maxcount; - - // update other list - otheriter->NB -= maxcount; - otheriter->_current = otheriter->HD; // other->current is moved to this! - } -} - - -/*! -put the iterator root object before the current iterator position in the list. -The current object will become the new head of the list. -\note The iterator level must be one to be able to use this function, -else an error will be generated - -\par Example - move the root object to make the new head the old tail object| -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->insend(2345); -a_listiter->insend(3456); -a_listiter->totail(); -a_listiter->reset_head(); -a_listiter->tohead(); //the new head will be at object 3456 -\endcode -*/ -template -void DL_Iter::reset_head() -{ - if ( _current == 0 ) - Error( "reset_head()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "reset_head()", ITER_GT_1 ); - - if( _current == RT ) - Error( "reset head()", ITER_HITROOT ); - - //link out RT - HD->_prev = TL; - TL->_next = HD; - - //link in RT before current - HD = _current; - TL = _current->_prev; - - TL->_next = RT; - HD->_prev = RT; -} - -/*! -put the iterator root object after the current iterator position in the list. -The current object will become the new tail of the list. -\note - The iterator level must be one to be able to use this function, - else an error will be generated -\par Example - move the root object to make the new tail the old head object -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->insend(2345); -a_listiter->insend(3456); -a_listiter->tohead(); -a_listiter->reset_tail(); -a_listiter->totail(); //the new tail will be at object 1234 -\endcode -*/ -template -void DL_Iter::reset_tail() -{ - if ( _current == 0 ) - Error( "reset_tail()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "reset_tail()", ITER_GT_1 ); - - if( _current == RT ) - Error( "reset head()", ITER_HITROOT ); - - //link out RT - HD->_prev = TL; - TL->_next = HD; - - //link in RT after current - TL = _current; - HD = _current->_next; - - HD->_prev = RT; - TL->_next = RT; -} - -/*! -is list empty (contains items or not)? -\return returns true is list is empty else false -\par exmaple: - too see if list is empty -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -if (a_listiter->Empty()) - cout << "empty" -\endcode -*/ -template -bool DL_Iter::empty() -{ - if ( _current == 0 ) - Error( "empty()", NO_LIST ); - - return( bool )( NB == 0 ); -} - -/*! -is the iterator at the root of the list. -\note Traversing the list in a certain direction using a while loop, -the end can be tested with this function. -\return returns true if the iterator is at the root of the list (after the last/tail/head object), else false. -\par example: - to traverse in both directions| -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->tohead(); -//traverse forwards -while ( ! a_listiter->hitroot()) -{ - cout << "The item =" << a_listiter->item(); - a_listiter++; //goto next object -} - -a_listiter->totail(); -//traverse backwards -while ( ! a_listiter->hitroot()) -{ - cout << "The item =" << a_listiter->item(); - a_listiter--; //goto next object -} -\endcode -*/ -template -bool DL_Iter::hitroot() -{ - if ( _current == 0 ) - Error( "hitroot()", NO_LIST ); - - return( bool )( _current == RT ); -} - -/*! -is the iterator at the head of the list. -\return returns true if the iterator is at the head object of the list, else false. -\par exmaple: - too see the object at the head -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->tohead(); -if (a_listiter->athead()) - cout << "at the head The item =" << a_listiter->item(); -\endcode -*/ -template -bool DL_Iter::athead() -{ - if ( _current == 0 ) - Error( "athead()", NO_LIST ); - - return( bool )( _current == HD ); -} - -/*! -is the iterator at the tail of the list. -\return returns true if the iterator is at the tail object of the list, - else false. -\par Example - too see the object at the tail| -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->totail(); -if (a_listiter->attail()) - cout << "at the tail The item =" << a_listiter->item(); -\endcode -*/ -template -bool DL_Iter::attail() -{ - if ( _current == 0 ) - Error( "attail()", NO_LIST ); - - return( bool )( _current == TL ); -} - -/*! -does the iterator/list contain the given object -\return returns true if the iterator/list contains the given object in the list, else false. -\par Example - too see if the object is already in the list -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); -a_listiter->insend(1234); - -if (a_listiter->has(1234)) - cout << "yes it does"; -\endcode -\param otheritem item to search for -*/ -template -bool DL_Iter::has( Dtype otheritem ) -{ - if ( _current == 0 ) - Error( "has()", NO_LIST ); - - DL_Node* node = HD; //can be 0 if empty - for( int i = 0; i < NB; i++ ) - { - if ( node->_item == otheritem ) - return true; - node = node->_next; - } - return false; -} - -/*! -number of items in list -\return number of items in the list -\par Example: - to see if a list contains only one object -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); -if (a_listiter->count() == 1) - cout << "one object in list"; -\endcode -*/ -template -int DL_Iter::count() -{ - if ( _current == 0 ) - Error( "count()", NO_LIST ); - - return NB; -} - -/*! -go to first item, if list is empty goto hite -\par Example - set iterator to head of list -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->tohead(); -\endcode -*/ -template -void DL_Iter::tohead() -{ - if ( _current == 0 ) - Error( "tohead()", NO_LIST ); - - _current = HD; -} - -/*! -go to last item, if list is empty goto hite -\par Example - set iterator to tail of list -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->totail(); -\endcode -*/ -template -void DL_Iter::totail() -{ - if ( _current == 0 ) - Error( "totail()", NO_LIST ); - - _current = TL; -} - -/*! -set the iterator position to the root (empty dummy) object in the list. -\par Example - set iterator to root of list and iterate -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->toroot(); -while (a_listiter->iterate()) - cout << a_listiter->item(); -\endcode -*/ -template -void DL_Iter::toroot() -{ - if ( _current == 0 ) - Error( "toroot()", NO_LIST ); - - _current = RT; -} - -/*! -set the iterator position to next object in the list ( can be the root also)(prefix). -\par Example -how to iterate backwards -\code -DL_List _intlist; //create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->tohead(); -while (!a_listiter->hitroot()) -{ - cout << a_listiter->item(); - _listiter++; -} -\endcode -*/ -template -void DL_Iter::operator++( void ) -{ - if ( _current == 0 ) - Error( "operator++()", NO_LIST ); - - _current = _current->_next; -} - -/*! -set the iterator position to next object in the list ( can be the root also)(prefix). -\par Example -how to iterate backwards -\code -DL_List _intlist; //create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->tohead(); -while (!a_listiter->hitroot()) -{ - cout << a_listiter->item(); - ++_listiter; -} -\endcode -*/ -template -void DL_Iter::operator++( int ) -{ - if ( _current == 0 ) - Error( "operator++(int)", NO_LIST ); - - _current = _current->_next; -} - - -/*! -set the iterator position to previous object in the list ( can be the root also)(prefix). -\par Example -how to iterate backwards -\code -DL_List _intlist; //create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->totail(); -while (!a_listiter->hitroot()) -{ - cout << a_listiter->item(); - _listiter--; -} -\endcode -*/ -template -void DL_Iter::operator--( void ) -{ - if ( _current == 0 ) - Error( "operator++()", NO_LIST ); - - _current = _current->_prev; -} - - -/*! -set the iterator position to previous object in the list ( can be the root also)(prefix). -\par Example -how to iterate backwards -\code -DL_List _intlist; //create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->totail(); -while (!a_listiter->hitroot()) -{ - cout << a_listiter->item(); - --_listiter; -} -\endcode -*/ -template -void DL_Iter::operator--( int ) -{ - if ( _current == 0 ) - Error( "operator++(int)", NO_LIST ); - - _current = _current->_prev; -} - - -/*! -set the iterator position n objects in the next direction ( can be the root also). -\par Example: -how to set iterator 2 items forward -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); -a_listiter->insend(1234); -a_listiter->tohead(); -a_listiter>>2;//at root now -\endcode -\param n go n places forward -*/ -template -void DL_Iter::operator>>( int n ) -{ - if ( _current == 0 ) - Error( "operator>>()", NO_LIST ); - - for( int i = 0; i < n; i++ ) - _current = _current->_next; -} - - -/*! -set the iterator position n objects in the previous direction ( can be the root also). -\par Example: - how to set iterator 2 items backwards -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); -a_listiter->insend(1234); -a_listiter->totail(); -a_listiter<<2;//at root now -\endcode -\param n go n places back -*/ -template -void DL_Iter::operator<<( int n ) -{ - if ( _current == 0 ) - Error( "operator<<()", NO_LIST ); - - for( int i = 0; i < n; i++ ) - _current = _current->_prev; -} - - -/*! -put the iterator at the position of the given object in the list. -\return returns true if the object was in the list, else false -\par Example: - goto element 2345 -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->insend(2345); -a_listiter->insend(3456); - -a_listiter->toitem(2345); template -\endcode -*/ -template -bool DL_Iter::toitem( Dtype item ) -{ - if ( _current == 0 ) - Error( "toitem(item)", NO_LIST ); - DL_Node* node = HD; //can be 0 if empty - for( int i = 0; i < NB; i++ ) - { - if ( node->_item == item ) - { - _current = node; - return true; - } - node = node->_next; - } - return false; -} - -/*! -put the iterator at the same position as the given iterator in the list. -\par Example: - goto element 2345 and let a_listiter2 point to the same position -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); -DL_Iter* a_listiter2=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->insend(2345); -a_listiter->insend(3456); -a_listiter->toitem(2345); -a_listiter2->toiter(a_listiter2); -\endcode -\param otheriter other iterator to let this iterator point to. -*/ -template -void DL_Iter::toiter( DL_Iter *otheriter ) -{ - if ( otheriter->_current == 0 ) - Error( "toiter(otheriter)", NO_LIST ); - // both iters must have the same list - if ( _list != otheriter->_list ) - Error( "toiter(otheriter)", NOT_SAME_LIST ); - - _current = otheriter->_current; -} - - -/*! -put the iterator at the position of the given object in the list. -\note DO NOT use this function. Normally you will not be able to address the nodes in a list. -\return returns true if the node was in the list, else false -\param othernode a node to let this iterator point to. -*/ -template -bool DL_Iter::tonode( DL_Node *othernode ) -{ - DL_Node* node = HD; //can be 0 if empty //node is a temporary cursor - for( int i = 0; i < NB; i++ ) - { - if ( node == othernode ) - { - _current = othernode; - return true; - } - node = node->_next; - } - return false; -} - -/*! -advance the iterator one position in the next direction in the list. -\return returns true if not at the end/root of the list else false. - -\note This function combines iteration and testing for the end of -the list in one. - -\note Therefore we do not have to advance the iterator ourselves. - -\note -The iterator is first put to the next object, before testing for the end of the list. | -This is why we need to start at the root element in general usage. - -\par Example - iterate through all the items in a list -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->insend(2345); -a_listiter->insend(3456); -a_listiter->tobegin(2345); - -while (a_listiter->iterate()) -{ cout << a_listiter->item(); } -\endcode -*/ -template -bool DL_Iter::iterate( void ) -{ - if ( _current == 0 ) - Error( "iterate()", NO_LIST ); - - _current = _current->_next; - if ( _current == RT ) - return false; - return true; -} - -/*! -To get the item at the current iterator position -\return returns the object where the iterator is pointing to at the moment. -\note -If the iterator is at the root of the list an error will be generated, -since there is no item there. -\par Example: - get the element at the head of the list| -\code -DL_List _intlist; //create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->tohead(); -int theitem=a_listiter->item(); -\endcode -*/ -template -Dtype DL_Iter::item() -{ - if ( _current == 0 ) - Error( "item()", NO_LIST ); - if ( _current == RT ) - Error( "item()", NO_ITEM ); - - return _current->_item; -} - -//! get the node at iterater position -template -DL_Node* DL_Iter::node() -{ - if ( _current == 0 ) - Error( "item()", NO_LIST ); - if ( _current == RT ) - Error( "item()", NO_ITEM ); - - return _current; -} - -/*! -set the iterator position to next object in the list ( can be the root also). -\note Use this function inside a new class derived from DL_Iter. -*/ -template -void DL_Iter::next() -{ - if ( _current == 0 ) - Error( "item()", NO_LIST ); - - _current = _current->_next; -} - - -/*! -set the iterator position to next object in the list, if this would be the root object, -then set the iterator at the head object -\par Example -cycle the list twice -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->insend(2345); -a_listiter->tohead(); - -int count=2*a_listiter->count(); -while (count) -{ - cout << a_listiter->item(); - next_wrap(); - count--; -} -\endcode -*/ -template -void DL_Iter::next_wrap() -{ - if ( _current == 0 ) - Error( "item()", NO_LIST ); - - _current = _current->_next; - if ( _current == RT ) - _current = _current->_next; -} - - -/*! -set the iterator position to previous object in the list ( can be the root also). -\note Use this function inside a new class derived from DL_Iter. -*/ -template -void DL_Iter::prev() -{ - if ( _current == 0 ) - Error( "item()", NO_LIST ); - - _current = _current->_prev; -} - -/*! -set the iterator position to previous object in the list, if this would be the root object, -then set the iterator at the tail object -\par Example -cycle the list twice -\code -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(1234); -a_listiter->insend(2345); -a_listiter->totail(); - -int count=2*a_listiter->count(); -while (count) -{ - cout << a_listiter->item(); - prev_wrap(); - count--; -} -\endcode -*/ -template -void DL_Iter::prev_wrap() -{ - if ( _current == 0 ) - Error( "item()", NO_LIST ); - - _current = _current->_prev; - if ( _current == RT ) - _current = _current->_prev; -} - -template -void DL_Iter::remove_all() -{ - if ( _current == 0 ) - Error( "remove_all()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "remove_all()", ITER_GT_1 ); - - _list->_iterlevel--; - _list->remove_all(); - _list->_iterlevel++; - _current = RT; -} - -/*! -remove object at current iterator position from the list. -\note The object itself is not deleted, only removed from the list. The user is responsible for memory management. - -\note The iterator level must be one to be able to use this function, else an error will be generated - -\note The list must contain an object at the current iterator position, else an error will be generated. -\par Example: - to insert integer a at begin of list and remove it directly -\code -DL_List _intlist; #create a list of integers - -int a=123; - -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insbegin(a); - -a_listiter->tohead(); - -a_listiter->remove(); -\endcode -*/ -template -void DL_Iter::remove() -{ - if ( _current == 0 ) - Error( "remove()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "remove()", ITER_GT_1 ); - if ( _current == RT ) - Error( "remove()", ITER_HITROOT ); - - DL_Node* node = _current; - - _current = _current->_next; - - node->_prev->_next = node->_next; // update forward link - node->_next->_prev = node->_prev; // update backward link - - NB--; - delete node; // delete list node -} - -/*! -remove the object at the begin of the list using an iterator -\note The object itself is not deleted, only removed from the list. The user is responsible for memory management. - -\note The iterator level must be one to be able to use this function, else an error will be generated - -\note The list must contain objects, else an error will be generated. - -\note Use this function if an iterator is needed to do more complex things. Else use the list member functions directly. -\par Example: - to insert integer a at begin of list and remove it directly| -\code -DL_List _intlist; #create a list of integers - -int a=123; - -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insbegin(a); -a_listiter->removehead(); -\endcode -*/ -template -void DL_Iter::removehead() -{ - if ( _current == 0 ) - Error( "removehead()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "removehead()", ITER_GT_1 ); - if( NB == 0 ) - Error( "removehead()", EMPTY ); - - if ( _current == HD ) - _current = _current->_next; - - _list->_iterlevel--; - _list->removehead(); - _list->_iterlevel++; -} - - -/*! -//remove the object at the end of the list using an iterator -\note The object itself is not deleted, only removed from the list. The user is responsible for memory management. - -\note The iterator level must be one to be able to use this function, else an error will be generated - -\note The list must contain objects, else an error will be generated. - -\note Use this function if an iterator is needed to do more complex things. Else use the list member functions directly. -\par Example: - to insert integer a at end of list and remove it directly -\code -DL_List _intlist; #create a list of integers - -int a=123; - -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(a); -a_listiter->removetail(); -\endcode -*/ -template -void DL_Iter::removetail() -{ - if ( _current == 0 ) - Error( "removetail()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "removetail()", ITER_GT_1 ); - if ( NB == 0 ) - Error( "removehead()", EMPTY ); - - if ( _current == TL ) - _current = _current->_prev; - - _list->_iterlevel--; - _list->removetail(); - _list->_iterlevel++; - -} - -/*! -insert the object given at the end of the list - -\note The iterator level must be one to be able to use this function, else an error will be generated - -\note Use this function if an iterator is needed to do more complex things. Else use the list member functions directly. -\par Example: - to insert integer a at end of list| -\code -DL_List _intlist; #create a list of integers - -int a=123; - -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(a); -\endcode -*/ -template -DL_Node* DL_Iter::insend( Dtype newitem ) -{ - if ( _current == 0 ) - Error( "insend()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "insend()", ITER_GT_1 ); - - _list->_iterlevel--; - DL_Node* ret = _list->insend( newitem ); - _list->_iterlevel++; - return ret; -} - - -/*! -insert the object given at the begin of the list -\note The iterator level must be one to be able to use this function, else an error will be generated - -\note Use this function if an iterator is needed to do more complex things. Else use the list member functions directly. - -\par Example: - to insert integer a at begin of list| -\code -DL_List _intlist; #create a list of integers - -int a=123; - -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insbegin(a); -\endcode -\param newitem an object for which the template list/iterator was generated -*/ -template -DL_Node* DL_Iter::insbegin( Dtype newitem ) -{ - if ( _current == 0 ) - Error( "insbegin()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "insbegin()", ITER_GT_1 ); - - _list->_iterlevel--; - DL_Node* ret = _list->insbegin( newitem ); - _list->_iterlevel++; - return ret; -} - -/*! -//insert the object given before the current position of the iterator in list -\note The iterator level must be one to be able to use this function, else an error will be generated -\par Example: - to insert integer before the iterator position in the list| -\code -DL_List _intlist; #create a list of integers - -int a=123; - -DL_Iter* a_listiter=new DL_Iter(&_intlist); -a_listiter->totail(); -a_listiter->insbefore(a); // insert before tail -\endcode -\param newitem an object for which the template list/iterator was generated -*/ -template -DL_Node* DL_Iter::insbefore( Dtype newitem ) -{ - if ( _current == 0 ) - Error( "insbefore()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "insbefore()", ITER_GT_1 ); - - DL_Node* newnode = new DL_Node( newitem ); - - newnode ->_next = _current; - _current->_prev->_next = newnode; - newnode ->_prev = _current->_prev; - _current->_prev = newnode; - - NB++; - return newnode; -} - - -/*! -insert the object given after the current position of the iterator in list -\note The iterator level must be one to be able to use this function, else an error will be generated -\par Example: to insert integer after the iterator position in the list| -\code -DL_List _intlist; #create a list of integers - -int a=123; - -DL_Iter* a_listiter=new DL_Iter(&_intlist); -a_listiter->tohead(); -a_listiter->insafter(a); // insert after head -\endcode -\param newitem an object for which the template list/iterator was generated -*/ -template -DL_Node* DL_Iter::insafter( Dtype newitem ) -{ - if ( _current == 0 ) - Error( "insafter()", NO_LIST ); - if ( _list->_iterlevel > 1 ) - Error( "insafter()", ITER_GT_1 ); - - DL_Node* newnode = new DL_Node( newitem ); - - newnode ->_next = _current->_next; - newnode ->_prev = _current; - _current->_next->_prev = newnode; - _current->_next = newnode; - - NB++; - return newnode; -} - -/*! -sort all items in the list according to the compare function. -when items need to be swapped to reach the right order the swap function will be called also. -\note There are no restrictions on the internal decision in the compare function when to return -1,0,1. - -\note The swap function can be used to change items when they are swapped. - fcmp (function, fcmp) -\verbatim - - Declaration: int (*fcmp) (Dtype,Dtype) - - compare function pointer, the function takes two objects in the list. It must return -1, 0, 1, to sort the list in upgoing - order the function should return: - - -1 is returned if the first object is bigger then the second. - 0 is returned if the objects are equal. - 1 is returned if the first object is smaller then the second. - - To sort the list in downgoing order: - - 1 is returned if the first object is bigger then the second. - 0 is returned if the objects are equal. - -1 is returned if the first object is smaller then the second. - - fswap (function, fswap) - - Declaration: void (*fswap) (Dtype,Dtype) - - swap function pointer, the function takes two objects in the list. It will be called when the objects are swapped to - reach the right order. If it is NULL, it will not be called. -\endverbatim -\par Example: sort the list in upgoing order using cocktailsort and the function numbersorter| -\code -int numbersorter(int a,int b) -{ - if(a < b) return(1); - else - if(a == b) return(0); - return(-1); -} - -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(2345); -a_listiter->insend(3456); -a_listiter->insend(1234); -a_listiter->cocktailsort(numbersorter,NULL); -\endcode -\param fcmp sortfunction -\param fswap swapfunction -*/ -template -int DL_Iter::cocktailsort( int ( *fcmp ) ( Dtype, Dtype ), bool ( *fswap )( Dtype, Dtype ) ) -{ - if ( _current == 0 ) - Error( "cocktailsort()", NO_LIST ); - if ( NB <= 1 ) - return 0; - - DL_Node* cursor; - Dtype swap; - - int swapResult = 0; - - // boven/ondergrens setten - DL_Node *bg = TL, *bgold = TL; - DL_Node *og = HD, *ogold = HD; - - bool swapped = true; - - // while swaping is done & lowerborder upperborder don't touch - while ( swapped && ( og != bg ) ) - { - swapped = false; - - // BUBBELSLAG lowerborder--->> upperborder - cursor = og; - while( !( cursor == bgold ) ) - { - // (current.next < current)? - if( fcmp( cursor->_next->_item, cursor->_item ) == 1 ) - { - // user function - if ( fswap != NULL ) - if ( fswap( cursor->_item, cursor->_next->_item ) ) - swapResult++; - // update swap-flag en upperborder - swapped = true; - bg = cursor; - // swap the items of the nodes - swap = cursor->_item; - cursor->_item = cursor->_next->_item; - cursor->_next->_item = swap; - } - cursor = cursor->_next; - }// end bubbelslag - bgold = bg; - - // BRICKSLAG lowerborder <<---upperborder - cursor = bg; - while( !( cursor == ogold ) ) - { - // (current < current.next)? - if( fcmp( cursor->_item, cursor->_prev->_item ) == 1 ) - { - // user function - if ( fswap != NULL ) - if ( fswap( cursor->_item, cursor->_prev->_item ) ) - swapResult++; - // update swap-flag and lowerborder - swapped = true; - og = cursor; - // swap de items van de nodes - swap = cursor->_item; - cursor->_item = cursor->_prev->_item; - cursor->_prev->_item = swap; - } - cursor = cursor->_prev; - }// end brickslag - ogold = og; - }// end while(ongesorteerd) - - return swapResult; -} - -/*! - sort all items in the list according to the compare function. - -\note - There are no restrictions on the internal decision in the compare function when to return -1,0,1. - -\note - For the mergesort function the objects will be swapped when the return value is -1. - -\note -\verbatim - - fcmp (function, fcmp) - - Declaration: int (*fcmp) (Dtype,Dtype) - - compare function pointer, the function takes two objects in the list. It must return -1, 0, 1, to sort the list in upgoing - order the function should return: - - -1 is returned if the first object is bigger then the second. - 0 is returned if the objects are equal. - 1 is returned if the first object is smaller then the second. - - To sort the list in downgoing order: - - 1 is returned if the first object is bigger then the second. - 0 is returned if the objects are equal. - -1 is returned if the first object is smaller then the second. -\endverbatim - -!tcarg: class | Dtype | list item object -\par example - sort the list in upgoing order using mergesort and the function numbersorter| -\code -int numbersorter(int a,int b) -{ - if(a < b) return(1); - else - if(a == b) return(0); - return(-1); -} - -DL_List _intlist; #create a list of integers -DL_Iter* a_listiter=new DL_Iter(&_intlist); - -a_listiter->insend(2345); -a_listiter->insend(3456); -a_listiter->insend(1234); -a_listiter->mergesort(numbersorter); -\endcode -*/ -template -void DL_Iter::mergesort( int ( *fcmp ) ( Dtype, Dtype ) ) -{ - if ( _current == 0 ) - Error( "mergesort()", NO_LIST ); - mergesort_rec( fcmp, RT, NB ); -} - - -template -void DL_Iter::mergesort_rec( int ( *fcmp )( Dtype, Dtype ), DL_Node *RT1, int n1 ) -{ - if ( n1 > 1 ) //one element left then stop - { - DL_Node RT2; - int n2; - - RT2._prev = RT1->_prev; - RT2._next = RT1->_next; - // goto middle - n2 = n1;n1 >>= 1;n2 -= n1; - for ( int i = 0; i < n1;i++ ) - RT2._next = RT2._next->_next; - - //RT2 is at half - RT1->_prev->_next = &RT2; - RT2._prev = RT1->_prev; - RT1->_prev = RT2._next->_prev; - RT2._next->_prev->_next = RT1; - - mergesort_rec( fcmp, RT1, n1 ); - mergesort_rec( fcmp, &RT2, n2 ); - mergetwo( fcmp, RT1, &RT2 ); - } -} - -template -void DL_Iter::mergetwo( int ( *fcmp )( Dtype, Dtype ), DL_Node *RT1, DL_Node *RT2 ) -{ - DL_Node *c, *a, *b; - a = RT1->_next;b = RT2->_next; - c = RT1; - do - { - if ( fcmp( a->_item , b->_item ) > -1 ) - { c->_next = a;a->_prev = c;c = a;a = a->_next;} - else - { c->_next = b;b->_prev = c;c = b;b = b->_next;} - if ( a == RT1 ) - { - c->_next = - b;b->_prev = c; //connect list b to the list made sofar - RT1->_prev = RT2->_prev; - RT1->_prev->_next = RT1; - break; - } - if ( b == RT2 ) - { - c->_next = a;a->_prev = c; //connect list a to the list made sofar - break; - } - } - while ( true ); -} - - -//======================================================================= -// implementation class DL_StackIter -//======================================================================= -/*! \class DL_StackIter -* template class DL_StackIter class for stack iterator on DL_List -* template stack iterator for any list/node type \n -* This class is the base class to attach/instantiate a stack iterator on a double linked list -* DL_List. The stack iterator is used to push and pop objects -* to and from the beginning of a list. -* class | Dtype | Object for traversing a DL_List of the same Dtype -*\par Example - How to work with a stack iterator for a list of type integer \n - to push a and b, pop a into list and remove_all directly using a stack iterator -* -*\code DL_List* a_list = new DL_List();# declaration and allocation -* -* int a=123; -* -* int b=345; -* -* { -* -* DL_StackIter* a_listiter=new DL_StackIter(a_list); -* -* a_listiter->push(a) -* -* a_listiter->push(b) -* -* a_listiter->pop() -* -* a_listiter->remove_all() -* -* } //to destruct the iterator before the list is deleted -* -* delete a_list; #delete it (must have no iterators attached to it) -*\endcode -*/ - -// constructor -template -DL_StackIter::DL_StackIter( DL_List *newlist ) - : DL_Iter( newlist ) // initialiseer BaseIter -{} - - -// destructor -template -DL_StackIter::~DL_StackIter() -{} - -// plaats nieuw item op stack -template -void DL_StackIter::push( Dtype newitem ) -{ - DL_Iter::insbegin( newitem ); -} -// remove current item -template -void DL_StackIter::remove_all() -{ - DL_Iter::remove_all(); -} - -// is stack leeg? -template -bool DL_StackIter::empty() -{ - return DL_Iter::empty(); -} - -// aantal items op stack -template -int DL_StackIter::count() -{ - return DL_Iter::count(); -} - -// haal bovenste item van stack -template -Dtype DL_StackIter::pop() -{ - if( DL_Iter::empty() ) - this->Error( "pop()", EMPTY ); - - DL_Iter::tohead(); - Dtype temp = DL_Iter::item(); - DL_Iter::removehead(); - return temp; -} - -//======================================================================= -// implementation class DL_SortIter -//======================================================================= -/*! \class DL_SortIter -* template class DL_SortIter -* class for sort iterator on DL_List -* template sort iterator for any list/node type -* This class is a derived class to attach/instantiate a sorted iterator on a double linked list -* DL_List. The iterator is used to insert items in sorted order into a list. -//!tcarg: class | Dtype | Object for traversing a DL_List of the same Dtype -*/ - -// constructor -template -DL_SortIter::DL_SortIter( DL_List* nw_list, int ( *new_func )( DType , DType ) ) - : DL_Iter( nw_list ), comparef( new_func ) -{} - -// destructor -template -DL_SortIter::~DL_SortIter() -{} - -// general function to insert item -template -void DL_SortIter::insert( DType new_item ) -{ - DL_Node* cursor = this->_current; //can be 0 if empty //node is a temporary cursor - - // if list is empty directly insert - if ( DL_Iter::empty() ) - { - DL_Iter::insend( new_item ); - } - else - { - // put new item left of item - DL_Iter::tohead(); - while( !DL_Iter::hitroot() ) - { - if ( !( *comparef )( DL_Iter::item(), new_item ) ) - break; - DL_Iter::next(); - } - - //if at root - DL_Iter::insbefore( new_item ); - } - - this->_current = cursor; //set to old cursor position -} - -template -void DL_SortIter::sortitererror() -{ - this->Error( "sortiter()", NOT_ALLOW ); -} - - diff --git a/polygon/kbool/include/kbool/_dl_itr.h b/polygon/kbool/include/kbool/_dl_itr.h deleted file mode 100644 index 54cad412ee..0000000000 --- a/polygon/kbool/include/kbool/_dl_itr.h +++ /dev/null @@ -1,407 +0,0 @@ -/*! \file _dl_itr.h - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: _dl_itr.h,v 1.6 2009/09/10 17:04:09 titato Exp $ -*/ - -//! author="Klaas Holwerda" -/* - * Definitions of classes, for list implementation - * template list and iterator for any list node type -*/ - -#ifndef _DL_Iter_H -#define _DL_Iter_H - -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#define _CRT_SECURE_NO_DEPRECATE 1 - -#include "kbool/booleng.h" -#include -#include - -using namespace std; - -#ifndef _STATUS_ENUM -#define _STATUS_ENUM -//!_root -#define HD _list->_root->_next -#define TL _list->_root->_prev -#define NB _list->_nbitems - -template class DL_List; -template class DL_Iter; -template class DL_SortIter; - -//! Template class DL_Node -template class DL_Node -{ - friend class DL_List; - friend class DL_Iter; - friend class DL_SortIter; - - //!Public members -public: - //!Template constructor no contents - //!Construct a node for a list object - DL_Node(); - - //!constructor with init of Dtype - DL_Node( Dtype n ); - - //!Destructor - ~DL_Node(); - - //!Public members -public: - //!data in node - Dtype _item; - - //!pointer to next node - DL_Node* _next; - - //!pointer to previous node - DL_Node* _prev; -}; - -//!Template class DL_List -template class DL_List -{ - friend class DL_Iter; - friend class DL_SortIter; - -public: - //!Constructor - //!Construct a list object - //!!tcarg class | Dtype | list object - DL_List(); - - //!destructor - ~DL_List(); - - //!Report off List Errors - void Error( string function, Lerror a_error ); - - //!Number of items in the list - int count(); - - //!Empty List? - bool empty(); - - //!insert the object given at the end of the list, after tail - DL_Node* insend( Dtype n ); - - //!insert the object given at the begin of the list, before head - DL_Node* insbegin( Dtype n ); - - //!remove the object at the begin of the list (head) - void removehead(); - - //! remove the object at the end of the list (tail) - void removetail(); - - //!remove all objects from the list - void remove_all( bool deleteObject = false ); - - //!Get the item at the head of the list - Dtype headitem(); - - //!Get the item at the tail of the list - Dtype tailitem(); - - //! to move all objects in a list to this list. - void takeover( DL_List* otherlist ); - -public: - //!the root node pointer of the list, the first and last node - //! in the list are connected to the root node. The root node is used - //! to detect the end / beginning of the list while traversing it. - DL_Node* _root; - - //!the number of items in the list, if empty list it is 0 - int _nbitems; - - //!number of iterators on the list, Attaching or instantiating an iterator to list, - //! will increment this member, detaching and - //! destruction of iterator for a list will decrement this number - short int _iterlevel; -}; - -//! Template class DL_Iter for iterator on DL_List -template -class DL_Iter -{ -public: - //!Construct an iterator object for a given list of type Dtype - DL_Iter( DL_List* newlist ); - - //!Constructor of iterator for the same list as another iterator - DL_Iter( DL_Iter* otheriter ); - - //!Constructor without an attached list - DL_Iter(); - - //!destructor - ~DL_Iter(); - - //!Report off Iterator Errors - void Error( string function, Lerror a_error ); - - //!This attaches an iterator to a list of a given type. - void Attach( DL_List* newlist ); - - //!This detaches an iterator from a list - void Detach(); - - //!execute given function for each item in the list/iterator - void foreach_f( void ( *fp ) ( Dtype n ) ); - - //! list mutations - - //!insert after tail item - DL_Node* insend( Dtype n ); - - //!insert before head item - DL_Node* insbegin( Dtype n ); - - //!insert before current iterator position - DL_Node* insbefore( Dtype n ); - - //!insert after current iterator position - DL_Node* insafter( Dtype n ); - - //!to move all objects in a list to the list of the iterator. - void takeover( DL_List* otherlist ); - - //!to move all objects in a list (using iterator of that list) to the list of the iterator - void takeover( DL_Iter* otheriter ); - - //! to move maxcount objects in a list (using iterator of that list) to the list of the iterator - void takeover( DL_Iter* otheriter, int maxcount ); - - //!remove object at current iterator position from the list. - void remove(); - - //!Remove head item - void removehead(); - - //!Remove tail item - void removetail(); - - //!Remove all items - void remove_all(); - - - /* void foreach_mf(void (Dtype::*mfp)() ); //call Dtype::mfp for each item */ - - //!is list empty (contains items or not)? - bool empty(); - - //!is iterator at root node (begin or end)? - bool hitroot(); - - //!is iterator at head/first node? - bool athead(); - - //!is iterator at tail/last node? - bool attail(); - - //!is given item member of the list - bool has( Dtype otheritem ); - - //!Number of items in the list - int count(); - - /* cursor movements */ - - //!go to last item, if list is empty goto hite - void totail(); - - //!go to first item, if list is empty goto hite - void tohead(); - - //!set the iterator position to the root (empty dummy) object in the list. - void toroot(); - - //! set the iterator position to next object in the list ( can be the root also). - void operator++ ( void ); - - //!set iterator to next item (pre fix) - void operator++ ( int ); - - //!set the iterator position to previous object in the list ( can be the root also)(postfix). - void operator-- ( void ); - - //!set the iterator position to previous object in the list ( can be the root also)(pre fix). - void operator-- ( int ); - - //!set the iterator position n objects in the next direction ( can be the root also). - void operator>> ( int ); - - //!set the iterator position n objects in the previous direction ( can be the root also). - void operator<< ( int ); - - //!set the iterator position to next object in the list, if this would be the root object, - //!then set the iterator at the head object - void next_wrap(); - - //!set the iterator position to previous object in the list, if this would be the root object, - //!then set the iterator at the tail object - void prev_wrap(); - - //!move root in order to make the current node the tail - void reset_tail(); - - //!move root in order to make the current node the head - void reset_head(); - - //!put the iterator at the position of the given object in the list. - bool toitem( Dtype ); - - //!put the iterator at the same position as the given iterator in the list. - void toiter( DL_Iter* otheriter ); - - //!put the iterator at the position of the given node in the list. - bool tonode( DL_Node* ); - - //!iterate through all items of the list - bool iterate( void ); - - //!To get the item at the current iterator position - Dtype item(); - - //! get node at iterator - DL_Node* node(); - - //!sort list with mergesort - void mergesort( int ( *fcmp ) ( Dtype, Dtype ) ); - - //!sort list with cocktailsort - /*! - \return number of swaps done. - */ - int cocktailsort( int ( * )( Dtype, Dtype ), bool ( * )( Dtype, Dtype ) = NULL ); - -protected: - - //!sort list with mergesort - void mergesort_rec( int ( *fcmp )( Dtype, Dtype ), DL_Node *RT1, int n ); - - //!sort list with mergesort - void mergetwo( int ( *fcmp )( Dtype, Dtype ), DL_Node *RT1, DL_Node *RT2 ); - - //!set the iterator position to next object in the list ( can be the root also). - void next(); - - //!set the iterator position to previous object in the list ( can be the root also). - void prev(); - - //!the list for this iterator - DL_List *_list; - - //!the current position of the iterator - DL_Node *_current; -}; - - -//! template class DL_StackIter class for stack iterator on DL_List -template -class DL_StackIter : protected DL_Iter -{ -public: - //!Constructor of stack iterator for given list - DL_StackIter( DL_List * ); - //!Constructor of stack iterator no list attached - DL_StackIter(); - - //!Destructor of stack iterator - ~DL_StackIter(); - - //!Remove all items from the stack - void remove_all(); - //!push given item on the stack - void push( Dtype n ); - //!get last inserted item from stack - Dtype pop(); - //!is stack empty? - bool empty(); - //!number of items on the stack - int count(); -}; - -//!template class DL_SortIter -template class DL_SortIter : public DL_Iter -{ -public: - //!Constructor of sort iterator for given list and sort function - DL_SortIter( DL_List* nw_list, int ( *new_func )( DType , DType ) ); - - //!Constructor of sort iterator with sort function and no list attached - DL_SortIter( int ( *newfunc )( DType, DType ) ); - - //!Destructor of sort iterator - ~DL_SortIter(); - - //!insert item in sorted order - void insert ( DType new_item ); - - /*override following functions to give an error */ - //!Not allowed - void insend ( bool n ){sortitererror();}; - //!Not allowed - void insbegin ( bool n ){sortitererror();}; - //!Not allowed - void insbefore ( bool n ){sortitererror();}; - //!Not allowed - void insafter ( bool n ){sortitererror();}; - //!Not allowed - void takeover ( DL_List* ){sortitererror();}; - //!Not allowed - void takeover ( DL_Iter* ){sortitererror();}; - //!Not allowed - void takeover ( DL_Iter* otheriter, int maxcount ){sortitererror();}; - //!Not allowed - void next_wrap() {sortitererror();}; - //!Not allowed - void prev_wrap() {sortitererror();}; - //!Not allowed - void reset_tail() {sortitererror();}; - //!Not allowed - void reset_head() {sortitererror();}; - -private: - //!Report off Iterator Errors - void sortitererror(); - - //!comparefunction used to insert items in sorted order - int ( *comparef )( DType, DType ); -}; - -#include "kbool/_dl_itr.cpp" - -#endif diff --git a/polygon/kbool/include/kbool/_lnk_itr.cpp b/polygon/kbool/include/kbool/_lnk_itr.cpp deleted file mode 100644 index a19cdf3577..0000000000 --- a/polygon/kbool/include/kbool/_lnk_itr.cpp +++ /dev/null @@ -1,257 +0,0 @@ -/*! \file _lnk_itr.cpp - \author Probably Klaas Holwerda - - Copyright: 2001-2004 (C) Probably Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: _lnk_itr.cpp,v 1.4 2009/02/06 21:33:03 titato Exp $ -*/ - -#ifdef __UNIX__ -#include "kbool/_lnk_itr.h" -#endif - -//======================================================================= -// implementation class LinkBaseIter -//======================================================================= - -template -TDLI::TDLI( DL_List* newlist ): DL_Iter( newlist ) -{} - -template -TDLI::TDLI( DL_Iter* otheriter ): DL_Iter( otheriter ) -{} - -template -TDLI::TDLI(): DL_Iter() -{} - -// destructor TDLI -template -TDLI::~TDLI() -{} - -template -void TDLI::delete_all() -{ - DL_Node* node; - Type* obj; - for ( int i = 0; i < NB; i++ ) - { - node = HD; - HD = node->_next; - obj = ( Type* )( node->_item ); - delete obj; - delete node; - } - NB = 0; //reset memory used (no lost pointers) - TL = RT; - _current = RT; -} - -template -void TDLI::foreach_f( void ( *fp ) ( Type* item ) ) -{ - DL_Iter::foreach_f( ( void ( * )( void* ) )fp ); //call fp for each item -} - -template -void TDLI::foreach_mf( void ( Type::*mfp ) () ) -{ - - DL_Node* node = HD; //can be 0 if empty - Type* obj; - for( int i = 0; i < NB; i++ ) - { - obj = ( Type* )( node->_item ); - ( obj->*mfp )(); - node = node->_next; - } -} - -template -void TDLI::takeover( DL_List* otherlist ) -{ - DL_Iter::takeover( ( DL_List* ) otherlist ); -} - -template -void TDLI::takeover( TDLI* otheriter ) -{ - DL_Iter::takeover( ( DL_Iter* ) otheriter ); -} - -template -void TDLI::takeover( TDLI* otheriter, int maxcount ) -{ - DL_Iter::takeover( ( DL_Iter* ) otheriter, maxcount ); -} - -// is item element of the list? -template -bool TDLI::has( Type* otheritem ) -{ - return DL_Iter::has( ( void* ) otheritem ); -} - -// goto to item -template -bool TDLI::toitem( Type* item ) -{ - return DL_Iter::toitem( ( void* ) item ); -} - -// get current item -template -Type* TDLI::item() -{ - return ( Type* ) DL_Iter::item(); -} - -template -void TDLI::insend( Type* newitem ) -{ - DL_Iter::insend( ( void* ) newitem ); -} - -template -void TDLI::insbegin( Type* newitem ) -{ - DL_Iter::insbegin( ( void* ) newitem ); -} - -template -void TDLI::insbefore( Type* newitem ) -{ - DL_Iter::insbefore( ( void* ) newitem ); -} - -template -void TDLI::insafter( Type* newitem ) -{ - DL_Iter::insafter( ( void* ) newitem ); -} - -template -void TDLI::insend_unsave( Type* newitem ) -{ - short int iterbackup = _list->_iterlevel; - _list->_iterlevel = 0; - DL_Iter::insend( ( void* ) newitem ); - _list->_iterlevel = iterbackup; -} - -template -void TDLI::insbegin_unsave( Type* newitem ) -{ - short int iterbackup = _list->_iterlevel; - _list->_iterlevel = 0; - DL_Iter::insbegin( ( void* ) newitem ); - _list->_iterlevel = iterbackup; -} - -template -void TDLI::insbefore_unsave( Type* newitem ) -{ - short int iterbackup = _list->_iterlevel; - _list->_iterlevel = 0; - DL_Iter::insbefore( ( void* ) newitem ); - _list->_iterlevel = iterbackup; -} - -template -void TDLI::insafter_unsave( Type* newitem ) -{ - short int iterbackup = _list->_iterlevel; - _list->_iterlevel = 0; - DL_Iter::insafter( ( void* ) newitem ); - _list->_iterlevel = iterbackup; -} - -template -void TDLI::mergesort( int ( *f )( Type* a, Type* b ) ) -{ - DL_Iter::mergesort( ( int ( * )( void*, void* ) ) f ); -} - -template -int TDLI::cocktailsort( int ( *f )( Type* a, Type* b ), bool ( *f2 )( Type* c, Type* d ) ) -{ - return DL_Iter::cocktailsort( ( int ( * )( void*, void* ) ) f, ( bool( * )( void*, void* ) ) f2 ); -} - -template -TDLISort::TDLISort( DL_List* lista, int ( *newfunc )( void*, void* ) ) - : DL_SortIter( lista, newfunc ) -{} - -template -TDLISort::~TDLISort() -{} - -template -void TDLISort::delete_all() -{ - DL_Node* node; - Type* obj; - for ( int i = 0; i < NB; i++ ) - { - node = HD; - HD = node->_next; - obj = ( Type* )( node->_item ); - delete obj; - delete node; - } - NB = 0; //reset memory used (no lost pointers) - TL = RT; - _current = RT; -} - -// is item element of the list? -template -bool TDLISort::has( Type* otheritem ) -{ - return DL_Iter::has( ( void* ) otheritem ); -} - -// goto to item -template -bool TDLISort::toitem( Type* item ) -{ - return DL_Iter::toitem( ( void* ) item ); -} - -// get current item -template -Type* TDLISort::item() -{ - return ( Type* ) DL_Iter::item(); -} - -template -TDLIStack::TDLIStack( DL_List* newlist ): DL_StackIter( newlist ) -{} - -// destructor TDLI -template -TDLIStack::~TDLIStack() -{} - -// plaats nieuw item op stack -template -void TDLIStack::push( Type* newitem ) -{ - DL_StackIter::push( ( Type* ) newitem ); -} - - -// haal bovenste item van stack -template -Type* TDLIStack::pop() -{ - return ( Type* ) DL_StackIter::pop(); -} - - diff --git a/polygon/kbool/include/kbool/_lnk_itr.h b/polygon/kbool/include/kbool/_lnk_itr.h deleted file mode 100644 index 1b9a297c25..0000000000 --- a/polygon/kbool/include/kbool/_lnk_itr.h +++ /dev/null @@ -1,159 +0,0 @@ -/*! \file _lnk_itr.h - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: _lnk_itr.h,v 1.4 2009/09/10 17:04:09 titato Exp $ -*/ - -//! author="Klaas Holwerda" -//! version="1.0" -/* - * Definitions of classes, for list implementation - * template list and iterator for any list node type -*/ -#ifndef _LinkBaseIter_H -#define _LinkBaseIter_H - -//! headerfiles="_dl_itr.h stdlib.h misc.h gdsmes.h" -#include -#include "kbool/booleng.h" - -#define SWAP(x,y,t)((t)=(x),(x)=(y),(y)=(t)) - -#include "kbool/_dl_itr.h" - -//! codefiles="_dl_itr.cpp" - -//! Template class TDLI -/*! - class for iterator on DL_List that is type casted version of DL_Iter - \sa DL_Iter for further documentation -*/ -template class TDLI : public DL_Iter -{ -public: - //!constructor - /*! - \param list to iterate on. - */ - TDLI( DL_List* list ); - - //!constructor - TDLI( DL_Iter* otheriter ); - - //! nolist constructor - TDLI(); - - //! destructor - ~TDLI(); - - //!call fp for each item - void foreach_f( void ( *fp ) ( Type* item ) ); - - //!call fp for each item - void foreach_mf( void ( Type::*fp ) () ); - - /* list mutations */ - - - //! delete all items - void delete_all (); - - - //! insert at end - void insend ( Type* n ); - - //! insert at begin - void insbegin ( Type* n ); - - //! insert before current - void insbefore ( Type* n ); - - //! insert after current - void insafter ( Type* n ); - - //! insert at end unsave (works even if more then one iterator is on the list - //! the user must be sure not to delete/remove items where other iterators - //! are pointing to. - void insend_unsave ( Type* n ); - - //! insert at begin unsave (works even if more then one iterator is on the list - //! the user must be sure not to delete/remove items where other iterators - //! are pointing to. - void insbegin_unsave ( Type* n ); - - //! insert before iterator position unsave (works even if more then one iterator is on the list - //! the user must be sure not to delete/remove items where other iterators - //! are pointing to. - void insbefore_unsave ( Type* n ); - - //! insert after iterator position unsave (works even if more then one iterator is on the list - //! the user must be sure not to delete/remove items where other iterators - //! are pointing to. - void insafter_unsave ( Type* n ); - - //! \sa DL_Iter::takeover(DL_List< Dtype >* otherlist ) - void takeover ( DL_List* otherlist ); - //! \sa DL_Iter::takeover(DL_Iter* otheriter) - void takeover ( TDLI* otheriter ); - //! \sa DL_Iter::takeover(DL_Iter* otheriter, int maxcount) - void takeover ( TDLI* otheriter, int maxcount ); - - //! \sa DL_Iter::has - bool has ( Type* ); - //! \sa DL_Iter::toitem - bool toitem ( Type* ); - - //!get the item then iterator is pointing at - Type* item (); - - //! \sa DL_Iter::mergesort - void mergesort ( int ( *f )( Type* a, Type* b ) ); - //! \sa DL_Iter::cocktailsort - int cocktailsort( int ( * ) ( Type* a, Type* b ), bool ( * ) ( Type* c, Type* d ) = NULL ); - -}; - -//! Template class TDLIsort -/*! -// class for sort iterator on DL_List that is type casted version of DL_SortIter -// see also inhereted class DL_SortIter for further documentation -*/ -template class TDLISort : public DL_SortIter -{ -public: - - //!constructor givin a list and a sort function - TDLISort( DL_List* list, int ( *newfunc )( void*, void* ) ); - ~TDLISort(); - - //!delete all items from the list - void delete_all(); - bool has ( Type* ); - bool toitem ( Type* ); - Type* item (); -}; - -//! Template class TDLIStack -/*! - class for iterator on DL_List that is type casted version of DL_StackIter - see also inhereted class DL_StackIter for further documentation -*/ -template class TDLIStack : public DL_StackIter -{ -public: - //constructor givin a list - TDLIStack( DL_List* list ); - - ~TDLIStack(); - - void push( Type* ); - Type* pop(); -}; - -#include"kbool/_lnk_itr.cpp" - -#endif diff --git a/polygon/kbool/include/kbool/booleng.h b/polygon/kbool/include/kbool/booleng.h deleted file mode 100644 index 5d0930d63a..0000000000 --- a/polygon/kbool/include/kbool/booleng.h +++ /dev/null @@ -1,596 +0,0 @@ -/*! \file booleng.h - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: booleng.h,v 1.9 2009/09/14 18:18:03 titato Exp $ -*/ - -#ifndef BOOLENG_H -#define BOOLENG_H - -#undef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES -#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1 -#define _CRT_SECURE_NO_DEPRECATE 1 - -#include -#include -#include -#include -#include - -using namespace std; - - -#if 0 // Kicad does not use kbool in dll version - -#if defined(__WXMSW__) - /* - __declspec works in BC++ 5 and later, Watcom C++ 11.0 and later as well - as VC++ and gcc - */ -# if defined(__VISUALC__) || defined(__BORLANDC__) || defined(__GNUC__) || defined(__WATCOMC__) -# define WXEXPORT __declspec(dllexport) -# define WXIMPORT __declspec(dllimport) -# else /* compiler doesn't support __declspec() */ -# define WXEXPORT -# define WXIMPORT -# endif -#elif defined(__WXPM__) -# if defined (__WATCOMC__) -# define WXEXPORT __declspec(dllexport) - /* - __declspec(dllimport) prepends __imp to imported symbols. We do NOT - want that! - */ -# define WXIMPORT -# elif defined(__EMX__) -# define WXEXPORT -# define WXIMPORT -# elif (!(defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ))) -# define WXEXPORT _Export -# define WXIMPORT _Export -# endif -#elif defined(__WXMAC__) || defined(__WXCOCOA__) -# ifdef __MWERKS__ -# define WXEXPORT __declspec(export) -# define WXIMPORT __declspec(import) -# endif -#elif defined(__CYGWIN__) -# define WXEXPORT __declspec(dllexport) -# define WXIMPORT __declspec(dllimport) -#endif - -#endif // if 0 for kicad - -/* for other platforms/compilers we don't anything */ -#ifndef WXEXPORT -# define WXEXPORT -# define WXIMPORT -#endif - -#ifdef A2DKBOOLMAKINGDLL -#define A2DKBOOLDLLEXP WXEXPORT -#define A2DKBOOLDLLEXP_DATA(type) WXEXPORT type -#define A2DKBOOLDLLEXP_CTORFN -#elif defined(WXART2D_USINGDLL) -#define A2DKBOOLDLLEXP WXIMPORT -#define A2DKBOOLDLLEXP_DATA(type) WXIMPORT type -#define A2DKBOOLDLLEXP_CTORFN -#else // not making nor using DLL -#define A2DKBOOLDLLEXP -#define A2DKBOOLDLLEXP_DATA(type) type -#define A2DKBOOLDLLEXP_CTORFN -#endif - -#define KBOOL_VERSION "2.1" - -#define KBOOL_DEBUG 0 -#define KBOOL_LOG 0 -#define KBOOL_INT64 1 - -class kbLink; - -#define LINELENGTH 200 - -#ifdef MAXDOUBLE -#undef MAXDOUBLE -#endif -#define MAXDOUBLE 1.7976931348623158e+308 - -#ifdef KBOOL_INT64 - -#if defined(__UNIX__) || defined(__GNUG__) - -typedef long long B_INT; // 8 bytes integer -//#define MAXB_INT LONG_LONG_MAX -//#define MINB_INT LONG_LONG_MIN // 8 bytes integer -const B_INT MAXB_INT = ( 0x7fffffffffffffffLL ); // 8 bytes integer -const B_INT MINB_INT = ( 0x8000000000000000LL ); - -#else //defined(__UNIX__) || defined(__GNUG__) - -typedef __int64 B_INT; // 8 bytes integer -#undef MAXB_INT -#undef MINB_INT - -const B_INT MAXB_INT = ( 0x7fffffffffffffff ); // 8 bytes integer -const B_INT MINB_INT = ( 0x8000000000000000 ); - -#endif //defined(__UNIX__) || defined(__GNUG__) - -#else //KBOOL_INT64 - -#if defined(__UNIX__) || defined(__GNUG__) -typedef long B_INT; // 8 bytes integer -const B_INT MAXB_INT = ( 0x7fffffffL ); // 8 bytes integer -const B_INT MINB_INT = ( 0x80000000L ); -#else -typedef long B_INT; // 8 bytes integer -const B_INT MAXB_INT = ( 0x7fffffff ); // 8 bytes integer -const B_INT MINB_INT = ( 0x80000000 ); -#endif - -#endif //KBOOL_INT64 - -B_INT babs( B_INT ); - -#ifdef M_PI -#undef M_PI -#endif -#define M_PI (3.1415926535897932384626433832795028841972) - -#ifdef M_PI_2 -#undef M_PI_2 -#endif -#define M_PI_2 1.57079632679489661923 - -#ifdef M_PI_4 -#undef M_PI_4 -#endif -#define M_PI_4 0.785398163397448309616 - -#ifndef NULL -#define NULL 0 -#endif - -B_INT bmin( B_INT const value1, B_INT const value2 ); -B_INT bmax( B_INT const value1, B_INT const value2 ); - -B_INT bmin( B_INT value1, B_INT value2 ); -B_INT bmax( B_INT value1, B_INT value2 ); - -#include - -//! errors in the boolean algorithm will be thrown using this class -class A2DKBOOLDLLEXP Bool_Engine_Error -{ -public: - Bool_Engine_Error( string message, string header = 0, int degree = 9, int fatal = 0 ); - Bool_Engine_Error( const Bool_Engine_Error& a ); - ~Bool_Engine_Error(); - string GetErrorMessage(); - string GetHeaderMessage(); - int GetErrorDegree(); - int GetFatal(); - -protected: - string _message; - string _header; - int _degree; - int _fatal; -}; - - -#define KBOOL_LOGFILE "kbool.log" - -enum kbEdgeType -{ - KB_OUTSIDE_EDGE, /*!< edge of the outside contour of a polygon */ - KB_INSIDE_EDGE, /*!< edge of the inside hole a polygon */ - KB_FALSE_EDGE /*!< edge to connect holes into polygons */ -} ; - -enum GroupType -{ - GROUP_A, /*!< to set Group A for polygons */ - GROUP_B /*!< to set Group A for polygons */ -}; - -enum BOOL_OP -{ - BOOL_NON, /*!< No operation */ - BOOL_OR, /*!< boolean OR operation */ - BOOL_AND, /*!< boolean AND operation */ - BOOL_EXOR, /*!< boolean EX_OR operation */ - BOOL_A_SUB_B, /*!< boolean Group A - Group B operation */ - BOOL_B_SUB_A, /*!< boolean Group B - Group A operation */ - BOOL_CORRECTION, /*!< polygon correction/offset operation */ - BOOL_SMOOTHEN, /*!< smooth operation */ - BOOL_MAKERING /*!< create a ring on all polygons */ -}; - -class kbGraphList; -class kbGraph; -class kbLink; -class kbNode; -template class TDLI; - -//! boolean engine to perform operation on two sets of polygons. -/* - First the engine needs to be filled with polygons. - The first operand in the operation is called group A polygons, the second group B. - The boolean operation ( BOOL_OR, BOOL_AND, BOOL_EXOR, BOOL_A_SUB_B, BOOL_B_SUB_A ) - are based on the two sets of polygons in group A and B. - The other operation on group A only. - - At the end of the operation the resulting polygons can be extracted. -*/ -class A2DKBOOLDLLEXP Bool_Engine -{ - -public: - - //! constructor - Bool_Engine(); - - //! destructor - virtual ~Bool_Engine(); - - string GetVersion() { return KBOOL_VERSION; } - - //! reports progress of algorithm. - virtual void SetState( string ); - - //! called at an internal error. - virtual void error( string text, string title ); - - //! called at an internal generated possible error. - virtual void info( string text, string title ); - - bool Do_Operation( BOOL_OP operation ); - - - //! distance within which points and lines will be snapped towards lines and other points - /* - The algorithm takes into account gaps and inaccuracies caused by rounding to integer coordinates - in the original data. - Imagine two rectangles one with a side ( 0,0 ) ( 2.0, 17.0 ) - and the other has a side ( 0,0 ) ( 1.0, 8.5 ) - If for some reason those coordinates where round to ( 0,0 ) ( 2, 17 ) ( 0,0 ) ( 1, 9 ), - there will be clearly a gap or overlap that was not intended. - Even without rounding this effect takes place since there is always a minimum significant bit - also when using doubles. - - If the user used as minimum accuracy 0.001, you need to choose Marge > 0.001 - The boolean engine scales up the input data with GetDGrid() * GetGrid() and rounds the result to - integer, So (assuming GRID = 100 DGRID = 1000) a vertex of 123.001 in the user data will - become 12300100 internal. - At the end of the algorithm the internal vertexes are scaled down again with GetDGrid() * GetGrid(), - so 12300103 becomes 123.00103 eventually. - So indeed the minimum accuracy might increase, you are free to round again if needed. - */ - void SetMarge( double marge ); - double GetMarge(); - - //! input points are scaled up with GetDGrid() * GetGrid() - /* - Grid makes sure that the integer data used within the algorithm has room for extra intersections - smaller than the smallest number within the input data. - The input data scaled up with DGrid is related to the accuracy the user has in his input data. - Another scaling with Grid is applied on top of it to create space in the integer number for - even smaller numbers. - */ - void SetGrid( B_INT grid ); - - //! See SetGrid - B_INT GetGrid(); - - //! input points are scaled up with GetDGrid() * GetGrid() - /* - The input data scaled up with DGrid is related to the accuracy the user has in his input data. - User data with a minimum accuracy of 0.001, means set the DGrid to 1000. - The input data may contain data with a minimum accuracy much smaller, but by setting the DGrid - everything smaller than 1/DGrid is rounded. - - DGRID is only meant to make fractional parts of input data which can be - doubles, part of the integers used in vertexes within the boolean algorithm. - And therefore DGRID bigger than 1 is not usefull, you would only loose accuracy. - Within the algorithm all input data is multiplied with DGRID, and the result - is rounded to an integer. - */ - void SetDGrid( double dgrid ); - - //! See SetDGrid - double GetDGrid(); - - //! When doing a correction operation ( also known as process offset ) - //! this defines the detail in the rounded corners. - /* - Depending on the round factor the corners of the polygon may be rounding within the correction - algorithm. The detail within this rounded corner is set here. - It defines the deviation the generated segments in arc like polygon may have towards the ideal - rounded corner using a perfect arc. - */ - void SetCorrectionAber( double aber ); - - //! see SetCorrectionAber - double GetCorrectionAber(); - - //! When doing a correction operation ( also known as process offset ) - //! this defines the amount of correction. - /* - The correction algorithm can apply positive and negative offset to polygons. - It takes into account closed in areas within a polygon, caused by overlapping/selfintersecting - polygons. So holes form that way are corrected proberly, but the overlapping parts itself - are left alone. An often used trick to present polygons with holes by linking to the outside - boundary, is therefore also handled properly. - The algoritm first does a boolean OR operation on the polygon, and seperates holes and - outside contours. - After this it creates a ring shapes on the above holes and outside contours. - This ring shape is added or subtracted from the holes and outside contours. - The result is the corrected polygon. - If the correction factor is > 0, the outside contours will become larger, while the hole contours - will become smaller. - */ - void SetCorrectionFactor( double aber ); - - //! see SetCorrectionFactor - double GetCorrectionFactor(); - - //! used within the smooth algorithm to define how much the smoothed curve may deviate - //! from the original. - void SetSmoothAber( double aber ); - - //! see SetSmoothAber - double GetSmoothAber(); - - //! segments of this size will be left alone in the smooth algorithm. - void SetMaxlinemerge( double maxline ); - - //! see SetMaxlinemerge - double GetMaxlinemerge(); - - //! Polygon may be filled in different ways (alternate and winding rule). - //! This here defines which method will be assumed within the algorithm. - void SetWindingRule( bool rule ); - - //! see SetWindingRule - bool GetWindingRule(); - - //! when set not only the top vertex of a hole is linked to the other holes and contours, - //! but also vertex other vertexes close to a hole can be used. - void SetAllowNonTopHoleLinking( bool allow ) { m_allowNonTopHoleLinking = allow; } - - //! see SetWindingRule - bool GetAllowNonTopHoleLinking() { return m_allowNonTopHoleLinking; } - - //! the smallest accuracy used within the algorithm for comparing two real numbers. - double GetAccur(); - - //! Used with in correction/offset algorithm. - /* - When the polygon contains sharp angles ( < 90 ), after a positive correction the - extended parrallel constructed offset lines may leed to extreme offsets on the angles. - The length of the crossing generated by the parrallel constructed offset lines - towards the original point in the polygon is compared to the offset which needs to be applied. - The Roundfactor then decides if this corner will be rounded. - A Roundfactor of 1 means that the resulting offset will not be bigger then the correction factor - set in the algorithm. Meaning even straight 90 degrees corners will be rounded. - A Roundfactor of > sqrt(2) is where 90 corners will be left alone, and smaller corners will be rounded. - */ - void SetRoundfactor( double roundfac ); - - //! see SetRoundfactor - double GetRoundfactor(); - -// the following are only be used within the algorithm, -// since they are scaled with m_DGRID - - //! only used internal. - void SetInternalMarge( B_INT marge ); - //! only used internal. - B_INT GetInternalMarge(); - - //! only used internal. - double GetInternalCorrectionAber(); - - //! only used internal. - double GetInternalCorrectionFactor(); - - //! only used internal. - double GetInternalSmoothAber(); - - //! only used internal. - B_INT GetInternalMaxlinemerge(); - - //! in this mode polygons add clockwise, or contours, - /*! - and polygons added counter clockwise or holes. - */ - void SetOrientationEntryMode( bool orientationEntryMode ) { m_orientationEntryMode = orientationEntryMode; } - - //! see SetOrientationEntryMode() - bool GetOrientationEntryMode() { return m_orientationEntryMode; } - - //! if set true holes are linked into outer contours by double overlapping segments. - /*! - This mode is needed when the software using the boolean algorithm does - not understand hole polygons. In that case a contour and its holes form one - polygon. In cases where software understands the concept of holes, contours - are clockwise oriented, while holes are anticlockwise oriented. - The output of the boolean operations, is following those rules also. - But even if extracting the polygons from the engine, each segment is marked such - that holes and non holes and linksegments to holes can be recognized. - */ - void SetLinkHoles( bool doLinkHoles ) { m_doLinkHoles = doLinkHoles; } - - //! see SetLinkHoles() - bool GetLinkHoles() { return m_doLinkHoles; } - - //!lof file will be created when set True - void SetLog( bool OnOff ); - - //! used to write to log file - void Write_Log( string); - //! used to write to log file - void Write_Log( string, string ); - //! used to write to log file - void Write_Log( string, double ); - //! used to write to log file - void Write_Log( string, B_INT ); - - FILE* GetLogFile() { return m_logfile; } - - // methods used to add polygons to the eng using points - - //! Start adding a polygon to the engine - /* - The boolean operation work on two groups of polygons ( group A or B ), - other algorithms are only using group A. - - You add polygons like this to the engine. - - // foreach point in a polygon ... - if (booleng->StartPolygonAdd(GROUP_A)) - { - booleng->AddPoint(100,100); - booleng->AddPoint(-100,100); - booleng->AddPoint(-100,-100); - booleng->AddPoint(100,-100); - } - booleng->EndPolygonAdd(); - - \param A_or_B defines if the new polygon will be of group A or B - - Holes or added by adding an inside polygons with opposite orientation compared - to another polygon added. - So the contour polygon ClockWise, then add counterclockwise polygons for holes, and visa versa. - BUT only if m_orientationEntryMode is set true, else all polygons are redirected, and become - individual areas without holes. - Holes in such a case must be linked into the contour using two extra segments. - */ - bool StartPolygonAdd( GroupType A_or_B ); - - //! see StartPolygonAdd - bool AddPoint( double x, double y ); - - //! see StartPolygonAdd - bool EndPolygonAdd(); - - // methods used to extract polygons from the eng by getting its points - - //! Use after StartPolygonGet() - int GetNumPointsInPolygon() { return m_numPtsInPolygon ; } - - //! get resulting polygons at end of an operation - /*! - // foreach resultant polygon in the booleng ... - while ( booleng->StartPolygonGet() ) - { - // foreach point in the polygon - while ( booleng->PolygonHasMorePoints() ) - { - fprintf(stdout,"x = %f\t", booleng->GetPolygonXPoint()); - fprintf(stdout,"y = %f\n", booleng->GetPolygonYPoint()); - } - booleng->EndPolygonGet(); - } - */ - bool StartPolygonGet(); - - //! see StartPolygonGet - /*! - This iterates through the first graph in the graphlist. - Setting the current kbNode properly by following the links in the graph - through its nodes. - */ - bool PolygonHasMorePoints(); - - //! see StartPolygonGet - double GetPolygonXPoint(); - - //! see StartPolygonGet - double GetPolygonYPoint(); - - //! in the resulting polygons this tells if the current polygon segment is one - //! used to link holes into the outer contour of the surrounding polygon - bool GetHoleConnectionSegment(); - - //! in the resulting polygons this tells if the current polygon segment is part - //! of a hole within a polygon. - bool GetHoleSegment(); - - //! an other way to get the type of segment. - kbEdgeType GetPolygonPointEdgeType(); - - //! see StartPolygonGet() - /*! - Removes a graph from the graphlist. - Called after an extraction of an output polygon was done. - */ - void EndPolygonGet(); - -private: - - bool m_doLog; - - //! contains polygons in graph form - kbGraphList* m_graphlist; - - double m_MARGE; - B_INT m_GRID; - double m_DGRID; - double m_CORRECTIONABER; - double m_CORRECTIONFACTOR; - double m_SMOOTHABER; - double m_MAXLINEMERGE; - bool m_WINDINGRULE; - double m_ACCUR; - double m_ROUNDFACTOR; - - bool m_orientationEntryMode; - - bool m_doLinkHoles; - bool m_allowNonTopHoleLinking; - - //! used in the StartPolygonAdd, AddPt, EndPolygonAdd sequence - kbGraph* m_GraphToAdd; - //! used in the StartPolygonAdd, AddPt, EndPolygonAdd sequence - kbNode* m_lastNodeToAdd; - //! used in the StartPolygonAdd, AddPt, EndPolygonAdd sequence - kbNode* m_firstNodeToAdd; - - //! the current group type ( group A or B ) - GroupType m_groupType; - - //! used in extracting the points from the resultant polygons - kbGraph* m_getGraph; - //! used in extracting the points from the resultant polygons - kbLink* m_getLink; - //! used in extracting the points from the resultant polygons - kbNode* m_getNode; - //! used in extracting the points from the resultant polygons - double m_PolygonXPoint; - //! used in extracting the points from the resultant polygons - double m_PolygonYPoint; - //! used in extracting the points from the resultant polygons - int m_numPtsInPolygon; - //! used in extracting the points from the resultant polygons - int m_numNodesVisited; - - FILE* m_logfile; - -public: - - //! use in kbNode to iterate links. - TDLI* _linkiter; - - //! how many time run intersections fase. - unsigned int m_intersectionruns; - -}; - -#endif diff --git a/polygon/kbool/include/kbool/graph.h b/polygon/kbool/include/kbool/graph.h deleted file mode 100644 index 24e21e65df..0000000000 --- a/polygon/kbool/include/kbool/graph.h +++ /dev/null @@ -1,207 +0,0 @@ -/*! \file graph.h - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: graph.h,v 1.5 2009/09/10 17:04:09 titato Exp $ -*/ - -/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/graph.h,v $ $Revision: 1.5 $ $Date: 2009/09/10 17:04:09 $ */ - -/* -Program GRAPH.H -Purpose Used to Intercect and other process functions -Last Update 03-04-1996 -*/ - -#ifndef GRAPH_H -#define GRAPH_H - -#include "kbool/booleng.h" -#include "kbool/_lnk_itr.h" -#include "kbool/link.h" -#include "kbool/line.h" -#include "kbool/scanbeam.h" - -class kbNode; - -class kbGraphList; - -//! one graph containing links that cab be connected. -class A2DKBOOLDLLEXP kbGraph -{ -protected: - Bool_Engine* _GC; -public: - - kbGraph( Bool_Engine* GC ); - kbGraph( kbLink*, Bool_Engine* GC ); - - kbGraph( kbGraph* other ); - - ~kbGraph(); - - bool GetBin() { return _bin; }; - void SetBin( bool b ) { _bin = b; }; - - void Prepare( int intersectionruns ); - void RoundInt( B_INT grid ); - void Rotate( bool plus90 ); - - //! adds a link to the linklist - void AddLink( kbNode *begin, kbNode *end ); - - //! adds a link to the linklist - void AddLink( kbLink *a_link ); - - bool AreZeroLines( B_INT Marge ); - - //! Delete parallel lines - void DeleteDoubles(); - - //! delete zerolines - bool DeleteZeroLines( B_INT Marge ); - bool RemoveNullLinks(); - - //! Process found intersections - void ProcessCrossings(); - //! set flags for operations based on group - void Set_Operation_Flags(); - - //! Left Right values - void Remove_IN_Links(); - - //! reset bin and mark flags in links. - void ResetBinMark(); - - // Remove unused links - void ReverseAllLinks(); - - //! Simplify the kbGraph - bool Simplify( B_INT Marge ); - - - //! Takes over all links of the argument - bool Smoothen( B_INT Marge ); - - void TakeOver( kbGraph* ); - - //! function for maximum performance - - //! Get the First link from the kbGraph - kbLink* GetFirstLink(); - kbNode* GetTopNode(); - void SetBeenHere( bool ); - void Reset_flags(); - - //! Set the group of a kbGraph - void SetGroup( GroupType ); - - //! Set the number of the kbGraph - void SetNumber( int ); - void Reset_Mark_and_Bin(); - bool GetBeenHere(); - int GetGraphNum(); - int GetNumberOfLinks(); - - void Boolean( BOOL_OP operation, kbGraphList* Result ); - void Correction( kbGraphList* Result, double factor ); - void MakeRing( kbGraphList* Result, double factor ); - void CreateRing( kbGraphList *ring, double factor ); - void CreateRing_fast( kbGraphList *ring, double factor ); - void CreateArc( kbNode* center, kbLine* incoming, kbNode* end, double radius, double aber ); - void CreateArc( kbNode* center, kbNode* begin, kbNode* end, double radius, bool clock, double aber ); - void MakeOneDirection(); - void Make_Rounded_Shape( kbLink* a_link, double factor ); - bool MakeClockWise(); - bool writegraph( bool linked ); - bool writeintersections(); - void WriteKEY( Bool_Engine* GC, FILE* file = NULL ); - void WriteGraphKEY( Bool_Engine* GC ); - -protected: - - //! Extracts partical polygons from the graph - /* - Links are sorted in XY at beginpoint. Bin and mark flag are reset. - Next start to collect subparts from the graph, setting the links bin for all found parts. - The parts are searched starting at a topleft corner NON set bin flag link. - Found parts are numbered, to be easily split into to real sperate graphs by Split() - - \param operation operation to collect for. - \param detecthole if you want holes detected, influences also way of extraction. - \param foundholes when holes are found this flag is set true, but only if detecthole is set true. - */ - void Extract_Simples( BOOL_OP operation, bool detecthole, bool& foundholes ); - - //! split graph into small graph, using the numbers in links. - void Split( kbGraphList* partlist ); - - //! Collect a graph by starting at argument link - /* - Called from Extract_Simples, and assumes sorted links with bin flag unset for non extarted piece - - Collect graphs pieces from a total graph, by following links set to a given boolean operation. - \param current_node start node to collect - \param operation operation to collect for. - \param detecthole if you want holes detected, influences also way of extraction. - \param graphnumber number to be given to links in the extracted graph piece - \param foundholes when holes are found this flag is set true. - */ - void CollectGraph( kbNode *current_node, BOOL_OP operation, bool detecthole, int graphnumber, bool& foundholes ); - - void CollectGraphLast( kbNode *current_node, BOOL_OP operation, bool detecthole, int graphnumber, bool& foundholes ); - - //! find a link not bin in the top left corner ( links should be sorted already ) - /*! - Last found position is used to find it quickly. - Used in ExtractSimples() - */ - kbNode* GetMostTopLeft( TDLI* _LI ); - - //! calculates crossing for all links in a graph, and add those as part of the graph. - /* - It is not just crossings calculation, snapping close nodes is part of it. - This is not done at maximum stability in economic time. - There are faster ways, but hardly ever they solve the problems, and they do not snap. - Here it is on purpose split into separate steps, to get a better result in snapping, and - to reach a better stability. - - \param Marge nodes and lines closer to eachother then this, are merged. - */ - bool CalculateCrossings( B_INT Marge ); - - //! equal nodes in position are merged into one. - int Merge_NodeToNode( B_INT Marge ); - - //! basic scan algorithm with a sweeping beam are line. - /*! - \param scantype a different face in the algorithm. - \param holes to detect hole when needed. - */ - int ScanGraph2( SCANTYPE scantype, bool& holes ); - - //! links not used for a certain operation can be deleted, simplifying extraction - void DeleteNonCond( BOOL_OP operation ); - - //! links not used for a certain operation can be set bin, simplifying extraction - void HandleNonCond( BOOL_OP operation ); - - //! debug - bool checksort(); - - //! used in correction/offset algorithm - bool Small( B_INT howsmall ); - - - bool _bin; - - DL_List* _linklist; - -}; - -#endif - - diff --git a/polygon/kbool/include/kbool/graphlst.h b/polygon/kbool/include/kbool/graphlst.h deleted file mode 100644 index 1a9028c25b..0000000000 --- a/polygon/kbool/include/kbool/graphlst.h +++ /dev/null @@ -1,65 +0,0 @@ -/*! \file graphlst.h - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: graphlst.h,v 1.4 2009/09/10 17:04:09 titato Exp $ -*/ - -/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/graphlst.h,v $ $Revision: 1.4 $ $Date: 2009/09/10 17:04:09 $ */ - -/* -Program GRAPHLST.H -Purpose Implements a list of graphs (header) -Last Update 11-03-1996 -*/ - -#ifndef GRAPHLIST_H -#define GRAPHLIST_H - -#include "kbool/booleng.h" - -#include "kbool/_lnk_itr.h" - -#include "kbool/graph.h" - -class Debug_driver; - - -class A2DKBOOLDLLEXP kbGraphList: public DL_List -{ -protected: - Bool_Engine* _GC; -public: - - kbGraphList( Bool_Engine* GC ); - - kbGraphList( kbGraphList* other ); - - ~kbGraphList(); - - void MakeOneGraph( kbGraph *total ); - - void Prepare( kbGraph *total ); - void MakeRings(); - void Correction(); - - void Simplify( double marge ); - void Smoothen( double marge ); - void Merge(); - void Boolean( BOOL_OP operation, int intersectionRunsMax ); - - void WriteGraphs(); - void WriteGraphsKEY( Bool_Engine* GC ); - -protected: - void Renumber(); - void UnMarkAll(); - -}; - - -#endif - diff --git a/polygon/kbool/include/kbool/kboolmod.h b/polygon/kbool/include/kbool/kboolmod.h deleted file mode 100644 index fb3b9e682d..0000000000 --- a/polygon/kbool/include/kbool/kboolmod.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef __A2D_KBOOLMOD_H__ -#define __A2D_KBOOLMOD_H__ - -#include "kbool/booleng.h" -#include "kbool/graph.h" -#include "kbool/graphlst.h" -#include "kbool/line.h" -#include "kbool/link.h" -#include "kbool/lpoint.h" -#include "kbool/node.h" -#include "kbool/record.h" -#include "kbool/scanbeam.h" - -#endif - diff --git a/polygon/kbool/include/kbool/line.h b/polygon/kbool/include/kbool/line.h deleted file mode 100644 index 07187e825e..0000000000 --- a/polygon/kbool/include/kbool/line.h +++ /dev/null @@ -1,107 +0,0 @@ -/*! \file line.h - \brief Mainy used for calculating crossings - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: line.h,v 1.5 2009/09/10 17:04:09 titato Exp $ -*/ - -#ifndef LINE_H -#define LINE_H - -#include "kbool/booleng.h" -#include "kbool/link.h" - -class A2DKBOOLDLLEXP Bool_Engine; - -// Status of a point to a line -enum PointStatus {LEFT_SIDE, RIGHT_SIDE, ON_AREA, IN_AREA}; - -class A2DKBOOLDLLEXP kbGraph; - -class A2DKBOOLDLLEXP kbLine -{ -protected: - Bool_Engine* m_GC; -public: - - // constructors and destructor - kbLine( Bool_Engine* GC ); - kbLine( kbLink*, Bool_Engine* GC ); - ~kbLine(); - - void Set( kbLink * ); - kbLink* GetLink(); - - //! Get the beginnode from a line - kbNode* GetBeginNode(); - - //! Get the endnode from a line - kbNode* GetEndNode(); - - //! Check if two lines intersects - int CheckIntersect( kbLine*, double Marge ); - - //! Intersects two lines - int Intersect( kbLine*, double Marge ); - int Intersect_simple( kbLine * lijn ); - bool Intersect2( kbNode* crossing, kbLine * lijn ); - - //!For an infinite line - PointStatus PointOnLine( kbNode* a_node, double& Distance, double Marge ); - - //!For a non-infinite line - PointStatus PointInLine( kbNode* a_node, double& Distance, double Marge ); - - //! Caclulate Y if X is known - B_INT Calculate_Y( B_INT X ); - B_INT Calculate_Y_from_X( B_INT X ); - void Virtual_Point( kbLPoint *a_point, double distance ); - - //! assignment operator - kbLine& operator=( const kbLine& ); - - kbNode* OffsetContour( kbLine* const nextline, kbNode* last_ins, double factor, kbGraph *shape ); - kbNode* OffsetContour_rounded( kbLine* const nextline, kbNode* _last_ins, double factor, kbGraph *shape ); - bool OkeForContour( kbLine* const nextline, double factor, kbNode* LastLeft, kbNode* LastRight, LinkStatus& _outproduct ); - bool Create_Ring_Shape( kbLine* nextline, kbNode** _last_ins_left, kbNode** _last_ins_right, double factor, kbGraph *shape ); - void Create_Begin_Shape( kbLine* nextline, kbNode** _last_ins_left, kbNode** _last_ins_right, double factor, kbGraph *shape ); - void Create_End_Shape( kbLine* nextline, kbNode* _last_ins_left, kbNode* _last_ins_right, double factor, kbGraph *shape ); - - //! Calculate the parameters if nessecary - void CalculateLineParameters(); - - //! Adds a crossing between the intersecting lines - void AddLineCrossing( B_INT , B_INT , kbLine * ); - - void AddCrossing( kbNode *a_node ); - kbNode* AddCrossing( B_INT X, B_INT Y ); - bool ProcessCrossings( TDLI* _LI ); - -// Linecrosslist - void SortLineCrossings(); - bool CrossListEmpty(); - DL_List* GetCrossList(); -// bool HasInCrossList(kbNode*); - -private: - - //! Function needed for Intersect - int ActionOnTable1( PointStatus, PointStatus ); - //! Function needed for Intersect - int ActionOnTable2( PointStatus, PointStatus ); - - double m_AA; - double m_BB; - double m_CC; - kbLink* m_link; - bool m_valid_parameters; - - //! List with crossings through this link - DL_List *linecrosslist; -}; - -#endif diff --git a/polygon/kbool/include/kbool/link.h b/polygon/kbool/include/kbool/link.h deleted file mode 100644 index d7f1301338..0000000000 --- a/polygon/kbool/include/kbool/link.h +++ /dev/null @@ -1,230 +0,0 @@ -/*! \file link.h - \brief Part of a graph, connection between nodes (Header) - \author Klaas Holwerda or Julian Smart - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: link.h,v 1.5 2009/09/10 17:04:09 titato Exp $ -*/ - -#ifndef LINK_H -#define LINK_H - -#include "kbool/booleng.h" -#include "kbool/_lnk_itr.h" - -enum LinkStatus {IS_LEFT, IS_ON, IS_RIGHT}; - -class kbLPoint; -class kbNode; -class kbRecord; - -//! segment within a graph -/* - A Graph contains a list of kbLink, the kbLink or connected by Node's. - Several kbLink can be connected to one Node. - A kbLink has a direction defined by its begin and end node. - Node do have a list of connected kbLink's. - So one can walk trough a graph in two ways: - 1- via its kbLink list - 2- via the node connected to the kbLink's -*/ -class A2DKBOOLDLLEXP kbLink -{ -protected: - Bool_Engine* _GC; -public: - - //! contructors - kbLink( Bool_Engine* GC ); - - //! contructors - kbLink( int graphnr, kbNode* begin, kbNode* end, Bool_Engine* GC ); - - //! contructors - kbLink( kbNode *begin, kbNode *end, Bool_Engine* GC ); - - //! destructors - ~kbLink(); - - - //! Merges the other node with argument - void MergeNodes( kbNode* const ); - - //! outproduct of two links - LinkStatus OutProduct( kbLink* const two, double accur ); - - //! link three compared to this and two - LinkStatus PointOnCorner( kbLink* const, kbLink* const ); - - //! Removes argument from the link - void Remove( kbNode* ); - - //! replaces olddone in the link by newnode - void Replace( kbNode* oldnode, kbNode* newnode ); - - //!top hole marking - void SetTopHole( bool value ); - - //!top hole marking - bool IsTopHole(); - - //! Marking functions - void UnMark(); - //! Marking functions - void Mark(); - //! Marking functions - void SetMark( bool ); - //! Marking functions - bool IsMarked(); - - //! holelink Marking functions - void SetHoleLink( bool val ){ m_holelink = val;}; - - //! holelink Marking functions - bool GetHoleLink(){ return m_holelink;}; - - //! Bin functions - void SetNotBeenHere(); - //! Bin functions - void SetBeenHere(); - //! Have you been here ?? - bool BeenHere(); - - //! Removes all the references to this - void UnLink(); - - //! functions for maximum performance - kbNode* GetBeginNode(); - - //! Datamember access functions - kbNode* GetEndNode(); - kbNode* GetLowNode(); - kbNode* GetHighNode(); - - //! Returns a next link beginning with argument - kbLink* Forth( kbNode* ); - - int GetGraphNum(); - bool GetInc(); - bool GetLeftA(); - bool GetLeftB(); - bool GetRightA(); - bool GetRightB(); - void GetLRO( kbLPoint*, int&, int&, double ); - - //! Return a node not equal to arg. - kbNode* GetOther( const kbNode* const ); - //! Is this link unused ? - bool IsUnused(); - - //! Used for given operation ? - bool IsMarked( BOOL_OP operation ); - - //! return true if Left side is marked true for operation - bool IsMarkedLeft( BOOL_OP operation ); - - //! return true if Right side is marked true for operation - bool IsMarkedRight( BOOL_OP operation ); - - //! is this a hole link for given operation - bool IsHole( BOOL_OP operation ); - - //! set the hole mark - void SetHole( bool ); - - //! is the hole mark set? - bool GetHole(); - - //! Are the nodes on about the same coordinates ? - bool IsZero( B_INT marge ); - bool ShorterThan( B_INT marge ); - - //! Resets the link - void Reset( kbNode* begin, kbNode* end, int graphnr = 0 ); - void Set( kbNode* begin, kbNode* end ); - void SetBeginNode( kbNode* ); - void SetEndNode( kbNode* ); - void SetGraphNum( int ); - void SetInc( bool ); - void SetLeftA( bool ); - void SetLeftB( bool ); - void SetRightA( bool ); - void SetRightB( bool ); - void SetGroup( GroupType ); - GroupType Group(); - - //! Flag calculation (internal only) - void SetLineTypes(); - void Reset(); - void Reset_flags(); - - //!put in this direction - void Redirect( kbNode* a_node ); - - void TakeOverOperationFlags( kbLink* link ); - - void SetRecordNode( DL_Node* recordNode ) { m_record = recordNode; } - - DL_Node* GetRecordNode() { return m_record; } - -protected: - - //! The mainitems of a link - kbNode *m_beginnode, *m_endnode; - //! Marker for walking over the graph -bool m_bin : 1; - //! Is this a part of hole ? -bool m_hole : 1; - //! link that is toplink of hole? -bool m_hole_top : 1; - //! going in one more time in this graph if true else going out one time -bool m_Inc : 1; - //! Is left in polygongroup A -bool m_LeftA : 1; - //! Is right in polygon group A -bool m_RightA : 1; - //! Is left in polygon group B -bool m_LeftB : 1; - //! Is right in polygongroup B -bool m_RightB : 1; - //! General purose marker, internally unused -bool m_mark : 1; - //! link for linking holes -bool m_holelink : 1; - - //! Marker for Merge Left -bool m_merge_L : 1; - //! Marker for substract a-b Left -bool m_a_substract_b_L: 1; - //! Marker for substract b-a Left -bool m_b_substract_a_L: 1; - //! Marker for intersect Left -bool m_intersect_L: 1; - //! Marker for X-OR Left -bool m_exor_L: 1; - - //! Marker for Merge Right -bool m_merge_R : 1; - //! Marker for substract a-b Right -bool m_a_substract_b_R: 1; - //! Marker for substract b-a Right -bool m_b_substract_a_R: 1; - //! Marker for intersect Right -bool m_intersect_R: 1; - //! Marker for X-OR Right -bool m_exor_R: 1; - - //! belongs to group A or B -GroupType m_group : 1; - - //! belongs to this polygon part in the graph. - int m_graphnum; - - DL_Node* m_record; -}; - -#endif - diff --git a/polygon/kbool/include/kbool/lpoint.h b/polygon/kbool/include/kbool/lpoint.h deleted file mode 100644 index 3c9c737a14..0000000000 --- a/polygon/kbool/include/kbool/lpoint.h +++ /dev/null @@ -1,60 +0,0 @@ -/*! \file lpoint.h - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: lpoint.h,v 1.4 2009/09/10 17:04:09 titato Exp $ -*/ - -/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/lpoint.h,v $ $Revision: 1.4 $ $Date: 2009/09/10 17:04:09 $ */ - -/* -Program LPOINT.H -Purpose Definition of GDSII pointtype structure -Last Update 12-12-1995 -*/ - -#ifndef LPOINT_H -#define LPOINT_H - -#include "kbool/booleng.h" - -class A2DKBOOLDLLEXP kbLPoint -{ -public: - kbLPoint(); - kbLPoint( B_INT const , B_INT const ); - kbLPoint( kbLPoint* const ); - - void Set( const B_INT, const B_INT ); - void Set( const kbLPoint & ); - - kbLPoint GetPoint(); - B_INT GetX(); - B_INT GetY(); - void SetX( B_INT ); - void SetY( B_INT ); - bool Equal( const kbLPoint a_point, B_INT Marge ); - bool Equal( const B_INT, const B_INT , B_INT Marge ); - bool ShorterThan( const kbLPoint a_point, B_INT marge ); - bool ShorterThan( const B_INT X, const B_INT Y, B_INT ); - - kbLPoint &operator=( const kbLPoint & ); - kbLPoint &operator+( const kbLPoint & ); - kbLPoint &operator-( const kbLPoint & ); - - kbLPoint &operator*( int ); - kbLPoint &operator/( int ); - - int operator==( const kbLPoint & ) const; - int operator!=( const kbLPoint & ) const; - -protected: - B_INT _x; - B_INT _y; - -}; - -#endif diff --git a/polygon/kbool/include/kbool/node.h b/polygon/kbool/include/kbool/node.h deleted file mode 100644 index db32f25855..0000000000 --- a/polygon/kbool/include/kbool/node.h +++ /dev/null @@ -1,87 +0,0 @@ -/*! \file node.h - \brief Holds a GDSII node structure (Header) - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: node.h,v 1.7 2009/09/14 16:50:12 titato Exp $ -*/ - -#ifndef NODE_H -#define NODE_H - -#include "kbool/booleng.h" - -#include "kbool/lpoint.h" - -#include "kbool/link.h" -#include "kbool/_lnk_itr.h" // LinkBaseIter -#include - -enum NodePosition { N_LEFT, N_ON, N_RIGHT}; - -class A2DKBOOLDLLEXP kbNode : public kbLPoint -{ -protected: - Bool_Engine* _GC; -public: - // friend must be deleted in the final version! - friend class Debug_driver; - - // constructors and destructors - kbNode( Bool_Engine* GC ); - - kbNode( const B_INT, const B_INT, Bool_Engine* GC ); - - kbNode( kbLPoint* const a_point, Bool_Engine* GC ); - kbNode( kbNode * const, Bool_Engine* GC ); - kbNode& operator=( const kbNode &other_node ); - ~kbNode(); - - //public member functions - void AddLink( kbLink* ); - DL_List* GetLinklist(); - - //! check two link for its operation flags to be the same when coming from the prev link. - bool SameSides( kbLink* const prev , kbLink* const link, BOOL_OP operation ); - - //! get the link most right or left to the current link, but with the specific operation - /*! flags the same on the sides of the new link. - */ - kbLink* GetMost( kbLink* const prev , LinkStatus whatside, BOOL_OP operation ); - - //! get link that is leading to a hole ( hole segment or linking segment ) - kbLink* GetMostHole( kbLink* const prev , LinkStatus whatside, BOOL_OP operation, - bool searchholelink = true ); - - //! get link that is not vertical. - kbLink* GetNotFlat(); - - //! get a link to a hole or from a hole. - kbLink* GetHoleLink( kbLink* const prev, LinkStatus whatside, - bool checkbin, BOOL_OP operation ); - - int Merge( kbNode* ); - void RemoveLink( kbLink* ); - bool Simplify( kbNode* First, kbNode* Second, B_INT Marge ); - - // memberfunctions for maximum performance - void RoundInt( B_INT grid ); - kbLink* GetIncomingLink(); - - int GetNumberOfLinks(); - kbLink* GetNextLink(); - kbLink* GetOtherLink( kbLink* ); - kbLink* GetOutgoingLink(); - kbLink* GetPrevLink(); - - kbLink* Follow( kbLink* const prev ); - kbLink* GetBinHighest( bool binset ); - -protected: - DL_List* _linklist; -}; - -#endif diff --git a/polygon/kbool/include/kbool/record.h b/polygon/kbool/include/kbool/record.h deleted file mode 100644 index d0bb2a7cd3..0000000000 --- a/polygon/kbool/include/kbool/record.h +++ /dev/null @@ -1,78 +0,0 @@ -/*! \file record.h - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: record.h,v 1.5 2009/09/10 17:04:09 titato Exp $ -*/ - -#ifndef RECORD_H -#define RECORD_H - -class kbNode; -#include "kbool/booleng.h" - -#include "kbool/link.h" -#include "kbool/line.h" - -enum BEAM_TYPE { NORMAL, FLAT}; - -enum DIRECTION {GO_LEFT, GO_RIGHT}; - -//extern void DeleteRecordPool(); -class A2DKBOOLDLLEXP Bool_Engine; - -class A2DKBOOLDLLEXP kbRecord -{ -protected: - Bool_Engine* _GC; -public: -// void deletepool(); - - kbRecord( kbLink* link, Bool_Engine* GC ); - - ~kbRecord(); - -// void* operator new(size_t size); - -// void operator delete(void* recordptr); - - void SetNewLink( kbLink* link ); - - void Set_Flags(); - - void Calc_Ysp( kbNode* low ); - - kbLink* GetLink(); - - kbLine* GetLine(); - - B_INT Ysp(); - - void SetYsp( B_INT ysp ); - - DIRECTION Direction(); - - bool Calc_Left_Right( kbRecord* record_above_me ); - - bool Equal( kbRecord* ); - -private: - kbLine _line; - - B_INT _ysp; - - //! going left are right in beam - DIRECTION _dir; - - //! how far in group_a - int _a; - - //! how far in group_b - int _b; - -}; - -#endif diff --git a/polygon/kbool/include/kbool/scanbeam.h b/polygon/kbool/include/kbool/scanbeam.h deleted file mode 100644 index 43eb09e716..0000000000 --- a/polygon/kbool/include/kbool/scanbeam.h +++ /dev/null @@ -1,58 +0,0 @@ -/*! \file scanbeam.h - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: scanbeam.h,v 1.6 2009/09/10 17:04:09 titato Exp $ -*/ - -#ifndef SCANBEAM_H -#define SCANBEAM_H - -#include "kbool/booleng.h" -#include "kbool/_lnk_itr.h" - -#include "kbool/record.h" -#include "kbool/link.h" - -enum SCANTYPE{NODELINK, LINKLINK, GENLR, LINKHOLES, INOUT}; - -#if defined(WXART2D_USINGDLL) -template class A2DKBOOLDLLEXP DL_Iter; -#endif - -class A2DKBOOLDLLEXP ScanBeam : public DL_List -{ -protected: - Bool_Engine* _GC; - -public: - ScanBeam( Bool_Engine* GC ); - ~ScanBeam(); - void SetType( kbNode* low, kbNode* high ); - - bool FindNew( SCANTYPE scantype, TDLI* _I, bool& holes ); - bool RemoveOld( SCANTYPE scantype, TDLI* _I, bool& holes ); - -private: - - bool ProcessHoles( bool atinsert, TDLI* _LI ); - int Process_LinkToLink_Crossings(); // find crossings - int Process_PointToLink_Crossings(); - int Process_LinkToLink_Flat( kbLine* flatline ); - void SortTheBeam( bool backangle ); - bool checksort(); - bool writebeam(); - void Calc_Ysp(); - //int FindCloseLinksAndCross(TDLI* _I,kbNode* _lowf); - void Generate_INOUT( int graphnumber ); - - kbNode* _low; - DL_Iter _BI; - int lastinserted; - BEAM_TYPE _type; -}; - -#endif diff --git a/polygon/kbool/include/kbool/statusb.h b/polygon/kbool/include/kbool/statusb.h deleted file mode 100644 index f961a84fb9..0000000000 --- a/polygon/kbool/include/kbool/statusb.h +++ /dev/null @@ -1,54 +0,0 @@ -/*! \file statusb.h - \author Probably Klaas Holwerda - - Copyright: 2001-2004 (C) Probably Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: statusb.h,v 1.3 2009/02/06 21:33:03 titato Exp $ -*/ - -/* @@(#) $Source: /cvsroot/wxart2d/wxArt2D/thirdparty/kbool/include/kbool/statusb.h,v $ $Revision: 1.3 $ $Date: 2009/02/06 21:33:03 $ */ - -/* -Program STATUSB.H -Purpose Controls the statusbar of the application (header) - This statusbar is a typical Windows statusbar - For porting to another platform there must be a StatusBar class - derived from this. - User interface element (See documentation for more details - about the functions needed in this class) -*/ - -#ifndef STATUSB_H -#define STATUSB_H -#include - -// abstract base class for own statusbar inherite from it -class A2DKBOOLDLLEXP StatusBar -{ -public: - // constructor & destructor - StatusBar(){}; - ~StatusBar(){}; - - virtual void SetXY( double = 0.0, double = 0.0 ) = 0; - virtual void ResetCoord() = 0; - virtual void SetFile( char* = 0 ) = 0; - virtual void SetProcess( char* = 0 ) = 0; - virtual void SetTime( time_t seconds = 0 ) = 0; - virtual void SetRecording( int status = 0 ) = 0; - virtual void SetZoom( float factor = 1 ) = 0; - virtual void Reset() = 0; - void StartDTimer(); - void EndDTimer(); - int GetDTimerOn(); - time_t GetDTimer(); - -protected: - int timer; - time_t oldtime; - time_t curtime; -}; - -#endif diff --git a/polygon/kbool/include/kbool/valuesvc.h b/polygon/kbool/include/kbool/valuesvc.h deleted file mode 100644 index bf4e83ec0b..0000000000 --- a/polygon/kbool/include/kbool/valuesvc.h +++ /dev/null @@ -1,9 +0,0 @@ -/*! \file valuesvc.h - \author Probably Klaas Holwerda - - Copyright: 2001-2004 (C) Probably Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: valuesvc.h,v 1.2 2009/02/06 21:33:03 titato Exp $ -*/ diff --git a/polygon/kbool/infos_kbool.txt b/polygon/kbool/infos_kbool.txt deleted file mode 100644 index 60763fef5f..0000000000 --- a/polygon/kbool/infos_kbool.txt +++ /dev/null @@ -1,7 +0,0 @@ -Boolean: GDSII viewer/editor + (boolean) operations on sets of 2d polygons. -Boolean Web Site: -http://boolean.klaasholwerda.nl/bool.html - -kbool is also used in wxArt2D -see www.wxart2d.org -the last version of kbool can be found on this site. diff --git a/polygon/kbool/kboollicense.txt b/polygon/kbool/kboollicense.txt deleted file mode 100644 index ba18bacda0..0000000000 --- a/polygon/kbool/kboollicense.txt +++ /dev/null @@ -1,684 +0,0 @@ -The kbool library is dual licensed. -The GPL applies for open source, but for commercial use it is proprietary. -Contact copyright holder for more information on other licensing schemes. - -Software library is provided "AS IS" without warranty of any kind, conform point 16 and 17 down here. - -Next a copy of the GPL license text. - -========================================================================== - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. \ No newline at end of file diff --git a/polygon/kbool/samples/boolonly/CMakeLists.txt b/polygon/kbool/samples/boolonly/CMakeLists.txt deleted file mode 100644 index c9f5f5e1c0..0000000000 --- a/polygon/kbool/samples/boolonly/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_executable(boolonly boolonly.cpp) - -if(WIN32) - add_definitions(-D_MSWVC_) -else(WIN32) - add_definitions(-D__UNIX__) -endif(WIN32) - -include_directories(${kbool_SOURCE_DIR}/..) - -target_link_libraries(boolonly kbool) diff --git a/polygon/kbool/samples/boolonly/boolonly.cpp b/polygon/kbool/samples/boolonly/boolonly.cpp deleted file mode 100644 index b2aa422995..0000000000 --- a/polygon/kbool/samples/boolonly/boolonly.cpp +++ /dev/null @@ -1,373 +0,0 @@ -/*! \file samples/boolonly/boolonly.cpp - \brief boolonly demonstrates the use of the boolean algorithm - \author Probably Klaas Holwerda - - Copyright: 2001-2004 (C) Probably Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: boolonly.cpp,v 1.7 2009/05/28 19:49:48 titato Exp $ -*/ - - -#include "boolonly.h" - -#include - -// Constructors -KBoolPoint::KBoolPoint() -{ - _x = 0.0; - _y = 0.0; -} - -KBoolPoint::KBoolPoint( double const X, double const Y ) -{ - _x = X; - _y = Y; -} - -double KBoolPoint::GetX() -{ - return _x; -} - -double KBoolPoint::GetY() -{ - return _y; -} - -template class TDLI; - - -void ArmBoolEng( Bool_Engine* booleng ) -{ - // set some global vals to arm the boolean engine - double DGRID = 1000; // round coordinate X or Y value in calculations to this - double MARGE = 0.001; // snap with in this range points to lines in the intersection routines - // should always be > DGRID a MARGE >= 10*DGRID is oke - // this is also used to remove small segments and to decide when - // two segments are in line. - double CORRECTIONFACTOR = 500.0; // correct the polygons by this number - double CORRECTIONABER = 1.0; // the accuracy for the rounded shapes used in correction - double ROUNDFACTOR = 1.5; // when will we round the correction shape to a circle - double SMOOTHABER = 10.0; // accuracy when smoothing a polygon - double MAXLINEMERGE = 1000.0; // leave as is, segments of this length in smoothen - - - // DGRID is only meant to make fractional parts of input data which - // are doubles, part of the integers used in vertexes within the boolean algorithm. - // Within the algorithm all input data is multiplied with DGRID - - // space for extra intersection inside the boolean algorithms - // only change this if there are problems - int GRID = 10000; - - booleng->SetMarge( MARGE ); - booleng->SetGrid( GRID ); - booleng->SetDGrid( DGRID ); - booleng->SetCorrectionFactor( CORRECTIONFACTOR ); - booleng->SetCorrectionAber( CORRECTIONABER ); - booleng->SetSmoothAber( SMOOTHABER ); - booleng->SetMaxlinemerge( MAXLINEMERGE ); - booleng->SetRoundfactor( ROUNDFACTOR ); - -} - -void AddPolygonsToBoolEng2( Bool_Engine* booleng ) -{ - int x1 = 100; - int x2 = 200; - int y1 = 100; - int y2 = 200; - int pitch1 = 200; - int numRowsAndCols = 120; - int i, j; - - for ( i = 0; i < numRowsAndCols; i++ ) - { - for ( j = 0; j < numRowsAndCols; j++ ) - { - // foreach point in a polygon ... - if ( booleng->StartPolygonAdd( GROUP_A ) ) - { - // Counter-Clockwise - booleng->AddPoint( x1, y1 ); - booleng->AddPoint( x2, y1 ); - booleng->AddPoint( x2, y2 ); - booleng->AddPoint( x1, y2 ); - - } - booleng->EndPolygonAdd(); - x1 += pitch1; - x2 += pitch1; - } - x1 = 100; - x2 = 200; - - y1 += pitch1; - y2 += pitch1; - - } - - x1 = 150; - x2 = 250; - y1 = 150; - y2 = 250; - - for ( i = 0; i < numRowsAndCols; i++ ) - { - for ( int j = 0; j < numRowsAndCols; j++ ) - { - // foreach point in a polygon ... - if ( booleng->StartPolygonAdd( GROUP_B ) ) - { - // Counter Clockwise - booleng->AddPoint( x1, y1 ); - booleng->AddPoint( x2, y1 ); - booleng->AddPoint( x2, y2 ); - booleng->AddPoint( x1, y2 ); - - } - booleng->EndPolygonAdd(); - x1 += pitch1; - x2 += pitch1; - } - x1 = 150; - x2 = 250; - - y1 += pitch1; - y2 += pitch1; - - } - -} - -void AddPolygonsToBoolEng( Bool_Engine* booleng ) -{ - // foreach point in a polygon ... - if ( booleng->StartPolygonAdd( GROUP_A ) ) - { - booleng->AddPoint( 28237.480000, 396.364000 ); - booleng->AddPoint( 28237.980000, 394.121000 ); - booleng->AddPoint( 28242.000000, 395.699000 ); - booleng->AddPoint( 28240.830000, 397.679000 ); - } - booleng->EndPolygonAdd(); - - // foreach point in a polygon ... - if ( booleng->StartPolygonAdd( GROUP_B ) ) - { - booleng->AddPoint( 28242.100000, 398.491000 ); - booleng->AddPoint( 28240.580000, 397.485000 ); - booleng->AddPoint( 28237.910000, 394.381000 ); - } - booleng->EndPolygonAdd(); - - if ( booleng->StartPolygonAdd( GROUP_B ) ) - { - booleng->AddPoint( 28243.440000, 399.709000 ); - booleng->AddPoint( 28237.910000, 394.381000 ); - booleng->AddPoint( 28239.290000, 394.763000 ); - } - booleng->EndPolygonAdd(); -} - -void AddPolygonsToBoolEng3( Bool_Engine* booleng ) -{ - // foreach point in a polygon ... - if ( booleng->StartPolygonAdd( GROUP_A ) ) - { - booleng->AddPoint( 100, 100 ); - booleng->AddPoint( -100, 100 ); - booleng->AddPoint( -100, -100 ); - booleng->AddPoint( 100, -100 ); - } - booleng->EndPolygonAdd(); - - // foreach point in a polygon ... - if ( booleng->StartPolygonAdd( GROUP_B ) ) - { - booleng->AddPoint( 50, 50 ); - booleng->AddPoint( -50, 50 ); - booleng->AddPoint( -50, -50 ); - booleng->AddPoint( 50, -50 ); - booleng->EndPolygonAdd(); - } - booleng->EndPolygonAdd(); -} - -void AddPolygonsToBoolEng4( Bool_Engine* booleng ) -{ - // foreach point in a polygon ... - if ( booleng->StartPolygonAdd( GROUP_A ) ) - { - booleng->AddPoint( 0, 0 ); - booleng->AddPoint( 0, 1000 ); - booleng->AddPoint( 1000, 1000 ); - booleng->AddPoint( 1000, 0 ); - } - booleng->EndPolygonAdd(); -} - -void GetPolygonsFromBoolEng( Bool_Engine* booleng ) -{ - // foreach resultant polygon in the booleng ... - while ( booleng->StartPolygonGet() ) - { - // foreach point in the polygon - while ( booleng->PolygonHasMorePoints() ) - { - fprintf( stderr, "x = %f\t", booleng->GetPolygonXPoint() ); - fprintf( stderr, "y = %f\n", booleng->GetPolygonYPoint() ); - } - booleng->EndPolygonGet(); - } -} - -void GetPolygonsFromBoolEngKEY( Bool_Engine* booleng ) -{ - FILE * file = fopen( "keyfile.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 0.0001; PHYSUNITS 2.54e-009; \ - \ - BGNSTR; \ - CREATION {2-11-15 15:39:21}; \ - LASTMOD {2-11-15 15:39:21}; \ - STRNAME top; \ - "); - // foreach resultant polygon in the booleng ... - while ( booleng->StartPolygonGet() ) - { - fprintf(file,"BOUNDARY; LAYER 2; DATATYPE 0;\n"); - fprintf(file," XY % d; \n",booleng->GetNumPointsInPolygon()+1 ); - - booleng->PolygonHasMorePoints(); - double firstx = booleng->GetPolygonXPoint(); - double firsty = booleng->GetPolygonYPoint(); - fprintf(file,"X % f;\t", firstx); - fprintf(file,"Y % f; \n", firsty); - - // foreach point in the polygon - while ( booleng->PolygonHasMorePoints() ) - { - fprintf(file,"X % f;\t", booleng->GetPolygonXPoint()); - fprintf(file,"Y % f; \n", booleng->GetPolygonYPoint()); - } - booleng->EndPolygonGet(); - fprintf(file,"X % f;\t", firstx); - fprintf(file,"Y % f; \n", firsty); - fprintf(file,"ENDEL;\n"); - } - - fprintf(file,"\ - ENDSTR top; \ - ENDLIB; \ - "); - fclose (file); -} - -int main() -{ - printf( "------------------------------------------------------\n" ); - printf( " | Unit test of the KBool Engine | \n" ); - printf( "------------------------------------------------------\n" ); - - float correction; - char a = '1'; - while (a != '0') - { - Bool_Engine* booleng = new Bool_Engine(); - ArmBoolEng( booleng ); - - AddPolygonsToBoolEng3( booleng ); - - printf( "\n***********************************\n" ); - printf( "*** version: % s \n", booleng->GetVersion().c_str() ); - printf( "***********************************\n" ); - printf( "1: OR operation\n" ); - printf( "2: AND operation\n" ); - printf( "3: EXOR operation\n" ); - printf( "4: A subtract B\n" ); - printf( "5: B subtract A\n" ); - printf( "6: Correct each polygon with a factor\n" ); - printf( "7: Smoothen each polygon\n" ); - printf( "8: Make a ring around each polygon\n" ); - printf( "9: No operation\n" ); - printf( "0: Quit\n" ); - printf( "***********************************\n" ); - - printf( "type a number and " ); - scanf("%c", &a, 1); - //scanf( " % c", &a ); - - switch (a) - { - case ('0'): - { - GetPolygonsFromBoolEng( booleng ); - break; - } - case ('1'): - booleng->Do_Operation(BOOL_OR); - break; - case ('2'): - booleng->Do_Operation(BOOL_AND); - break; - case ('3'): - booleng->Do_Operation(BOOL_EXOR); - break; - case ('4'): - booleng->Do_Operation(BOOL_A_SUB_B); - break; - case ('5'): - booleng->Do_Operation(BOOL_B_SUB_A); - break; - case ('6'): - printf( "give correction factor ( eg. 100.0 or - 100.0 ): "); - scanf(" % f", &correction ); // correct the polygons by this number - booleng->SetCorrectionFactor( correction ); - booleng->Do_Operation(BOOL_CORRECTION); - break; - case ('7'): - booleng->Do_Operation(BOOL_SMOOTHEN); - break; - case ('8'): - printf("give width of ring : "); - scanf(" % f", &correction ); - // create a ring of this size - booleng->SetCorrectionFactor( fabs( correction / 2.0) ); - booleng->Do_Operation(BOOL_MAKERING); - break; - case ('9'): - break; - default: - break; - - } - - if (a != '0') - { - printf("\nresulting polygons\n" ); - - GetPolygonsFromBoolEng( booleng ); - - //OR USE THIS - //GetPolygonsFromBoolEngKEY( booleng ); - - printf( "\n\ntype a character and "); - scanf( " % c", &a ); - } - delete booleng; - } - - return 0; -} - diff --git a/polygon/kbool/samples/boolonly/boolonly.h b/polygon/kbool/samples/boolonly/boolonly.h deleted file mode 100644 index e75aea11c5..0000000000 --- a/polygon/kbool/samples/boolonly/boolonly.h +++ /dev/null @@ -1,28 +0,0 @@ -/*! \file kbool/samples/boolonly/boolonly.h - \author Probably Klaas Holwerda - - Copyright: 2001-2004 (C) Probably Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: boolonly.h,v 1.5 2009/02/06 21:33:03 titato Exp $ -*/ - -#include "kbool/booleng.h" -#include "kbool/_lnk_itr.h" - -class KBoolPoint -{ -public: - - KBoolPoint(); - KBoolPoint( double const , double const ); - double GetX(); - double GetY(); - -private: - double _x; - double _y; - -}; - diff --git a/polygon/kbool/samples/boolonly/boolonly.rc b/polygon/kbool/samples/boolonly/boolonly.rc deleted file mode 100644 index 85ac88f203..0000000000 --- a/polygon/kbool/samples/boolonly/boolonly.rc +++ /dev/null @@ -1,2 +0,0 @@ -mondrian ICON "sample.ico" -#include "wx/msw/wx.rc" diff --git a/polygon/kbool/src/CMakeLists.txt b/polygon/kbool/src/CMakeLists.txt deleted file mode 100644 index 5a8aa68175..0000000000 --- a/polygon/kbool/src/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -if(WIN32) - add_definitions(-D_MSWVC_) -else(WIN32) - add_definitions(-D__UNIX__) -endif(WIN32) - - -include_directories(../include) - -set(KBOOL_SRCS - booleng.cpp - graph.cpp - graphlst.cpp - line.cpp - link.cpp - lpoint.cpp - node.cpp - record.cpp - scanbeam.cpp) - -add_library(kbool STATIC ${KBOOL_SRCS}) diff --git a/polygon/kbool/src/booleng.cpp b/polygon/kbool/src/booleng.cpp deleted file mode 100644 index 50c5a629a6..0000000000 --- a/polygon/kbool/src/booleng.cpp +++ /dev/null @@ -1,585 +0,0 @@ -/*! \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 - -#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(); - 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 ); -} diff --git a/polygon/kbool/src/graph.cpp b/polygon/kbool/src/graph.cpp deleted file mode 100644 index cab57cda72..0000000000 --- a/polygon/kbool/src/graph.cpp +++ /dev/null @@ -1,2629 +0,0 @@ -/*! \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(); - - _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(); - _bin = false; -} - -kbGraph::kbGraph( kbGraph* other ) -{ - _GC = other->_GC; - _linklist = new DL_List(); - _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _linklist ); - if ( _LI.empty() ) return; - _LI.foreach_mf( &kbLink::UnMark );//reset bin and mark flag of each link -} - -void kbGraph::ReverseAllLinks() -{ - kbNode * dummy; - TDLI _LI = TDLI( _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 _LI = TDLI( _linklist ); - _LI.foreach_mf( &kbLink::Reset_flags ); -} - -// ReSet the bin and mark flag of the links -void kbGraph::Reset_Mark_and_Bin() -{ - TDLI _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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* _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 _LI = TDLI( _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 _LI=TDLI(_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 _LI = TDLI( _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 links = TDLI( _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 _LI = TDLI( _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 IResult = TDLI( 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 IResult = TDLI( 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 IResult = TDLI( 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 _LI = TDLI( _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 _LI = TDLI( _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 Iring = TDLI( 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 _LI = TDLI( _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 _LI = TDLI( _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 _LI = TDLI( _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 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 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 _LI = TDLI( _linklist ); - if ( _LI.empty() ) - { - return true; - } - - _LI.tohead(); - while( !_LI.hitroot() ) - { - kbLink * curl = _LI.item(); - TDLI 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 _LI = TDLI( _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 _LI=TDLI(_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 _LI=TDLI(_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 -} - - - - diff --git a/polygon/kbool/src/graphlst.cpp b/polygon/kbool/src/graphlst.cpp deleted file mode 100644 index 64049bae06..0000000000 --- a/polygon/kbool/src/graphlst.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/*! \file src/graphlst.cpp - \brief Implements a list of graphs - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: graphlst.cpp,v 1.4 2009/09/10 17:04:09 titato Exp $ -*/ - -//#include "debugdrv.h" -#include "kbool/booleng.h" -#include "kbool/graphlst.h" - -//extern Debug_driver* _debug_driver; -//this here is to initialize the static iterator of graphlist -//with NOLIST constructor - -int graphsorterX( kbGraph *, kbGraph * ); -int graphsorterY( kbGraph *, kbGraph * ); - -kbGraphList::kbGraphList( Bool_Engine* GC ) -{ - _GC = GC; -} - -kbGraphList::kbGraphList( kbGraphList* other ) -{ - _GC = other->_GC; - - TDLI _LI = TDLI( other ); - _LI.tohead(); - while ( !_LI.hitroot() ) - { - insend( new kbGraph( _LI.item() ) ); - _LI++; - } -} - -kbGraphList::~kbGraphList() -{ - TDLI _LI = TDLI( this ); - //first empty the graph - _LI.delete_all(); -} - -//prepare the graphlist for the boolean operations -//group all graphs into ONE graph -void kbGraphList::Prepare( kbGraph* total ) -{ - if ( empty() ) - return; - - //round to grid and put in one graph - _GC->SetState( "Simplify" ); - - // Simplify all graphs in the list - Simplify( ( double ) _GC->GetGrid() ); - - if ( ! _GC->GetOrientationEntryMode() ) - { - TDLI _LI = TDLI( this ); - _LI.tohead(); - while ( !_LI.hitroot() ) - { - _LI.item()->MakeClockWise(); - _LI++; - } - } - - Renumber(); - - //the graplist contents will be transferred to one graph - MakeOneGraph( total ); -} - -// the function will make from all the graphs in the graphlist one graph, -// simply by throwing all the links in one graph, the graphnumbers will -// not be changed -void kbGraphList::MakeOneGraph( kbGraph* total ) -{ - TDLI _LI = TDLI( this ); - _LI.tohead(); - while( !_LI.hitroot() ) - { - total->TakeOver( _LI.item() ); - delete _LI.item(); - _LI.remove(); - } -} - -// -// Renumber all the graphs -// -void kbGraphList::Renumber() -{ - if ( _GC->GetOrientationEntryMode() ) - { - TDLI _LI = TDLI( this ); - _LI.tohead(); - while ( !_LI.hitroot() ) - { - if ( _LI.item()->GetFirstLink()->Group() == GROUP_A ) - _LI.item()->SetNumber( 1 ); - else - _LI.item()->SetNumber( 2 ); - _LI++; - } - } - else - { - unsigned int Number = 1; - TDLI _LI = TDLI( this ); - _LI.tohead(); - while ( !_LI.hitroot() ) - { - _LI.item()->SetNumber( Number++ ); - _LI++; - } - } -} - - -// Simplify the graphs -void kbGraphList::Simplify( double marge ) -{ - TDLI _LI = TDLI( this ); - _LI.foreach_mf( &kbGraph::Reset_Mark_and_Bin ); - - _LI.tohead(); - while ( !_LI.hitroot() ) - { - if ( _LI.item()->Simplify( ( B_INT ) marge ) ) - { - if ( _LI.item()->GetNumberOfLinks() < 3 ) - // delete this graph from the graphlist - { - delete _LI.item(); - _LI.remove(); - } - } - else - _LI++; - } -} - -// Smoothen the graphs -void kbGraphList::Smoothen( double marge ) -{ - TDLI _LI = TDLI( this ); - _LI.foreach_mf( &kbGraph::Reset_Mark_and_Bin ); - - _LI.tohead(); - while ( !_LI.hitroot() ) - { - if ( _LI.item()->Smoothen( ( B_INT ) marge ) ) - { - if ( _LI.item()->GetNumberOfLinks() < 3 ) - // delete this graph from the graphlist - { - delete _LI.item(); - _LI.remove(); - } - } - else - _LI++; - } -} - - -// Turn off all markers in all the graphs -void kbGraphList::UnMarkAll() -{ - TDLI _LI = TDLI( this ); - _LI.foreach_mf( &kbGraph::Reset_Mark_and_Bin ); -} - -//============================================================================== -// -//======================== BOOLEAN FUNCTIONS =================================== -// -//============================================================================== - -void kbGraphList::Correction() -{ - TDLI _LI = TDLI( this ); - int todo = _LI.count(); - - if ( _GC->GetInternalCorrectionFactor() ) //not zero - { - _LI.tohead(); - for( int i = 0; i < todo ; i++ ) - { - //the input graph will be empty in the end - kbGraphList *_correct = new kbGraphList( _GC ); - { - _LI.item()->MakeClockWise(); - _LI.item()->Correction( _correct, _GC->GetInternalCorrectionFactor() ); - - delete _LI.item(); - _LI.remove(); - - //move corrected graphlist to result - while ( !_correct->empty() ) - { - //add to end - _LI.insend( ( kbGraph* )_correct->headitem() ); - _correct->removehead(); - } - } - delete _correct; - } - } -} - -void kbGraphList::MakeRings() -{ - TDLI _LI = TDLI( this ); - int todo = _LI.count(); - - _LI.tohead(); - for( int i = 0; i < todo ; i++ ) - { - //the input graph will be empty in the end - kbGraphList *_ring = new kbGraphList( _GC ); - { - _LI.item()->MakeClockWise(); - _LI.item()->MakeRing( _ring, _GC->GetInternalCorrectionFactor() ); - - delete _LI.item(); - _LI.remove(); - - //move created rings graphs to this - while ( !_ring->empty() ) - { - //add to end - ( ( kbGraph* )_ring->headitem() )->MakeClockWise(); - _LI.insend( ( kbGraph* )_ring->headitem() ); - _ring->removehead(); - } - } - delete _ring; - } - -} - -//merge the graphs in the list and return the merged result -void kbGraphList::Merge() -{ - if ( count() <= 1 ) - return; - - { - TDLI _LI = TDLI( this ); - _LI.tohead(); - while ( !_LI.hitroot() ) - { - _LI.item()->SetGroup( GROUP_A ); - _LI++; - } - } - - kbGraph* _tomerge = new kbGraph( _GC ); - - Renumber(); - - //the graplist contents will be transferred to one graph - MakeOneGraph( _tomerge ); - //the original is empty now - - _tomerge->Prepare( 1 ); - _tomerge->Boolean( BOOL_OR, this ); - - delete _tomerge; -} - -#define TRIALS 30 -#define SAVEME 1 - -//perform boolean operation on the graphs in the list -void kbGraphList::Boolean( BOOL_OP operation, int intersectionRunsMax ) -{ - _GC->SetState( "Performing Boolean Operation" ); - - if ( count() == 0 ) - return; - - kbGraph* _prepared = new kbGraph( _GC ); - - if ( empty() ) - return; - - //round to grid and put in one graph - _GC->SetState( "Simplify" ); - - int intersectionruns = 1; - - while ( intersectionruns <= intersectionRunsMax ) - { - try - { - Prepare( _prepared ); - - if ( _prepared->GetNumberOfLinks() ) - { - //calculate intersections etc. - _GC->SetState( "prepare" ); - _prepared->Prepare( intersectionruns ); - //_prepared->writegraph(true); - _prepared->Boolean( operation, this ); - } - intersectionruns = intersectionRunsMax + 1; - } - catch ( Bool_Engine_Error & error ) - { -#if KBOOL_DEBUG - _prepared->WriteGraphKEY( _GC ); -#endif - intersectionruns++; - if ( intersectionruns == intersectionRunsMax ) - { - _prepared->WriteGraphKEY( _GC ); - _GC->info( error.GetErrorMessage(), "error" ); - throw error; - } - } - catch( ... ) - { - -#if KBOOL_DEBUG - _prepared->WriteGraphKEY( _GC ); -#endif - intersectionruns++; - if ( intersectionruns == intersectionRunsMax ) - { - _prepared->WriteGraphKEY( _GC ); - _GC->info( "Unknown exception", "error" ); - throw; - } - } - } - - delete _prepared; -} - - -void kbGraphList::WriteGraphs() -{ - TDLI _LI = TDLI( this ); - _LI.tohead(); - while( !_LI.hitroot() ) - { - _LI.item()->writegraph( false ); - _LI++; - } -} - -void kbGraphList::WriteGraphsKEY( Bool_Engine* GC ) -{ - FILE * file = fopen( "graphkeyfile.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 0.0001; PHYSUNITS 1e-009; \ - \ - BGNSTR; \ - CREATION {2-11-15 15:39:21}; \ - LASTMOD {2-11-15 15:39:21}; \ - STRNAME top; \ - "); - - TDLI _LI=TDLI(this); - _LI.tohead(); - while(!_LI.hitroot()) - { - _LI.item()->WriteKEY( GC, file ); - _LI++; - } - - fprintf(file,"\ - ENDSTR top; \ - ENDLIB; \ - "); - - fclose (file); -} diff --git a/polygon/kbool/src/instonly.cpp b/polygon/kbool/src/instonly.cpp deleted file mode 100644 index 97827c7ce7..0000000000 --- a/polygon/kbool/src/instonly.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/*! \file kbool/src/instonly.cpp - \author Probably Klaas Holwerda - - Copyright: 2001-2004 (C) Probably Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: instonly.cpp,v 1.3 2009/02/06 21:33:03 titato Exp $ -*/ - -#ifdef __GNUG__ -#pragma option -Jgd - -#include "kbool/_dl_itr.h" -#include "kbool/node.h" -#include "kbool/record.h" -#include "kbool/link.h" -#include "kbool/_lnk_itr.h" -#include "kbool/scanbeam.h" -#include "kbool/graph.h" -#include "kbool/graphlst.h" -//#include "kbool/misc.h" - -template class DL_Node; -template class DL_Iter; -template class DL_List; - -template class DL_Node; -template class DL_Iter; -template class DL_List; - -template class TDLI; -template class TDLI; -template class TDLI; -template class TDLI; -template class TDLI; - -#endif diff --git a/polygon/kbool/src/line.cpp b/polygon/kbool/src/line.cpp deleted file mode 100644 index fffe323dc1..0000000000 --- a/polygon/kbool/src/line.cpp +++ /dev/null @@ -1,1479 +0,0 @@ -/*! \file src/line.cpp - \brief Mainly used for calculating crossings - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: line.cpp,v 1.6 2009/09/13 18:34:06 titato Exp $ -*/ - -// Standard include files -#include "kbool/booleng.h" - -// Include files for forward declarations -#include "kbool/link.h" -#include "kbool/node.h" - -// header -#include "kbool/line.h" - -#include "kbool/graph.h" -#include "kbool/graphlst.h" - -// -// The default constructor -// -kbLine::kbLine( Bool_Engine* GC ) -{ - m_GC = GC; - m_AA = 0.0; - m_BB = 0.0; - m_CC = 0.0; - m_link = 0; - linecrosslist = NULL; - m_valid_parameters = false; -} - -kbLine::~kbLine() -{ - if ( linecrosslist ) - delete linecrosslist; -} - -// -// constructor with a link -// -kbLine::kbLine( kbLink *a_link, Bool_Engine* GC ) -{ - m_GC = GC; - // a_link must exist - assert( a_link ); - // points may not be equal - // must be an if statement because if an assert is used there will - // be a macro expansion error - - //if (a_link->GetBeginNode()->Equal(a_link->GetEndNode(), 1)) - // assert(!a_link); - - linecrosslist = NULL; - m_link = a_link; - m_valid_parameters = false; -} - - - -// ActionOnTable1 -// This function decide which action must be taken, after PointInLine -// has given the results of two points in relation to a line. See table 1 in the report -// -// input Result_beginnode: -// Result_endnode : -// The results can be LEFT_SIDE, RIGHT_SIDE, ON_AREA, IN_AREA -// -// return -1: Illegal combination -// 0: No action, no crosspoints -// 1: Investigate results points in relation to the other line -// 2: endnode is a crosspoint, no further investigation -// 3: beginnode is a crosspoint, no further investigation -// 4: beginnode and endnode are crosspoints, no further investigation -// 5: beginnode is a crosspoint, need further investigation -// 6: endnode is a crosspoint, need further investigation -int kbLine::ActionOnTable1( PointStatus Result_beginnode, PointStatus Result_endnode ) -{ - // Action 1.5 beginnode and endnode are crosspoints, no further investigation needed - if ( - ( Result_beginnode == IN_AREA ) - && - ( Result_endnode == IN_AREA ) - ) - return 4; - // Action 1.1, there are no crosspoints, no action - if ( - ( - ( Result_beginnode == LEFT_SIDE ) - && - ( Result_endnode == LEFT_SIDE ) - ) - || - ( - ( Result_beginnode == RIGHT_SIDE ) - && - ( Result_endnode == RIGHT_SIDE ) - ) - ) - return 0; - // Action 1.2, maybe there is a crosspoint, further investigation needed - if ( - ( - ( Result_beginnode == LEFT_SIDE ) - && - ( - ( Result_endnode == RIGHT_SIDE ) - || - ( Result_endnode == ON_AREA ) - ) - ) - || - ( - ( Result_beginnode == RIGHT_SIDE ) - && - ( - ( Result_endnode == LEFT_SIDE ) - || - ( Result_endnode == ON_AREA ) - ) - ) - || - ( - ( Result_beginnode == ON_AREA ) - && - ( - ( Result_endnode == LEFT_SIDE ) - || - ( Result_endnode == RIGHT_SIDE ) - || - ( Result_endnode == ON_AREA ) - ) - ) - ) - return 1; - // Action 1.3, there is a crosspoint, no further investigation - if ( - ( - ( Result_beginnode == LEFT_SIDE ) - || - ( Result_beginnode == RIGHT_SIDE ) - ) - && - ( Result_endnode == IN_AREA ) - ) - return 2; - // Action 1.4 there is a crosspoint, no further investigation - if ( - ( Result_beginnode == IN_AREA ) - && - ( - ( Result_endnode == LEFT_SIDE ) - || - ( Result_endnode == RIGHT_SIDE ) - ) - ) - return 3; - // Action 1.6 beginnode is a crosspoint, further investigation needed - if ( - ( Result_beginnode == IN_AREA ) - && - ( Result_endnode == ON_AREA ) - ) - return 5; - // Action 1.7 endnode is a crosspoint, further investigation needed - if ( - ( Result_beginnode == ON_AREA ) - && - ( Result_endnode == IN_AREA ) - ) - return 6; - // All other combinations are illegal - return -1; -} - - -// ActionOnTable2 -// This function decide which action must be taken, after PointInLine -// has given the results of two points in relation to a line. It can only give a -// correct decision if first the relation of the points from the line -// are investigated in relation to the line wich can be constucted from the points. -// -// input Result_beginnode: -// Result_endnode : -// The results can be LEFT_SIDE, RIGHT_SIDE, ON_AREA, IN_AREA -// -// return -1: Illegal combination -// 0: No action, no crosspoints -// 1: Calculate crosspoint -// 2: endnode is a crosspoint -// 3: beginnode is a crosspoint -// 4: beginnode and endnode are crosspoints -int kbLine::ActionOnTable2( PointStatus Result_beginnode, PointStatus Result_endnode ) -{ - // Action 2.5, beginnode and eindpoint are crosspoints - if ( - ( Result_beginnode == IN_AREA ) - && - ( Result_endnode == IN_AREA ) - ) - return 4; - // Action 2.1, there are no crosspoints - if ( - ( - ( Result_beginnode == LEFT_SIDE ) - && - ( - ( Result_endnode == LEFT_SIDE ) - || - ( Result_endnode == ON_AREA ) - ) - ) - || - ( - ( Result_beginnode == RIGHT_SIDE ) - && - ( - ( Result_endnode == RIGHT_SIDE ) - || - ( Result_endnode == ON_AREA ) - ) - ) - || - ( - ( Result_beginnode == ON_AREA ) - && - ( - ( Result_endnode == LEFT_SIDE ) - || - ( Result_endnode == RIGHT_SIDE ) - || - ( Result_endnode == ON_AREA ) - ) - ) - ) - return 0; - // Action 2.2, there is a real intersection, which must be calculated - if ( - ( - ( Result_beginnode == LEFT_SIDE ) - && - ( Result_endnode == RIGHT_SIDE ) - ) - || - ( - ( Result_beginnode == RIGHT_SIDE ) - && - ( Result_endnode == LEFT_SIDE ) - ) - ) - return 1; - // Action 2.3, endnode is a crosspoint - if ( - ( - ( Result_beginnode == LEFT_SIDE ) - || - ( Result_beginnode == RIGHT_SIDE ) - || - ( Result_beginnode == ON_AREA ) - ) - && - ( Result_endnode == IN_AREA ) - ) - return 2; - // Action 2.4, beginnode is a crosspoint - if ( - ( Result_beginnode == IN_AREA ) - && - ( - ( Result_endnode == LEFT_SIDE ) - || - ( Result_endnode == RIGHT_SIDE ) - || - ( Result_endnode == ON_AREA ) - ) - ) - return 3; - // All other combinations are illegal - return -1; -} - -// -// This fucntion will ad a crossing to this line and the other line -// the crossing will be put in the link, because the line will be destructed -// after use of the variable -// -void kbLine::AddLineCrossing( B_INT X, B_INT Y, kbLine *other_line ) -{ - // the other line must exist - assert( other_line ); - // the links of the lines must exist - assert( other_line->m_link && m_link ); - other_line->AddCrossing( AddCrossing( X, Y ) ); -} - -// Calculate the Y when the X is given -// -B_INT kbLine::Calculate_Y( B_INT X ) -{ - // link must exist to get info about the nodes - assert( m_link ); - - CalculateLineParameters(); - if ( m_AA != 0 ) - { - //vertical line is undefined - assert( m_BB ); - return ( B_INT )( -( m_AA * X + m_CC ) / m_BB ); - } - else - // horizontal line - return m_link->GetBeginNode()->GetY(); -} - -B_INT kbLine::Calculate_Y_from_X( B_INT X ) -{ - // link must exist to get info about the nodes - assert( m_link ); - assert( m_valid_parameters ); - - if ( m_AA != 0 ) - return ( B_INT ) ( ( -( m_AA * X + m_CC ) / m_BB ) + 0.5 ); - else - // horizontal line - return m_link->GetBeginNode()->GetY(); -} - -void kbLine::Virtual_Point( kbLPoint *a_point, double distance ) -{ - // link must exist to get info about the nodes - assert( m_link ); - assert( m_valid_parameters ); - - //calculate the distance using the slope of the line - //and rotate 90 degrees - - a_point->SetY( ( B_INT )( a_point->GetY() + ( distance * -( m_BB ) ) ) ); - a_point->SetX( ( B_INT )( a_point->GetX() - ( distance * m_AA ) ) ); -} - - - -// -// Calculate the lineparameters for the line if nessecary -// -void kbLine::CalculateLineParameters() -{ - // linkmust exist to get beginnode AND endnode - assert( m_link ); - - // if not valid_parameters calculate the parameters - if ( !m_valid_parameters ) - { - kbNode * bp, *ep; - double length; - - // get the begin and endnode via the link - bp = m_link->GetBeginNode(); - ep = m_link->GetEndNode(); - - // bp AND ep may not be the same - if ( bp == ep ) - assert ( bp != ep ); - - m_AA = ( double ) ( ep->GetY() - bp->GetY() ); // A = (Y2-Y1) - m_BB = ( double ) ( bp->GetX() - ep->GetX() ); // B = (X1-X2) - - // the parameters A end B can now be normalized - length = sqrt( m_AA * m_AA + m_BB * m_BB ); - - if( length == 0 ) - m_GC->error( "length = 0", "CalculateLineParameters" ); - - m_AA = ( m_AA / length ); - m_BB = ( m_BB / length ); - - m_CC = -( ( m_AA * bp->GetX() ) + ( bp->GetY() * m_BB ) ); - - m_valid_parameters = true; - } -} - - -// Checks if a line intersect with another line -// inout Line : another line -// Marge: optional, standard on MARGE (declared in MISC.CPP) -// -// return true : lines are crossing -// false: lines are not crossing -// -int kbLine::CheckIntersect ( kbLine * lijn, double Marge ) -{ - double distance = 0; - // link must exist - assert( m_link ); - // lijn must exist - assert( lijn ); - - // points may not be equal - // must be an if statement because if an assert is used there will - // be a macro expansion error - if ( m_link->GetBeginNode() == m_link->GetEndNode() ) - assert( !m_link ); - - int Take_Action1, Take_Action2, Total_Result; - kbNode *bp, *ep; - PointStatus Result_beginnode, Result_endnode; - - bp = lijn->m_link->GetBeginNode(); - ep = lijn->m_link->GetEndNode(); - Result_beginnode = PointInLine( bp, distance, Marge ); - Result_endnode = PointInLine( ep, distance, Marge ); - Take_Action1 = ActionOnTable1( Result_beginnode, Result_endnode ); - switch ( Take_Action1 ) - { - case 0: Total_Result = false ; break; - case 1: - { - bp = m_link->GetBeginNode(); - ep = m_link->GetEndNode(); - Result_beginnode = lijn->PointInLine( bp, distance, Marge ); - Result_endnode = lijn->PointInLine( ep, distance, Marge ); - Take_Action2 = ActionOnTable2( Result_beginnode, Result_endnode ); - switch ( Take_Action2 ) - { - case 0: Total_Result = false; break; - case 1: case 2: case 3: case 4: Total_Result = true; break; - default: Total_Result = false; assert( Total_Result ); - } - } - ; break; // This break belongs to the switch(Take_Action1) - case 2: case 3: case 4: case 5: case 6: Total_Result = true; break; - default: Total_Result = false; assert( Total_Result ); - } - return Total_Result; //This is the final decision -} - - -// -// Get the beginnode from the line -// usage: kbNode *anode = a_line.GetBeginNode() -// -kbNode *kbLine::GetBeginNode() -{ - // link must exist - assert( m_link ); - return m_link->GetBeginNode(); -} - - -// -// Get the endnode from the line -// usage: kbNode *anode = a_line.GetEndNode() -// -kbNode *kbLine::GetEndNode() -{ - // link must exist - assert( m_link ); - return m_link->GetEndNode(); -} - -// Intersects two lines -// input Line : another line -// Marge: optional, standard on MARGE -// -// return 0: If there are no crossings -// 1: If there is one crossing -// 2: If there are two crossings -int kbLine::Intersect( kbLine * lijn, double Marge ) -{ - double distance = 0; - // lijn must exist - assert( lijn ); - - // points may not be equal - // must be an if statement because if an assert is used there will - // be a macro expansion error - if ( m_link->GetBeginNode() == m_link->GetEndNode() ) - assert( !m_link ); - - kbNode *bp, *ep; - PointStatus Result_beginnode, Result_endnode; - int Take_Action1, Take_Action2, Number_of_Crossings = 0; - - // Get the nodes from lijn via the link - bp = lijn->m_link->GetBeginNode(); - ep = lijn->m_link->GetEndNode(); - - Result_beginnode = PointInLine( bp, distance, Marge ); - Result_endnode = PointInLine( ep, distance, Marge ); - - Take_Action1 = ActionOnTable1( Result_beginnode, Result_endnode ); - - // The first switch will insert a crosspoint immediatly - switch ( Take_Action1 ) - { - // for the cases see the returnvalue of ActionTable1 - case 2: case 6: AddCrossing( ep ); - Number_of_Crossings = 1; - break; - case 3: case 5: AddCrossing( bp ); - Number_of_Crossings = 1; - break; - case 4: AddCrossing( bp ); - AddCrossing( ep ); - Number_of_Crossings = 2; - break; - } - // This switch wil investigate the points of this line in relation to lijn - switch ( Take_Action1 ) - { - // for the cases see the returnvalue of ActionTable1 -case 1: case 5: case 6: - { - // Get the nodes from this line via the link - bp = m_link->GetBeginNode(); - ep = m_link->GetEndNode(); - Result_beginnode = lijn->PointInLine( bp, distance, Marge ); - Result_endnode = lijn->PointInLine( ep, distance, Marge ); - Take_Action2 = ActionOnTable2( Result_beginnode, Result_endnode ); - switch ( Take_Action2 ) - { - // for the cases see the returnvalue of ActionTable2 - case 1: - { // begin of scope to calculate the intersection - double X, Y, Denominator; - CalculateLineParameters(); - Denominator = ( m_AA * lijn->m_BB ) - ( lijn->m_AA * m_BB ); - // Denominator may not be 0 - assert( Denominator != 0.0 ); - // Calculate intersection of both linesegments - X = ( ( m_BB * lijn->m_CC ) - ( lijn->m_BB * m_CC ) ) / Denominator; - Y = ( ( lijn->m_AA * m_CC ) - ( m_AA * lijn->m_CC ) ) / Denominator; - - //make a decent rounding to B_INT - AddLineCrossing( ( B_INT )X, ( B_INT )Y, lijn ); - } // end of scope to calculate the intersection - Number_of_Crossings++; - break; - case 2: lijn->AddCrossing( ep ); - Number_of_Crossings++; - break; - case 3: lijn->AddCrossing( bp ); - Number_of_Crossings++; - break; - case 4: lijn->AddCrossing( bp ); - lijn->AddCrossing( ep ); - Number_of_Crossings = 2; - break; - } - } - ; break; // This break belongs to the outer switch - } - return Number_of_Crossings; //This is de final number of crossings -} - - -// Intersects two lines there must be a crossing -int kbLine::Intersect_simple( kbLine * lijn ) -{ - // lijn must exist - assert( lijn ); - - double X, Y, Denominator; - Denominator = ( m_AA * lijn->m_BB ) - ( lijn->m_AA * m_BB ); - // Denominator may not be 0 - if ( Denominator == 0.0 ) - m_GC->error( "colliniar lines", "line" ); - // Calculate intersection of both linesegments - X = ( ( m_BB * lijn->m_CC ) - ( lijn->m_BB * m_CC ) ) / Denominator; - Y = ( ( lijn->m_AA * m_CC ) - ( m_AA * lijn->m_CC ) ) / Denominator; - AddLineCrossing( ( B_INT )X, ( B_INT )Y, lijn ); - - return( 0 ); -} - -// Intersects two lines there must be a crossing -bool kbLine::Intersect2( kbNode* crossing, kbLine * lijn ) -{ - // lijn must exist - assert( lijn ); - - double X, Y, Denominator; - Denominator = ( m_AA * lijn->m_BB ) - ( lijn->m_AA * m_BB ); - // Denominator may not be 0 - if ( Denominator == 0.0 ) - return false; - // Calculate intersection of both linesegments - X = ( ( m_BB * lijn->m_CC ) - ( lijn->m_BB * m_CC ) ) / Denominator; - Y = ( ( lijn->m_AA * m_CC ) - ( m_AA * lijn->m_CC ) ) / Denominator; - - crossing->SetX( ( B_INT )X ); - crossing->SetY( ( B_INT )Y ); - return true; -} - -// -// test if a point lies in the linesegment. If the point isn't on the line -// the function returns a value that indicates on which side of the -// line the point is (in linedirection from first point to second point -// -// returns LEFT_SIDE, when point lies on the left side of the line -// RIGHT_SIDE, when point lies on the right side of the line -// ON_AREA, when point lies on the infinite line within a range -// IN_AREA, when point lies in the area of the linesegment -// the returnvalues are declared in (LINE.H) -PointStatus kbLine::PointInLine( kbNode *a_node, double& Distance, double Marge ) -{ - Distance = 0; - - //Punt must exist - assert( a_node ); - // link must exist to get beginnode and endnode via link - assert( m_link ); - - // get the nodes form the line via the link - kbNode *bp, *ep; - bp = m_link->GetBeginNode(); - ep = m_link->GetEndNode(); - - // both node must exist - assert( bp && ep ); - // node may not be the same - assert( bp != ep ); - - //quick test if point is begin or endpoint - if ( a_node == bp || a_node == ep ) - return IN_AREA; - - int Result_of_BBox = false; - PointStatus Result_of_Online; - - // Checking if point is in bounding-box with marge - B_INT xmin = bmin( bp->GetX(), ep->GetX() ); - B_INT xmax = bmax( bp->GetX(), ep->GetX() ); - B_INT ymin = bmin( bp->GetY(), ep->GetY() ); - B_INT ymax = bmax( bp->GetY(), ep->GetY() ); - - if ( a_node->GetX() >= ( xmin - Marge ) && a_node->GetX() <= ( xmax + Marge ) && - a_node->GetY() >= ( ymin - Marge ) && a_node->GetY() <= ( ymax + Marge ) ) - Result_of_BBox = true; - - // Checking if point is on the infinite line - Result_of_Online = PointOnLine( a_node, Distance, Marge ); - - // point in boundingbox of the line and is on the line then the point is IN_AREA - if ( ( Result_of_BBox ) && ( Result_of_Online == ON_AREA ) ) - return IN_AREA; - else - return Result_of_Online; -} - - -// -// test if a point lies on the line. If the point isn't on the line -// the function returns a value that indicates on which side of the -// line the point is (in linedirection from first point to second point -// -// returns LEFT_SIDE, when point lies on the left side of the line -// ON_AREA, when point lies on the infinite line within a range -// RIGHT_SIDE, when point lies on the right side of the line -// LEFT_SIDE , RIGHT_SIDE , ON_AREA -PointStatus kbLine::PointOnLine( kbNode *a_node, double& Distance, double Marge ) -{ - Distance = 0; - - // a_node must exist - assert( a_node ); - // link must exist to get beginnode and endnode - assert( m_link ); - - // get the nodes from the line via the link - kbNode *bp, *ep; - bp = m_link->GetBeginNode(); - ep = m_link->GetEndNode(); - - // both node must exist - assert( bp && ep ); - // node may not be queal - assert( bp != ep ); - - //quick test if point is begin or endpoint - if ( a_node == bp || a_node == ep ) - return ON_AREA; - - CalculateLineParameters(); - // calculate the distance of a_node in relation to the line - Distance = ( m_AA * a_node->GetX() ) + ( m_BB * a_node->GetY() ) + m_CC; - - if ( Distance < -Marge ) - return LEFT_SIDE; - else - { - if ( Distance > Marge ) - return RIGHT_SIDE; - else - return ON_AREA; - } -} - - -// -// Sets lines parameters -// usage: a_line.Set(a_pointer_to_a_link); -// -void kbLine::Set( kbLink *a_link ) -{ - // points must exist - assert( a_link ); - // points may not be equal - // must be an if statement because if an assert is used there will - // be a macro expansion error -// if (a_link->GetBeginNode()->Equal(a_link->GetEndNode(),MARGE)) assert(!a_link); - - linecrosslist = NULL; - m_link = a_link; - m_valid_parameters = false; -} - -kbLink* kbLine::GetLink() -{ - return m_link; -} -// -// makes a line same as these -// usage : line1 = line2; -// -kbLine& kbLine::operator=( const kbLine& a_line ) -{ - m_AA = a_line.m_AA; - m_BB = a_line.m_BB; - m_CC = a_line.m_CC; - m_link = a_line.m_link; - linecrosslist = NULL; - m_valid_parameters = a_line.m_valid_parameters; - return *this; -} - -kbNode* kbLine::OffsetContour( kbLine* const nextline, kbNode* _last_ins, double factor, kbGraph *shape ) -{ - kbLink * offs_currentlink; - kbLine offs_currentline( m_GC ); - kbLink* offs_nextlink; - kbLine offs_nextline( m_GC ); - kbNode* offs_end; - - kbNode* offs_bgn_next; - kbNode* offs_end_next; - - // make a node from this point - offs_end = new kbNode( GetEndNode(), m_GC ); - Virtual_Point( offs_end, factor ); - offs_currentlink = new kbLink( 0, _last_ins, offs_end, m_GC ); - offs_currentline.Set( offs_currentlink ); - - offs_bgn_next = new kbNode( nextline->m_link->GetBeginNode(), m_GC ); - nextline->Virtual_Point( offs_bgn_next, factor ); - - offs_end_next = new kbNode( nextline->m_link->GetEndNode(), m_GC ); - nextline->Virtual_Point( offs_end_next, factor ); - - offs_nextlink = new kbLink( 0, offs_bgn_next, offs_end_next, m_GC ); - offs_nextline.Set( offs_nextlink ); - - offs_currentline.CalculateLineParameters(); - offs_nextline.CalculateLineParameters(); - offs_currentline.Intersect2( offs_end, &offs_nextline ); - - // make a link between the current and the previous and add this to kbGraph - shape->AddLink( offs_currentlink ); - - delete offs_nextlink; - - return( offs_end ); -} - - -kbNode* kbLine::OffsetContour_rounded( kbLine* const nextline, kbNode* _last_ins, double factor, kbGraph *shape ) -{ - kbLink * offs_currentlink; - kbLine offs_currentline( m_GC ); - kbLink* offs_nextlink; - kbLine offs_nextline( m_GC ); - kbNode* offs_end; - kbNode* medial_axes_point = new kbNode( m_GC ); - kbNode* bu_last_ins = new kbNode( _last_ins, m_GC ); - - kbNode* offs_bgn_next; - kbNode* offs_end_next; - - // make a node from this point - offs_end = new kbNode( GetEndNode(), m_GC ); - - *_last_ins = *GetBeginNode(); - Virtual_Point( _last_ins, factor ); - Virtual_Point( offs_end, factor ); - offs_currentlink = new kbLink( 0, _last_ins, offs_end, m_GC ); - offs_currentline.Set( offs_currentlink ); - - offs_bgn_next = new kbNode( nextline->m_link->GetBeginNode(), m_GC ); - nextline->Virtual_Point( offs_bgn_next, factor ); - - offs_end_next = new kbNode( nextline->m_link->GetEndNode(), m_GC ); - nextline->Virtual_Point( offs_end_next, factor ); - - offs_nextlink = new kbLink( 0, offs_bgn_next, offs_end_next, m_GC ); - offs_nextline.Set( offs_nextlink ); - - offs_currentline.CalculateLineParameters(); - offs_nextline.CalculateLineParameters(); - offs_currentline.Intersect2( medial_axes_point, &offs_nextline ); - - double result_offs = sqrt( pow( ( double )GetEndNode()->GetY() - medial_axes_point->GetY(), 2 ) + - pow( ( double )GetEndNode()->GetX() - medial_axes_point->GetX(), 2 ) ); - - if ( result_offs < fabs( m_GC->GetRoundfactor() * factor ) ) - { - *_last_ins = *bu_last_ins; - *offs_end = *medial_axes_point; - delete medial_axes_point; - delete bu_last_ins; - // make a link between the current and the previous and add this to kbGraph - delete offs_nextlink; - shape->AddLink( offs_currentlink ); - return( offs_end ); - } - else - { //let us create a circle - *_last_ins = *bu_last_ins; - delete medial_axes_point; - delete bu_last_ins; - kbNode* endarc = new kbNode( offs_bgn_next, m_GC ); - shape->AddLink( offs_currentlink ); - delete offs_nextlink; - shape->CreateArc( GetEndNode(), &offs_currentline, endarc, fabs( factor ), m_GC->GetInternalCorrectionAber() ); - return( endarc ); - } -} - - -bool kbLine::OkeForContour( kbLine* const nextline, double factor, kbNode* LastLeft, kbNode* LastRight, LinkStatus& _outproduct ) -{ - assert( m_link ); - assert( m_valid_parameters ); - assert( nextline->m_link ); - assert( nextline->m_valid_parameters ); - - factor = fabs( factor ); - -// PointStatus status=ON_AREA; - double distance = 0; - - kbNode offs_end_next( nextline->m_link->GetEndNode(), m_GC ); - - _outproduct = m_link->OutProduct( nextline->m_link, m_GC->GetAccur() ); - - switch ( _outproduct ) - { - // current line lies on leftside of prev line - case IS_RIGHT : - { - nextline->Virtual_Point( &offs_end_next, -factor ); - - // status= - nextline->PointOnLine( LastRight, distance, m_GC->GetAccur() ); - if ( distance > factor ) - { - PointOnLine( &offs_end_next, distance, m_GC->GetAccur() ); - if ( distance > factor ) - return( true ); - } - } - break; - // current line lies on rightside of prev line - case IS_LEFT : - { - nextline->Virtual_Point( &offs_end_next, factor ); - - // status= - nextline->PointOnLine( LastLeft, distance, m_GC->GetAccur() ); - if ( distance < -factor ) - { - PointOnLine( &offs_end_next, distance, m_GC->GetAccur() ); - if ( distance < -factor ) - return( true ); - } - } - break; - // current line lies on prev line - case IS_ON : - { - return( true ); - } - }//end switch - - return( false ); -} - - -bool kbLine::Create_Ring_Shape( kbLine* nextline, kbNode** _last_ins_left, kbNode** _last_ins_right, double factor, kbGraph *shape ) -{ - kbNode * _current; - LinkStatus _outproduct = IS_ON; - - if ( OkeForContour( nextline, factor, *_last_ins_left, *_last_ins_right, _outproduct ) ) - { - switch ( _outproduct ) - { - // Line 2 lies on leftside of this line - case IS_RIGHT : - { - *_last_ins_left = OffsetContour_rounded( nextline, *_last_ins_left, factor, shape ); - *_last_ins_right = OffsetContour( nextline, *_last_ins_right, -factor, shape ); - } - break; - case IS_LEFT : - { - *_last_ins_left = OffsetContour( nextline, *_last_ins_left, factor, shape ); - *_last_ins_right = OffsetContour_rounded( nextline, *_last_ins_right, -factor, shape ); - - } - break; - // Line 2 lies on this line - case IS_ON : - { - // make a node from this point - _current = new kbNode( m_link->GetEndNode(), m_GC ); - Virtual_Point( _current, factor ); - - // make a link between the current and the previous and add this to kbGraph - shape->AddLink( *_last_ins_left, _current ); - *_last_ins_left = _current; - - _current = new kbNode( m_link->GetEndNode(), m_GC ); - Virtual_Point( _current, -factor ); - - shape->AddLink( *_last_ins_right, _current ); - *_last_ins_right = _current; - } - break; - }//end switch - return( true ); - } - /* else - { - switch (_outproduct) - { - // Line 2 lies on leftside of this line - case IS_RIGHT : - { - *_last_ins_left =OffsetContour_rounded(nextline,*_last_ins_left,factor,Ishape); - *_last_ins_right =OffsetContour(nextline,*_last_ins_right,-factor,Ishape); - } - break; - case IS_LEFT : - { - *_last_ins_left =OffsetContour(nextline,*_last_ins_left,factor,Ishape); - *_last_ins_right =OffsetContour_rounded(nextline,*_last_ins_right,-factor,Ishape); - - } - break; - // Line 2 lies on this line - case IS_ON : - { - // make a node from this point - _current = new kbNode(m_link->GetEndNode()); - Virtual_Point(_current,factor); - - // make a link between the current and the previous and add this to kbGraph - Ishape->AddLink(*_last_ins_left, _current); - *_last_ins_left=_current; - - _current = new kbNode(m_link->GetEndNode()); - Virtual_Point(_current,-factor); - - Ishape->AddLink(*_last_ins_right, _current); - *_last_ins_right=_current; - } - break; - }//end switch - return(true); - } - */ - return( false ); -} - - -void kbLine::Create_Begin_Shape( kbLine* nextline, kbNode** _last_ins_left, kbNode** _last_ins_right, double factor, kbGraph *shape ) -{ - factor = fabs( factor ); - LinkStatus _outproduct; - _outproduct = m_link->OutProduct( nextline->m_link, m_GC->GetAccur() ); - - switch ( _outproduct ) - { - case IS_RIGHT : - { - *_last_ins_left = new kbNode( m_link->GetEndNode(), m_GC ); - - Virtual_Point( *_last_ins_left, factor ); - - *_last_ins_right = new kbNode( nextline->m_link->GetBeginNode(), m_GC ); - nextline->Virtual_Point( *_last_ins_right, -factor ); - - shape->AddLink( *_last_ins_left, *_last_ins_right ); - - *_last_ins_left = OffsetContour_rounded( nextline, *_last_ins_left, factor, shape ); - } - break; - case IS_LEFT : - { - *_last_ins_left = new kbNode( nextline->m_link->GetBeginNode(), m_GC ); - nextline->Virtual_Point( *_last_ins_left, factor ); - - *_last_ins_right = new kbNode( m_link->GetEndNode(), m_GC ); - Virtual_Point( *_last_ins_right, -factor ); - - shape->AddLink( *_last_ins_left, *_last_ins_right ); - - *_last_ins_right = OffsetContour_rounded( nextline, *_last_ins_right, -factor, shape ); - } - break; - // Line 2 lies on this line - case IS_ON : - { - *_last_ins_left = new kbNode( nextline->m_link->GetBeginNode(), m_GC ); - Virtual_Point( *_last_ins_left, factor ); - - *_last_ins_right = new kbNode( nextline->m_link->GetBeginNode(), m_GC ); - Virtual_Point( *_last_ins_right, -factor ); - - shape->AddLink( *_last_ins_left, *_last_ins_right ); - } - break; - }//end switch - -} - -void kbLine::Create_End_Shape( kbLine* nextline, kbNode* _last_ins_left, kbNode* _last_ins_right, double factor, kbGraph *shape ) -{ - kbNode * _current; - factor = fabs( factor ); - LinkStatus _outproduct; - _outproduct = m_link->OutProduct( nextline->m_link, m_GC->GetAccur() ); - - switch ( _outproduct ) - { - case IS_RIGHT : - { - _current = new kbNode( m_link->GetEndNode(), m_GC ); - Virtual_Point( _current, -factor ); - shape->AddLink( _last_ins_right, _current ); - _last_ins_right = _current; - - _last_ins_left = OffsetContour_rounded( nextline, _last_ins_left, factor, shape ); - shape->AddLink( _last_ins_left, _last_ins_right ); - } - break; - case IS_LEFT : - { - _current = new kbNode( m_link->GetEndNode(), m_GC ); - Virtual_Point( _current, factor ); - shape->AddLink( _last_ins_left, _current ); - _last_ins_left = _current; - - _last_ins_right = OffsetContour_rounded( nextline, _last_ins_right, -factor, shape ); - shape->AddLink( _last_ins_right, _last_ins_left ); - } - break; - // Line 2 lies on this line - case IS_ON : - { - _current = new kbNode( m_link->GetEndNode(), m_GC ); - Virtual_Point( _current, factor ); - shape->AddLink( _last_ins_left, _current ); - _last_ins_left = _current; - - _current = new kbNode( m_link->GetEndNode(), m_GC ); - Virtual_Point( _current, -factor ); - shape->AddLink( _last_ins_right, _current ); - _last_ins_right = _current; - - shape->AddLink( _last_ins_left, _last_ins_right ); - } - break; - }//end switch - -} - -// -// Generate from the found crossings a part of the kbGraph -// -bool kbLine::ProcessCrossings( TDLI* _LI ) -{ - kbNode * last; kbLink *dummy; -// assert (beginnode && endnode); - - if ( !linecrosslist ) return false; - - if ( linecrosslist->empty() ) return false; - if ( linecrosslist->count() > 1 ) SortLineCrossings(); - m_link->GetEndNode()->RemoveLink( m_link ); - last = m_link->GetEndNode(); - // Make new links : - while ( !linecrosslist->empty() ) - { - dummy = new kbLink( m_link->GetGraphNum(), ( kbNode* ) linecrosslist->tailitem(), last, m_GC ); - dummy->SetBeenHere(); - dummy->SetGroup( m_link->Group() ); - _LI->insbegin( dummy ); - last = ( kbNode* )linecrosslist->tailitem(); - linecrosslist->removetail(); - } - // Recycle this link : - last->AddLink( m_link ); - m_link->SetEndNode( last ); - delete linecrosslist; - linecrosslist = NULL; - return true; -} - -/* -// Sorts the links on the X values -int NodeXYsorter(kbNode* a, kbNode* b) -{ - if ( a->GetX() < b->GetX()) - return(1); - if ( a->GetX() > b->GetX()) - return(-1); - //they are eqaul in x - if ( a->GetY() < b->GetY()) - return(-1); - if ( a->GetY() > b->GetY()) - return(1); - //they are eqaul in y - return(0); -} - -// -// Generate from the found crossings a part of the graph -// this routine is used in combination with the scanbeam class -// the this link most stay at the same place in the sorted graph -// The link is split into peaces wich are inserted sorted into the graph -// on beginnode. -// The mostleft link most become the new link for the beam record -// therefore the mostleft new/old link is returned to become the beam record link -// also the part returned needs to have the bin flag set to the original value it had in the beam -kbLink* kbLine::ProcessCrossingsSmart(TDLI* _LI) -{ - kbNode *lastinserted; - kbLink *new_link; - kbLink *returnlink; - assert (beginnode && endnode); - if (!linecrosslist) return this; - - if (linecrosslist->empty()) return this; - if (linecrosslist->count()>1) - { - SortLineCrossings(); - } - int inbeam; - - //most left at the beginnode or endnode - if (NodeXYsorter(beginnode,endnode)==1) - { - //re_use this link - endnode->RemoveLink(this); - linecrosslist->insend(endnode); //the last link to create is towards this node - endnode=(kbNode*) linecrosslist->headitem(); - endnode->AddLink(this); - inbeam=NodeXYsorter(_LI->item()->beginnode,beginnode); - switch (inbeam) - { - case -1: - case 0: - bin=true; - break; - case 1: - bin=false; - break; - } - returnlink=this; - - lastinserted=endnode; - linecrosslist->removehead(); - // Make new links starting at endnode - while (!linecrosslist->empty()) - { - new_link=new kbLink(graphnum,lastinserted,(kbNode*) linecrosslist->headitem()); - - new_link->group=group; - int inbeam=NodeXYsorter(_LI->item()->beginnode,lastinserted); - switch (inbeam) - { - case -1: - { - double x,y,xl,yl; - char buf[80]; - x=((kbNode*)(linecrosslist->headitem()))->GetX(); - y=((kbNode*)(linecrosslist->headitem()))->GetY(); - xl=_LI->item()->beginnode->GetX(); - yl=_LI->item()->beginnode->GetY(); - sprintf(buf," x=%f , y=%f inserted before %f,%f",x,y,xl,yl); - _messagehandler->info(buf,"scanbeam"); - new_link->bin=true; - } - break; - case 0: - new_link->bin=true; - returnlink=new_link; - break; - case 1: - new_link->bin=false; - break; - } - - //insert a link into the graph that is already sorted on beginnodes of the links. - //starting at a given position - // if empty then just insert - - if (_LI->empty()) - _LI->insend(new_link); - else - { - // put new item left of the one that is bigger are equal - int i=0; - int insert=0; - while(!_LI->hitroot()) - { - if ((insert=linkXYsorter(new_link,_LI->item()))!=-1) - break; - (*_LI)++; - i++; - } - - _LI->insbefore_unsave(new_link); - if (insert==0 && _LI->item()->beginnode!=new_link->beginnode) - //the begin nodes are equal but not the same merge them into one node - { kbNode* todelete=_LI->item()->beginnode; - new_link->beginnode->Merge(todelete); - delete todelete; - } - - //set back iter - (*_LI) << (i+1); - } - - lastinserted=(kbNode*)linecrosslist->headitem(); - linecrosslist->removehead(); - } - } - else - { - //re_use this link - endnode->RemoveLink(this); - linecrosslist->insend(endnode); //the last link to create is towards this node - endnode=(kbNode*) linecrosslist->headitem(); - endnode->AddLink(this); - inbeam=NodeXYsorter(_LI->item()->beginnode,endnode); - switch (inbeam) - { - case -1: - case 0: - bin=true; - break; - case 1: - bin=false; - break; - } - returnlink=this; - - lastinserted=endnode; - linecrosslist->removehead(); - - // Make new links starting at endnode - while (!linecrosslist->empty()) - { - new_link=new kbLink(graphnum,lastinserted,(kbNode*) linecrosslist->headitem()); - new_link->group=group; - - inbeam=NodeXYsorter(_LI->item()->beginnode,(kbNode*) linecrosslist->headitem()); - switch (inbeam) - { - case -1: - case 0: - new_link->bin=true; - break; - case 1: - new_link->bin=false; - break; - } - inbeam=NodeXYsorter(_LI->item()->beginnode,lastinserted); - switch (inbeam) - { - case -1: - { - double x,y,xl,yl; - char buf[80]; - x=lastinserted->GetX(); - y=lastinserted->GetY(); - xl=_LI->item()->beginnode->GetX(); - yl=_LI->item()->beginnode->GetY(); - sprintf(buf," x=%f , y=%f inserted before %f,%f",x,y,xl,yl); - _messagehandler->info(buf,"scanbeam"); - } - break; - case 0: - break; - case 1: - returnlink=new_link; - break; - } - - //insert a link into the graph that is already sorted on beginnodes of the links. - //starting at a given position - // if empty then just insert - - if (_LI->empty()) - _LI->insend(new_link); - else - { - // put new item left of the one that is bigger are equal - int i=0; - int insert=0; - while(!_LI->hitroot()) - { - if ((insert=linkXYsorter(new_link,_LI->item()))!=-1) - break; - (*_LI)++; - i++; - } - - _LI->insbefore_unsave(new_link); - if (insert==0 && _LI->item()->beginnode!=new_link->beginnode) - //the begin nodes are equal but not the same merge them into one node - { kbNode* todelete=_LI->item()->beginnode; - new_link->beginnode->Merge(todelete); - delete todelete; - } - //set back iter - (*_LI) << (i+1); - } - - lastinserted=(kbNode*)linecrosslist->headitem(); - linecrosslist->removehead(); - } - } - delete linecrosslist; - linecrosslist=NULL; - - return returnlink; -} -*/ - -static int NODE_X_ASCENDING_L ( kbNode* a, kbNode* b ) -{ - if( b->GetX() > a->GetX() ) return( 1 ); - else - if( b->GetX() == a->GetX() ) return( 0 ); - - return( -1 ); -} - -static int NODE_X_DESCENDING_L( kbNode* a, kbNode* b ) -{ - if( a->GetX() > b->GetX() ) return( 1 ); - else - if( a->GetX() == b->GetX() ) return( 0 ); - - return( -1 ); -} - -static int NODE_Y_ASCENDING_L ( kbNode* a, kbNode* b ) -{ - if( b->GetY() > a->GetY() ) return( 1 ); - else - if( b->GetY() == a->GetY() ) return( 0 ); - return( -1 ); -} - -static int NODE_Y_DESCENDING_L( kbNode* a, kbNode* b ) -{ - if( a->GetY() > b->GetY() ) return( 1 ); - else - if( a->GetY() == b->GetY() ) return( 0 ); - - return( -1 ); -} - -// -// This function finds out which sortfunction to use with sorting -// the crossings. -// -void kbLine::SortLineCrossings() -{ - TDLI I( linecrosslist ); - - B_INT dx, dy; - dx = babs( m_link->GetEndNode()->GetX() - m_link->GetBeginNode()->GetX() ); - dy = babs( m_link->GetEndNode()->GetY() - m_link->GetBeginNode()->GetY() ); - if ( dx > dy ) - { // thislink is more horizontal then vertical - if ( m_link->GetEndNode()->GetX() > m_link->GetBeginNode()->GetX() ) - I.mergesort( NODE_X_ASCENDING_L ); - else - I.mergesort( NODE_X_DESCENDING_L ); - } - else - { // this link is more vertical then horizontal - if ( m_link->GetEndNode()->GetY() > m_link->GetBeginNode()->GetY() ) - I.mergesort( NODE_Y_ASCENDING_L ); - else - I.mergesort( NODE_Y_DESCENDING_L ); - } -} - -// -// Adds a cross Node to this. a_node may not be deleted before processing the crossings -// -void kbLine::AddCrossing( kbNode *a_node ) -{ - if ( a_node == m_link->GetBeginNode() || a_node == m_link->GetEndNode() ) return; - - - if ( !linecrosslist ) - { - linecrosslist = new DL_List(); - linecrosslist->insend( a_node ); - } - else - { - TDLI I( linecrosslist ); - if ( !I.has( a_node ) ) - I.insend( a_node ); - } -} - -// -// see above -// -kbNode* kbLine::AddCrossing( B_INT X, B_INT Y ) -{ - kbNode * result = new kbNode( X, Y, m_GC ); - AddCrossing( result ); - return result; -} - -DL_List* kbLine::GetCrossList() -{ - if ( linecrosslist ) - return linecrosslist; - return NULL; -} - -bool kbLine::CrossListEmpty() -{ - if ( linecrosslist ) - return linecrosslist->empty(); - return true; -} - -/* -bool kbLine::HasInCrossList(kbNode *n) -{ - if(linecrosslist!=NULL) - { - TDLI I(linecrosslist); - return I.has(n); - } - return false; -} -*/ - diff --git a/polygon/kbool/src/link.cpp b/polygon/kbool/src/link.cpp deleted file mode 100644 index a8f24c3fe6..0000000000 --- a/polygon/kbool/src/link.cpp +++ /dev/null @@ -1,721 +0,0 @@ -/*! \file src/link.cpp - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: link.cpp,v 1.4 2009/09/07 19:23:28 titato Exp $ -*/ - -#include "kbool/booleng.h" - -#include "kbool/link.h" -#include "kbool/line.h" -#include -#include - -#include "kbool/node.h" -#include "kbool/graph.h" -#include "kbool/graphlst.h" - -int linkXYsorter( kbLink *, kbLink * ); - -// -// Default constructor -// -kbLink::kbLink( Bool_Engine* GC ) -{ - _GC = GC; - Reset(); -} - - -// -// This constructor makes this link a valid part of a graph -// -kbLink::kbLink( int graphnr, kbNode *begin, kbNode *end, Bool_Engine* GC ) -{ - _GC = GC; - Reset(); - - // Set the references of the node and of this link correct - begin->AddLink( this ); - end->AddLink( this ); - m_beginnode = begin; - m_endnode = end; - m_graphnum = graphnr; -} - -// -// This constructor makes this link a valid part of a graph -// -kbLink::kbLink( kbNode *begin, kbNode *end, Bool_Engine* GC ) -{ - _GC = GC; - Reset(); - - // Set the references of the node and of this link correct - begin->AddLink( this ); - end->AddLink( this ); - m_beginnode = begin; - m_endnode = end; - m_graphnum = 0; -} - - -// -// Destructor -// -kbLink::~kbLink() -{ - UnLink(); -} - -// -// Checks whether the current algorithm has been on this link -// -bool kbLink::BeenHere() -{ - if ( m_bin ) return true; - return false; -} - -void kbLink::TakeOverOperationFlags( kbLink* link ) -{ - m_merge_L = link->m_merge_L; - m_a_substract_b_L = link->m_a_substract_b_L; - m_b_substract_a_L = link->m_b_substract_a_L; - m_intersect_L = link->m_intersect_L; - m_exor_L = link->m_exor_L; - - m_merge_R = link->m_merge_R; - m_a_substract_b_R = link->m_a_substract_b_R; - m_b_substract_a_R = link->m_b_substract_a_R; - m_intersect_R = link->m_intersect_R; - m_exor_R = link->m_exor_R; -} -// -// Returns the next link from the argument -// -kbLink* kbLink::Forth( kbNode *node ) -{ - assert( node == m_beginnode || node == m_endnode ); - return node->GetOtherLink( this ); -} - -// -// Returns the Beginnode -// -kbNode *kbLink::GetBeginNode() -{ - return m_beginnode; -} - -// -// Returns the endnode -// -kbNode* kbLink::GetEndNode() -{ - return m_endnode; -} - -kbNode* kbLink::GetLowNode() -{ - return ( ( m_beginnode->GetY() < m_endnode->GetY() ) ? m_beginnode : m_endnode ); -} - -kbNode* kbLink::GetHighNode() -{ - return ( ( m_beginnode->GetY() > m_endnode->GetY() ) ? m_beginnode : m_endnode ); -} - -// -// Returns the graphnumber -// -int kbLink::GetGraphNum() -{ - return m_graphnum; -} - -bool kbLink::GetInc() -{ - return m_Inc; -// if (Inc) return true; -// return false; -} - -void kbLink::SetInc( bool inc ) -{ - m_Inc = inc; -// Inc=0; -// if (inc) Inc=1; -} - -bool kbLink::GetLeftA() -{ - return m_LeftA; -} - -void kbLink::SetLeftA( bool la ) -{ - m_LeftA = la; -} - -bool kbLink::GetLeftB() -{ - return m_LeftB; -} - -void kbLink::SetLeftB( bool lb ) -{ - m_LeftB = lb; -} - -bool kbLink::GetRightA() -{ - return m_RightA; -} - -void kbLink::SetRightA( bool ra ) -{ - m_RightA = ra; -} - -bool kbLink::GetRightB() -{ - return m_RightB; -} - -void kbLink::SetRightB( bool rb ) -{ - m_RightB = rb; -} - -// -// This function is very popular by GP-faults -// It returns the node different from a -// -kbNode* kbLink::GetOther( const kbNode *const a ) -{ - return ( ( a != m_beginnode ) ? m_beginnode : m_endnode ); -} - - -// -// Is this marked for given operation -// -bool kbLink::IsMarked( BOOL_OP operation ) -{ - switch ( operation ) - { - case( BOOL_OR ): return m_merge_L || m_merge_R; - case( BOOL_AND ): return m_intersect_L || m_intersect_R; - case( BOOL_A_SUB_B ): return m_a_substract_b_L || m_a_substract_b_R; - case( BOOL_B_SUB_A ): return m_b_substract_a_L || m_b_substract_a_R; - case( BOOL_EXOR ): return m_exor_L || m_exor_R; - default: return false; - } -} - -bool kbLink::IsMarkedLeft( BOOL_OP operation ) -{ - switch ( operation ) - { - case( BOOL_OR ): return m_merge_L; - case( BOOL_AND ): return m_intersect_L; - case( BOOL_A_SUB_B ): return m_a_substract_b_L; - case( BOOL_B_SUB_A ): return m_b_substract_a_L; - case( BOOL_EXOR ): return m_exor_L; - default: return false; - } -} - -bool kbLink::IsMarkedRight( BOOL_OP operation ) -{ - switch ( operation ) - { - case( BOOL_OR ): return m_merge_R; - case( BOOL_AND ): return m_intersect_R; - case( BOOL_A_SUB_B ): return m_a_substract_b_R; - case( BOOL_B_SUB_A ): return m_b_substract_a_R; - case( BOOL_EXOR ): return m_exor_R; - default: return false; - } -} - -// -// Is this a hole for given operation -// beginnode must be to the left -bool kbLink::IsHole( BOOL_OP operation ) -{ - - bool topsideA, topsideB; - - if ( m_beginnode->GetX() < m_endnode->GetX() ) //going to the right? - { topsideA = m_RightA; topsideB = m_RightB; } - else - { topsideA = m_LeftA; topsideB = m_LeftB; } - - switch ( operation ) - { - case( BOOL_OR ): return ( !topsideB && !topsideA ); - case( BOOL_AND ): return ( !topsideB || !topsideA ); - case( BOOL_A_SUB_B ): return ( topsideB || !topsideA ); - case( BOOL_B_SUB_A ): return ( topsideA || !topsideB ); - case( BOOL_EXOR ): return !( ( topsideB && !topsideA ) || ( !topsideB && topsideA ) ); - default: return false; - } -} - -// -// Is this a part of a hole -// -bool kbLink::GetHole() -{ - return ( m_hole ); -} - - -void kbLink::SetHole( bool h ) -{ - m_hole = h; -} - - -// -// Is this not marked at all -// -bool kbLink::IsUnused() -{ - return - !( m_merge_L || m_merge_R || - m_a_substract_b_L || m_a_substract_b_R || - m_b_substract_a_L || m_b_substract_a_R || - m_intersect_L || m_intersect_R || - m_exor_L || m_exor_R ); -} - - -bool kbLink::IsZero( B_INT marge ) -{ - return ( m_beginnode->Equal( m_endnode, marge ) ) ; -} - - -bool kbLink::ShorterThan( B_INT marge ) -{ - return ( m_beginnode->ShorterThan( m_endnode, marge ) ) ; -} - - -// -// Mark this link -// -void kbLink::Mark() -{ - m_mark = true; -} - - -#ifndef ABS -#define ABS(a) (((a)<0) ? -(a) : (a)) -#endif - - -// -// This makes from the begin and endnode one node (argument begin_or_end_node) -// The references to this link in the node will also be deleted -// After doing that, link link can be deleted or be recycled. -// -void kbLink::MergeNodes( kbNode *const begin_or_end_node ) -{ -// assert(beginnode && endnode); -// assert ((begin_or_end_node == beginnode)||(begin_or_end_node == endnode)); - - m_beginnode->RemoveLink( this ); - m_endnode->RemoveLink( this ); - - if ( m_endnode != m_beginnode ) - { // only if beginnode and endnode are different nodes - begin_or_end_node->Merge( GetOther( begin_or_end_node ) ); - } - m_endnode = NULL; - m_beginnode = NULL; -} - -// -// Return the position of the second link compared to this link -// Result = IS_ON | IS_LEFT | IS_RIGHT -// Here Left and Right is defined as being left or right from -// the this link towards the center (common) node -// -LinkStatus kbLink::OutProduct( kbLink* const two, double accur ) -{ - kbNode * center; - double distance; - if ( two->GetBeginNode()->Equal( two->GetEndNode(), 1 ) ) - assert( !two ); - if ( GetBeginNode()->Equal( GetEndNode(), 1 ) ) - assert( !this ); - kbLine* temp_line = new kbLine( this, _GC ); - - //the this link should connect to the other two link at at least one node - if ( m_endnode == two->m_endnode || m_endnode == two->m_beginnode ) - center = m_endnode; - else - { - center = m_beginnode; -// assert(center==two->endnode || center==two->beginnode); - } - - //here something tricky - // the factor 10000.0 is needed to asure that the pointonline - // is more accurate in this case compared to the intersection for graphs - int uitp = temp_line->PointOnLine( two->GetOther( center ), distance, accur ); - - delete temp_line; - - /*double uitp= (_x - first._x) * (third._y - _y) - - (_y - first._y) * (third._x - _x); - if (uitp>0) return IS_LEFT; - if (uitp<0) return IS_RIGHT; - return IS_ON;*/ - - //depending on direction of this link (going to or coming from centre) - if ( center == m_endnode ) - { - if ( uitp == LEFT_SIDE ) - return IS_LEFT; - if ( uitp == RIGHT_SIDE ) - return IS_RIGHT; - } - else //center=beginnode - { - if ( uitp == LEFT_SIDE ) - return IS_RIGHT; - if ( uitp == RIGHT_SIDE ) - return IS_LEFT; - } - return IS_ON; -} - -// -// Return the position of the third link compared to this link and -// the second link -// Result = IS_ON | IS_LEFT | IS_RIGHT -// -LinkStatus kbLink::PointOnCorner( kbLink* const two, kbLink* const third ) -{ - LinkStatus - TwoToOne, // Position of two to this line - ThirdToOne, // Position of third to this line - ThirdToTwo, // Position of third to two - Result; - -//m kbNode* center; - -//the this link should connect to the other two link at at least one node -//m if (endnode==two->endnode || endnode==two->beginnode) -//m center=endnode; -//m else -//m { center=beginnode; -// assert(center==two->endnode || center==two->beginnode); -//m } -// assert(center==third->endnode || center==third->beginnode); - - - - // Calculate the position of the links compared to eachother - TwoToOne = OutProduct( two, _GC->GetAccur() ); - ThirdToOne = OutProduct( third, _GC->GetAccur() ); - //center is used in outproduct to give de direction of two - // this is why the result should be swapped - ThirdToTwo = two->OutProduct( third, _GC->GetAccur() ); - if ( ThirdToTwo == IS_RIGHT ) - ThirdToTwo = IS_LEFT; - else if ( ThirdToTwo == IS_LEFT ) - ThirdToTwo = IS_RIGHT; - - // Select the result - switch( TwoToOne ) - { - // Line 2 lies on leftside of this line - case IS_LEFT : if ( ( ThirdToOne == IS_RIGHT ) || ( ThirdToTwo == IS_RIGHT ) ) return IS_RIGHT; - else if ( ( ThirdToOne == IS_LEFT ) && ( ThirdToTwo == IS_LEFT ) ) return IS_LEFT; - else Result = IS_ON; break; - // Line 2 lies on this line - case IS_ON : if ( ( ThirdToOne == IS_RIGHT ) && ( ThirdToTwo == IS_RIGHT ) ) return IS_RIGHT; - else if ( ( ThirdToOne == IS_LEFT ) && ( ThirdToTwo == IS_LEFT ) ) return IS_LEFT; - // else if ((ThirdToOne==IS_RIGHT) && (ThirdToTwo==IS_LEFT)) return IS_RIGHT; - // else if ((ThirdToOne==IS_LEFT) && (ThirdToTwo==IS_RIGHT)) return IS_LEFT; - else Result = IS_ON; break; - // Line 2 lies on right side of this line - case IS_RIGHT : if ( ( ThirdToOne == IS_RIGHT ) && ( ThirdToTwo == IS_RIGHT ) ) return IS_RIGHT; - else if ( ( ThirdToOne == IS_LEFT ) || ( ThirdToTwo == IS_LEFT ) ) return IS_LEFT; - else Result = IS_ON; break; - default: Result = IS_ON; assert( false ); - } - return Result; -} - -// -// Remove the reference from this link to a_node -// -void kbLink::Remove( kbNode *a_node ) -{ - ( m_beginnode == a_node ) ? m_beginnode = NULL : m_endnode = NULL; -} - - -// -// Replace oldnode by newnode and correct the references -// -void kbLink::Replace( kbNode *oldnode, kbNode *newnode ) -{ - if ( m_beginnode == oldnode ) - { - m_beginnode->RemoveLink( this ); // remove the reference to this - newnode->AddLink( this ); // let newnode refer to this - m_beginnode = newnode; // let this refer to newnode - } - else - { //assert(endnode==oldnode); - m_endnode->RemoveLink( this ); - newnode->AddLink( this ); - m_endnode = newnode; - } -} - - -// -// Reset all values -// -void kbLink::Reset() -{ - m_beginnode = 0; - m_endnode = 0; - Reset_flags(); -} - - -// -// Reset all flags -// -void kbLink::Reset_flags() -{ - m_bin = false; // Marker for walking over the graph - m_hole = false; // Is this a part of hole ? - m_hole_top = false; // link that is toplink of hole? - m_group = GROUP_A; // Does this belong to group A or B ( o.a. for boolean operations between graphs) - m_LeftA = false; // Is left in polygongroup A - m_RightA = false; // Is right in polygon group A - m_LeftB = false; // Is left in polygon group B - m_RightB = false; // Is right in polygongroup B - m_mark = false; // General purose marker, internally unused - m_holelink = false; - - m_merge_L = m_merge_R = false; // Marker for Merge - m_a_substract_b_L = m_a_substract_b_R = false; // Marker for substract - m_b_substract_a_L = m_b_substract_a_R = false; // Marker for substract - m_intersect_L = m_intersect_R = false; // Marker for intersect - m_exor_L = m_exor_R = false; // Marker for Exor -} - -// -// Refill this link by the arguments -// -void kbLink::Reset( kbNode *begin, kbNode *end, int graphnr ) -{ - // Remove all the previous references - UnLink(); - Reset(); - // Set the references of the node and of this link correct - begin->AddLink( this ); - end->AddLink( this ); - m_beginnode = begin; - m_endnode = end; - if ( graphnr != 0 ) - m_graphnum = graphnr; -} - - -void kbLink::Set( kbNode *begin, kbNode *end ) -{ - m_beginnode = begin; - m_endnode = end; -} - -void kbLink::SetBeenHere() -{ - m_bin = true; -} - -void kbLink::SetNotBeenHere() -{ - m_bin = false; -} - -void kbLink::SetBeginNode( kbNode* new_node ) -{ - m_beginnode = new_node; -} - - -void kbLink::SetEndNode( kbNode* new_node ) -{ - m_endnode = new_node; -} - - -// -// Sets the graphnumber to argument num -// -void kbLink::SetGraphNum( int num ) -{ - m_graphnum = num; -} - -GroupType kbLink::Group() -{ - return m_group; -} - - -// -// Reset the groupflag to argument groep -// -void kbLink::SetGroup( GroupType groep ) -{ - m_group = groep; -} - - -// -// Remove all references to this link and from this link -// -void kbLink::UnLink() -{ - if ( m_beginnode ) - { - m_beginnode->RemoveLink( this ); - if ( !m_beginnode->GetNumberOfLinks() ) delete m_beginnode; - } - m_beginnode = NULL; - if ( m_endnode ) - { - m_endnode->RemoveLink( this ); - if ( !m_endnode->GetNumberOfLinks() ) delete m_endnode; - } - m_endnode = NULL; -} - - -void kbLink::UnMark() -{ - m_mark = false; - m_bin = false; -} - -void kbLink::SetMark( bool value ) -{ - m_mark = value; -} - -// -// general purpose mark checker -// -bool kbLink::IsMarked() { return m_mark; } - -void kbLink::SetTopHole( bool value ) { m_hole_top = value; } - -bool kbLink::IsTopHole() { return m_hole_top; } - -// -// Calculates the merge/substact/exor/intersect flags -// -void kbLink::SetLineTypes() -{ - m_merge_R = - m_a_substract_b_R = - m_b_substract_a_R = - m_intersect_R = - m_exor_R = - m_merge_L = - m_a_substract_b_L = - m_b_substract_a_L = - m_intersect_L = - m_exor_L = false; - - //if left side is in group A and B then it is for the merge - m_merge_L = m_LeftA || m_LeftB; - m_merge_R = m_RightA || m_RightB; - //both in mean does not add to result. - if ( m_merge_L && m_merge_R ) - m_merge_L = m_merge_R = false; - - m_a_substract_b_L = m_LeftA && !m_LeftB; - m_a_substract_b_R = m_RightA && !m_RightB; - //both in mean does not add to result. - if ( m_a_substract_b_L && m_a_substract_b_R ) - m_a_substract_b_L = m_a_substract_b_R = false; - - m_b_substract_a_L = m_LeftB && !m_LeftA; - m_b_substract_a_R = m_RightB && !m_RightA; - //both in mean does not add to result. - if ( m_b_substract_a_L && m_b_substract_a_R ) - m_b_substract_a_L = m_b_substract_a_R = false; - - m_intersect_L = m_LeftB && m_LeftA; - m_intersect_R = m_RightB && m_RightA; - //both in mean does not add to result. - if ( m_intersect_L && m_intersect_R ) - m_intersect_L = m_intersect_R = false; - - m_exor_L = !( ( m_LeftB && m_LeftA ) || ( !m_LeftB && !m_LeftA ) ); - m_exor_R = !( ( m_RightB && m_RightA ) || ( !m_RightB && !m_RightA ) ); - //both in mean does not add to result. - if ( m_exor_L && m_exor_R ) - m_exor_L = m_exor_R = false; -} - - -//put in direction with a_node as beginnode -void kbLink::Redirect( kbNode* a_node ) -{ - if ( a_node != m_beginnode ) - { - // swap the begin- and endnode of the current link - kbNode * dummy = m_beginnode; - m_beginnode = m_endnode; - m_endnode = dummy; - - bool swap = m_LeftA; - m_LeftA = m_RightA; - m_RightA = swap; - - swap = m_LeftB; - m_LeftB = m_RightB; - m_RightB = swap; - - swap = m_merge_L ; - m_merge_L = m_merge_R; - m_merge_R = swap; - - swap = m_a_substract_b_L; - m_a_substract_b_L = m_a_substract_b_R; - m_a_substract_b_R = swap; - - swap = m_b_substract_a_L; - m_b_substract_a_L = m_b_substract_a_R; - m_b_substract_a_R = swap; - - swap = m_intersect_L; - m_intersect_L = m_intersect_R; - m_intersect_R = swap; - - swap = m_exor_L; - m_exor_L = m_exor_R; - m_exor_R = swap; - } -} diff --git a/polygon/kbool/src/lpoint.cpp b/polygon/kbool/src/lpoint.cpp deleted file mode 100644 index 737fedb1a4..0000000000 --- a/polygon/kbool/src/lpoint.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/*! \file src/lpoint.cpp - \brief Definition of GDSII kbLPoint type structure - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: lpoint.cpp,v 1.4 2009/09/10 17:04:09 titato Exp $ -*/ - -#include "kbool/lpoint.h" -#include - -// Constructors -kbLPoint::kbLPoint() -{ - _x = 0; - _y = 0; -} - - -kbLPoint::kbLPoint( B_INT const X, B_INT const Y ) -{ - _x = X; - _y = Y; -} - - -kbLPoint::kbLPoint( kbLPoint* const a_point ) -{ - if ( !a_point ) - throw Bool_Engine_Error( "Cannot copy a NULL Point Object.\n\nCould not create a kbLPoint Object.", - "Fatal Creation Error", 0, 1 ); - _x = a_point->_x; - _y = a_point->_y; -} - - -B_INT kbLPoint::GetX() -{ - return _x; -} - -B_INT kbLPoint::GetY() -{ - return _y; -} - - -void kbLPoint::SetX( B_INT a_point_x ) -{ - _x = a_point_x; -} - - -void kbLPoint::SetY( B_INT a_point_y ) -{ - _y = a_point_y; -} - - -kbLPoint kbLPoint::GetPoint() -{ - return * this; -} - - -void kbLPoint::Set( const B_INT X, const B_INT Y ) -{ - _x = X; - _y = Y; -} - - -void kbLPoint::Set( const kbLPoint &a_point ) -{ - _x = a_point._x; - _y = a_point._y; -} - -bool kbLPoint::Equal( const kbLPoint a_point, B_INT Marge ) -{ - B_INT delta_x, delta_y; - - delta_x = babs( ( _x - a_point._x ) ); - delta_y = babs( ( _y - a_point._y ) ); - - if ( ( delta_x <= Marge ) && ( delta_y <= Marge ) ) - return true; - else - return false; -} - - -bool kbLPoint::Equal( const B_INT X, const B_INT Y, B_INT Marge ) -{ - return ( bool )( ( babs( _x - X ) <= Marge ) && ( babs( _y - Y ) <= Marge ) ); -} - -bool kbLPoint::ShorterThan( const kbLPoint a_point, B_INT Marge ) -{ - double a, b; - a = ( double ) ( a_point._x - _x ); - a *= a; - b = ( double ) ( a_point._y - _y ); - b *= b; - - return ( bool ) ( ( a + b ) <= Marge * Marge ? true : false ) ; -} - - -bool kbLPoint::ShorterThan( const B_INT X, const B_INT Y, B_INT Marge ) -{ - double a, b; - a = ( double ) ( X - _x ); - a *= a; - b = ( double ) ( Y - _y ); - b *= b; - - return ( bool ) ( a + b <= Marge * Marge ? true : false ) ; -} - - -// overload the assign (=) operator -// usage : a_point = another_point; - -kbLPoint &kbLPoint::operator=( const kbLPoint &other_point ) -{ - _x = other_point._x; - _y = other_point._y; - return *this; -} - - -// overload the + operator -// usage : a_point = point1 + point2; - -kbLPoint &kbLPoint::operator+( const kbLPoint &other_point ) -{ - _x += other_point._x; - _y += other_point._y; - return *this; -} - - - -// overload the - operator -// usage : a_point = point1 - point2; - -kbLPoint &kbLPoint::operator-( const kbLPoint &other_point ) -{ - _x -= other_point._x; - _y -= other_point._y; - return *this; -} - - -// overload the * operator -// usage: a_point = point1 * 100; - -kbLPoint &kbLPoint::operator*( int factor ) -{ - _x *= factor; - _y *= factor; - return *this; -} - - -// overload the / operator -// usage: a_point = point1 / 100; - -kbLPoint &kbLPoint::operator/( int factor ) -{ - _x /= factor; - _y /= factor; - return *this; -} - - -// overload the compare (==) operator -// usage: if (point1 == point2) { }; - -int kbLPoint::operator==( const kbLPoint &other_point ) const -{ - return ( ( other_point._x == _x ) && ( other_point._y == _y ) ); -} - - -// overload the diffrent (!=) operator -// usage: if (point1 != point2) { }; - -int kbLPoint::operator!=( const kbLPoint &other_point ) const -{ - return ( ( other_point._x != _x ) || ( other_point._y != _y ) ); -} - - - diff --git a/polygon/kbool/src/node.cpp b/polygon/kbool/src/node.cpp deleted file mode 100644 index 93ab8b1c20..0000000000 --- a/polygon/kbool/src/node.cpp +++ /dev/null @@ -1,620 +0,0 @@ -/*! \file src/node.cpp - \brief Holds a GDSII node structure - \author Klaas Holwerda - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: node.cpp,v 1.7 2009/09/14 16:50:12 titato Exp $ -*/ - -#include "kbool/node.h" -#include "kbool/link.h" -#include "kbool/line.h" -#include - -//this here is to initialize the static iterator of node -//with NOLIST constructor -//TDLI kbNode::_linkiter=TDLI(_GC); - -kbNode::kbNode( Bool_Engine* GC ) : kbLPoint( 0, 0 ) -{ - _GC = GC; - _linklist = new DL_List(); -} - - -kbNode::kbNode( B_INT const X, B_INT const Y, Bool_Engine* GC ) : kbLPoint( X, Y ) -{ - _GC = GC; - _linklist = new DL_List(); -} - - -kbNode::kbNode( kbLPoint* const a_point, Bool_Engine* GC ) : kbLPoint( a_point ) -{ - _GC = GC; - _linklist = new DL_List(); -} - - -//kbNode::kbNode(kbNode * const other) : kbLPoint(other) -kbNode::kbNode( kbNode * const other, Bool_Engine* GC ) -{ - _GC = GC; - _x = other->_x; - _y = other->_y; - _linklist = new DL_List(); -} - -kbNode& kbNode::operator=( const kbNode &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 kbNode::RoundInt( B_INT grid ) -{ - _x = ( B_INT ) floor( ( _x + grid * 0.5 ) / grid ) * grid; - _y = ( B_INT ) floor( ( _y + grid * 0.5 ) / grid ) * grid; -} - -kbNode::~kbNode() -{ - delete _linklist; -} - -DL_List* kbNode::GetLinklist() -{ - return _linklist; -} - -void kbNode::AddLink( kbLink *a_link ) -{ -// assert(a_link); - _linklist->insbegin( a_link ); -} - -kbLink* kbNode::GetIncomingLink() -{ - if ( ( ( kbLink* )_linklist->headitem() )->GetEndNode() == this ) - return ( kbLink* )_linklist->headitem(); - else - return ( kbLink* )_linklist->tailitem(); -} - -kbLink* kbNode::GetOutgoingLink() -{ - if ( ( ( kbLink* )_linklist->headitem() )->GetBeginNode() == this ) - return ( kbLink* )_linklist->headitem(); - else - return ( kbLink* )_linklist->tailitem(); -} - -// -// Returns the number of connected links -// -int kbNode::GetNumberOfLinks() -{ - return _linklist->count(); -} - -kbLink* kbNode::GetOtherLink( kbLink* prev ) -{ - if ( prev == ( kbLink* )_linklist->headitem() ) - return ( kbLink* )_linklist->tailitem(); - if ( prev == ( kbLink* )_linklist->tailitem() ) - return ( kbLink* )_linklist->headitem(); - - return NULL; -} - - -int kbNode::Merge( kbNode *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 Iother( other->_linklist ); - kbLink* 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 kbNode::RemoveLink( kbLink *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 kbNode::Simplify( kbNode *First, kbNode *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 - kbLink tmp_link( _GC ); - tmp_link.Set( First, Second ); - kbLine 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; -} - - -kbLink* kbNode::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; - kbLink *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; - } -} - - -kbLink* kbNode::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; - kbLink *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 kbNode::SameSides( kbLink* const prev , kbLink* 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 -kbLink* kbNode::GetMost( kbLink* const prev , LinkStatus whatside, BOOL_OP operation ) -{ - kbLink * reserve = 0; - kbLink *Result = NULL, *link; - kbNode* prevbegin = prev->GetOther( this ); - - if ( _linklist->count() == 2 ) // only two links to this node take the one != prev - { - if ( ( link = ( kbLink* )_linklist->headitem() ) == prev ) //this is NOT the one to go on - link = ( kbLink* )_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 kbNode - 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 -kbLink* kbNode::GetMostHole( kbLink* const prev, LinkStatus whatside, BOOL_OP operation, bool searchholelink ) -{ - kbLink * reserve = 0; - kbLink *Result = NULL, *link; - kbNode* prevbegin = prev->GetOther( this ); - - if ( _linklist->count() == 2 ) // only two links to this node take the one != prev - { - if ( ( link = ( kbLink* )_linklist->headitem() ) == prev ) //this is NOT the one to go on - link = ( kbLink* )_linklist->tailitem(); - if ( - !link->BeenHere() && - link->GetHole() && - ( searchholelink && link->GetHoleLink() || !link->GetHoleLink() ) && - 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 kbNode - while( !_GC->_linkiter->hitroot() ) - { - link = _GC->_linkiter->item(); - if ( - !link->BeenHere() && - link->GetHole() && - ( searchholelink && link->GetHoleLink() || !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 -kbLink* kbNode::GetHoleLink( kbLink* const prev, LinkStatus whatside, bool checkbin, BOOL_OP operation ) -{ - kbLink * 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 ) - ) - { - 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->Detach(); - return ( Result ); -} - -// this function gets the highest not flat link -kbLink* kbNode::GetNotFlat() -{ - kbLink * 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 -kbLink *kbNode::Follow( kbLink* const prev ) -{ - kbLink * 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 -kbLink* kbNode::GetBinHighest( bool binset ) -{ - kbLink * 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 ); -} - - diff --git a/polygon/kbool/src/record.cpp b/polygon/kbool/src/record.cpp deleted file mode 100644 index d1e21fac86..0000000000 --- a/polygon/kbool/src/record.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/*! \file src/record.cpp - \author Klaas Holwerda or Julian Smart - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: record.cpp,v 1.5 2009/09/10 17:04:09 titato Exp $ -*/ - -#include "kbool/booleng.h" -#include "kbool/record.h" -#include "kbool/node.h" - -#include -#include - -#define LNK _line.GetLink() - -//int r_index=-1; -//void* _Record_Pool[30]; - -//void DeleteRecordPool() -//{ -// while (r_index!=-1) -// { -// free( _Record_Pool[r_index--]); -// } -//} - -kbRecord::~kbRecord() -{} - - -//void* kbRecord::operator new(size_t size) -//{ -// -// if (r_index!=-1) -// { -// return _Record_Pool[r_index--]; -// } -// -// return malloc(size); -//} - -//void kbRecord::operator delete(void* recordptr) -//{ -// -// if (r_index < 28) -// { -// _Record_Pool[++r_index]= recordptr; -// return; -// } -// -// free (recordptr); -//} - -//void kbRecord::deletepool() -//{ -// -// while (r_index!=-1) -// { -// free( _Record_Pool[r_index--]); -// } -//} - -kbRecord::kbRecord( kbLink* link, Bool_Engine* GC ) - : _line( GC ) -{ - _GC = GC; - _dir = GO_RIGHT; - _a = 0; - _b = 0; - _line.Set( link ); - _line.CalculateLineParameters(); -} - - -//when the dimensions of a link for a record changes, its line parameters need to be recalculated -void kbRecord::SetNewLink( kbLink* link ) -{ - _line.Set( link ); - _line.CalculateLineParameters(); -} - -//for beams calculate the ysp on the low scanline -void kbRecord::Calc_Ysp( kbNode* low ) -{ - if ( ( LNK->GetEndNode() == low ) || ( LNK->GetBeginNode() == low ) ) - { - _ysp = low->GetY(); - return; - } - - if ( LNK->GetEndNode()->GetX() == LNK->GetBeginNode()->GetX() ) - _ysp = low->GetY(); //flatlink only in flatbeams - else if ( LNK->GetEndNode()->GetX() == low->GetX() ) - _ysp = LNK->GetEndNode()->GetY(); - else if ( LNK->GetBeginNode()->GetX() == low->GetX() ) - _ysp = LNK->GetBeginNode()->GetY(); - else - _ysp = _line.Calculate_Y_from_X( low->GetX() ); -} - -//to set the _dir for new links in the beam -void kbRecord::Set_Flags() -{ - if ( LNK->GetEndNode()->GetX() == LNK->GetBeginNode()->GetX() ) //flatlink ? - { //only happens in flat beams - if ( LNK->GetEndNode()->GetY() < LNK->GetBeginNode()->GetY() ) - _dir = GO_RIGHT; - else - _dir = GO_LEFT; - } - else - { - if ( LNK->GetEndNode()->GetX() > LNK->GetBeginNode()->GetX() ) - _dir = GO_RIGHT; - else - _dir = GO_LEFT; - } -} - -kbLink* kbRecord::GetLink() -{ - return LNK; -} - -B_INT kbRecord::Ysp() -{ - return _ysp; -} - -void kbRecord::SetYsp( B_INT ysp ) -{ - _ysp = ysp; -} - -DIRECTION kbRecord::Direction() -{ - return DIRECTION( _dir ); -} - -bool kbRecord::Calc_Left_Right( kbRecord* record_above_me ) -{ - bool par = false; - - if ( !record_above_me ) //null if no record above - { _a = 0;_b = 0; } - else - { - _a = record_above_me->_a; - _b = record_above_me->_b; - } - - switch ( _dir & 1 ) - { - case GO_LEFT : if ( LNK->Group() == GROUP_A ) - { - LNK->SetRightA( ( bool )( _a > 0 ) ); - - if ( _GC->GetWindingRule() ) - LNK->GetInc() ? _a++ : _a--; - else - { //ALTERNATE - if ( _a ) - _a = 0; - else - _a = 1; - } - - LNK->SetLeftA( ( bool )( _a > 0 ) ); - LNK->SetLeftB( ( bool )( _b > 0 ) ); - LNK->SetRightB( ( bool )( _b > 0 ) ); - } - else - { - LNK->SetRightA( ( bool )( _a > 0 ) ); - LNK->SetLeftA( ( bool )( _a > 0 ) ); - LNK->SetRightB( ( bool )( _b > 0 ) ); - - if ( _GC->GetWindingRule() ) - LNK->GetInc() ? _b++ : _b--; - else //ALTERNATE - { - if ( _b ) - _b = 0; - else - _b = 1; - } - - LNK->SetLeftB( ( bool )( _b > 0 ) ); - } - break; - case GO_RIGHT : if ( LNK->Group() == GROUP_A ) - { - LNK->SetLeftA( ( bool )( _a > 0 ) ); - - if ( _GC->GetWindingRule() ) - LNK->GetInc() ? _a++ : _a--; - else - { //ALTERNATE - if ( _a ) - _a = 0; - else - _a = 1; - } - - LNK->SetRightA( ( bool )( _a > 0 ) ); - LNK->SetLeftB( ( bool )( _b > 0 ) ); - LNK->SetRightB( ( bool )( _b > 0 ) ); - } - else - { - LNK->SetRightA( ( bool )( _a > 0 ) ); - LNK->SetLeftA( ( bool )( _a > 0 ) ); - LNK->SetLeftB( ( bool )( _b > 0 ) ); - - if ( _GC->GetWindingRule() ) - LNK->GetInc() ? _b++ : _b--; - else - { //ALTERNATE - if ( _b ) - _b = 0; - else - _b = 1; - } - - LNK->SetRightB( ( bool )( _b > 0 ) ); - } - break; - default : _GC->error( "Undefined Direction of link", "function IScanBeam::Calc_Set_Left_Right()" ); - break; - } - -//THE NEXT WILL WORK for MOST windingrule polygons, -//even when not taking into acount windingrule -// not all - /* - switch (_dir&1) - { - case GO_LEFT : if (LNK->Group() == GROUP_A) - { - LNK->SetRightA((bool)(_a>0)); - - if (booleng->Get_WindingRule()) - LNK->GetInc() ? _a++ : _a--; - else - _a--; - - LNK->SetLeftA((bool)(_a>0)); - LNK->SetLeftB((bool)(_b>0)); - LNK->SetRightB((bool)(_b>0)); - } - else - { - LNK->SetRightA((bool)(_a > 0)); - LNK->SetLeftA((bool)(_a>0)); - LNK->SetRightB((bool)(_b>0)); - - if (booleng->Get_WindingRule()) - LNK->GetInc() ? _b++ : _b--; - else - _b--; - - LNK->SetLeftB((bool)(_b>0)); - } - break; - case GO_RIGHT : if (LNK->Group() == GROUP_A) - { - LNK->SetLeftA((bool)(_a>0)); - - if (booleng->Get_WindingRule()) - LNK->GetInc() ? _a++ : _a--; - else - _a++; - - LNK->SetRightA((bool)(_a>0)); - LNK->SetLeftB((bool)(_b>0)); - LNK->SetRightB((bool)(_b>0)); - } - else - { - LNK->SetRightA((bool)(_a>0)); - LNK->SetLeftA((bool)(_a>0)); - LNK->SetLeftB((bool)(_b>0)); - - if (booleng->Get_WindingRule()) - LNK->GetInc() ? _b++ : _b--; - else - _b++; - - LNK->SetRightB((bool)(_b>0)); - } - break; - default : _messagehandler->error("Undefined Direction of link","function IScanBeam::Calc_Set_Left_Right()"); - break; - } - */ - //if the records are parallel (same begin/endnodes) - //the above link a/b flag are adjusted to the current a/b depth - if ( record_above_me && Equal( record_above_me ) ) - { - par = true; - LNK->Mark(); - record_above_me->_a = _a; - record_above_me->_b = _b; - if ( Direction() == GO_LEFT ) - { - //set the bottom side of the above link - if ( record_above_me->Direction() == GO_LEFT ) - { - record_above_me->LNK->SetLeftA( LNK->GetLeftA() ); - record_above_me->LNK->SetLeftB( LNK->GetLeftB() ); - } - else - { - record_above_me->LNK->SetRightA( LNK->GetLeftA() ); - record_above_me->LNK->SetRightB( LNK->GetLeftB() ); - } - } - else - { - //set the bottom side of the above link - if ( record_above_me->Direction() == GO_LEFT ) - { - record_above_me->LNK->SetLeftA( LNK->GetRightA() ); - record_above_me->LNK->SetLeftB( LNK->GetRightB() ); - } - else - { - record_above_me->LNK->SetRightA( LNK->GetRightA() ); - record_above_me->LNK->SetRightB( LNK->GetRightB() ); - } - } - } - return par; -} - -bool kbRecord::Equal( kbRecord *a ) -{ - return( ( bool )( ( LNK->GetOther( a->LNK->GetBeginNode() ) == a->LNK->GetEndNode() ) && - ( LNK->GetOther( a->LNK->GetEndNode() ) == a->LNK->GetBeginNode() ) ) ); -} - - -kbLine* kbRecord::GetLine() -{ - return & _line; -} - - diff --git a/polygon/kbool/src/scanbeam.cpp b/polygon/kbool/src/scanbeam.cpp deleted file mode 100644 index 000bdeedca..0000000000 --- a/polygon/kbool/src/scanbeam.cpp +++ /dev/null @@ -1,1467 +0,0 @@ -/*! \file src/scanbeam.cpp - \author Klaas Holwerda or Julian Smart - - Copyright: 2001-2004 (C) Klaas Holwerda - - Licence: see kboollicense.txt - - RCS-ID: $Id: scanbeam.cpp,v 1.7 2009/09/14 16:50:12 titato Exp $ -*/ - -// class scanbeam -// this class represents de space between two scanlines -#include "kbool/scanbeam.h" -#include -#include - -#include "kbool/booleng.h" - -#include "kbool/graph.h" -#include "kbool/node.h" - -//this here is to initialize the static iterator of scanbeam -//with NOLIST constructor - -int recordsorter( kbRecord* , kbRecord* ); - -int recordsorter_ysp_angle( kbRecord* , kbRecord* ); -int recordsorter_ysp_angle_back( kbRecord* rec1, kbRecord* rec2 ); - -ScanBeam::ScanBeam( Bool_Engine* GC ): DL_List() -{ - _GC = GC; - _type = NORMAL; - _BI.Attach( this ); -} - -ScanBeam::~ScanBeam() -{ - //first delete all record still in the beam - _BI.Detach(); - remove_all( true ); - - //DeleteRecordPool(); -} - -void ScanBeam::SetType( kbNode* low, kbNode* high ) -{ - if ( low->GetX() < high->GetX() ) - _type = NORMAL; - else - _type = FLAT; -} - -/* -//catch node to link crossings -// must be sorted on ysp -int ScanBeam::FindCloseLinksAndCross(TDLI* _I,kbNode* _lowf) -{ - int merges = 0; - kbRecord* record; - - TDLI _BBI=TDLI(this); - - if (_BI.count() > 1) - { - //first search a link towards this node - for(_BI.tohead(); !_BI.hitroot(); _BI++) - { - record=_BI.item(); - if( (record->GetLink()->GetBeginNode()==_lowf) || - (record->GetLink()->GetEndNode() ==_lowf) - ) - break; - } - - //NOTICE if the node "a_node" is not inside a record - //for instance to connected flat links (flatlinks not in beam) - //then IL will be at end (those will be catched at 90 degrees rotation) - if (_BI.hitroot()) - { - return(merges); - } - - //from IL search back for close links - _BBI.toiter(&_BI); - _BBI--; - while(!_BBI.hitroot()) - { - record=_BBI.item(); - - if (record->Ysp() != _lowf->GetY()) - break; - - // the distance to the low node is smaller then the MARGE - if( (record->GetLink()->GetBeginNode()!=_lowf) && - (record->GetLink()->GetEndNode() !=_lowf) - ) - { // the link is not towards the low node - record->GetLink()->AddCrossing(_lowf); - record->SetNewLink(record->GetLink()->ProcessCrossingsSmart(_I)); - merges++; - } - _BBI--; - } - - //from IL search forward for close links - _BBI.toiter(&_BI); - _BBI++; - while(!_BBI.hitroot()) - { - record=_BBI.item(); - - if (record->Ysp() != _lowf->GetY()) -// if (record->Ysp() < _lowf->GetY()-MARGE) - break; - - // the distance to the low node is smaller then the MARGE - if( (record->GetLink()->GetBeginNode()!=_lowf) && - (record->GetLink()->GetEndNode() !=_lowf) - ) - { // the link is not towards the low node - record->GetLink()->AddCrossing(_lowf); - record->SetNewLink(record->GetLink()->ProcessCrossingsSmart(_I)); - merges++; - } - _BBI++; - } - } - return merges; -} -*/ - -/* -bool ScanBeam::Update(TDLI* _I,kbNode* _lowf) -{ - bool found=false; - kbLink* link; - - _BI.tohead(); - while (!_BI.hitroot()) - { - - kbRecord* record=_BI.item(); - record->Calc_Ysp(_type,_low); - _BI++; - } - - FindCloseLinksAndCross(_I,_lowf); - - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record=_BI.item(); - //records containing links towards the new low node - //are links to be marked for removal - - if ((record->GetLink()->GetEndNode() == _lowf) || - (record->GetLink()->GetBeginNode() == _lowf) - ) - { - //cross here the links that meat eachother now - delete _BI.item(); - _BI.remove(); - - //cross here the links that meat eachother now - _BI--; - if (!_BI.hitroot() && (_BI.count() > 1)) - { - kbRecord* prev=_BI.item(); - _BI++; - if (!_BI.hitroot()) - { - if (!_BI.item()->Equal(prev)) // records NOT parallel - if (_BI.item()->GetLine()->Intersect(prev->GetLine(),MARGE)) - { - //they did cross, integrate the crossings in the graph - //this may modify the links already part of the record - //this is why they are returned in set for the record - _BI.item()->SetNewLink(_BI.item()->GetLink()->ProcessCrossingsSmart(_I)); - prev->SetNewLink(prev->GetLink()->ProcessCrossingsSmart(_I)); - } - } - } - else - _BI++; - } - else - _BI++; - } - - //writebeam(); - - //ONLY links towards the low node are possible to be added - //the bin flag will be set if it fits in the beam - //so for following beams it will not be checked again - while ( bool(link=_lowf->GetBinHighest(false)) ) - { - kbRecord* record=new kbRecord(link); - // yp_new will always be the y of low node since all new links are - // from this node - record->SetYsp(_lowf->GetY()); - record->Set_Flags(_type); - //need to calculate ysn to be able to sort this record in the right order - //this is only used when the insert node is equal for both records - // ins_smart and cross neighbour directly - // if empty then just insert - - if (empty()) - insend(record); - else - { - // put new item left of the one that is bigger - _BI.tohead(); - while(!_BI.hitroot()) - { - if (recordsorter_ysp_angle(record,_BI.item())==1) - break; - _BI++; - } - - _BI.insbefore(record); - _BI--;_BI--; //just before the new record inserted - if (!_BI.hitroot()) - { - kbRecord* prev=_BI.item(); - _BI++; //goto the new record inserted - if (!_BI.item()->Equal(prev)) // records NOT parallel - { - if (_BI.item()->GetLine()->Intersect(prev->GetLine(),MARGE)) - { - //this may modify the links already part of the record - //this is why they are returned in set for the record - _BI.item()->SetNewLink(_BI.item()->GetLink()->ProcessCrossingsSmart(_I)); - prev->SetNewLink(prev->GetLink()->ProcessCrossingsSmart(_I)); - } - } - } - else - _BI++; - - kbRecord* prev=_BI.item(); //the new record - _BI++; - if (!_BI.hitroot() && !_BI.item()->Equal(prev)) // records NOT parallel - { - kbRecord* cur=_BI.item(); - if (cur->GetLine()->Intersect(prev->GetLine(),MARGE)) - { - //this may modify the links already part of the record - //this is why they are returned in set for the record - cur->SetNewLink(cur->GetLink()->ProcessCrossingsSmart(_I)); - prev->SetNewLink(prev->GetLink()->ProcessCrossingsSmart(_I)); - } - } - } - //remember this to calculate in/out values for each new link its polygon again. - GNI->insend(record->GetLink()->GetGraphNum()); - found=true; - record->GetLink()->SetBeenHere(); - } - - FindCloseLinksAndCross(_I,_lowf); - //writebeam(); - return(found); -} -*/ - -bool ScanBeam::FindNew( SCANTYPE scantype, TDLI* _I, bool& holes ) -{ - bool foundnew = false; - - _low = _I->item()->GetBeginNode(); - - kbLink* link; - - //if (!checksort()) - // SortTheBeam(); - - lastinserted = 0; - //ONLY links towards the low node are possible to be added - //the bin flag will be set if it fits in the beam - //so for following beams it will not be checked again - while ( ( link = _low->GetBinHighest( false ) ) != NULL ) - { - if ( ( link->GetEndNode()->GetX() == link->GetBeginNode()->GetX() ) //flatlink in flatbeam - && ( ( scantype == NODELINK ) || ( scantype == LINKLINK ) || ( scantype == LINKHOLES ) ) - ) - { - switch( scantype ) - { - case NODELINK: - { - //all vertical links in flatbeam are ignored - //normal link in beam - kbRecord * record = new kbRecord( link, _GC ); - // yp_new will always be the y of low node since all new links are - // from this node - record->SetYsp( _low->GetY() ); - record->Set_Flags(); - // put new item left of the one that is lower in the beam - // The last one inserted in this loop, is already left of the current - // iterator position. So the new links are inerted in proper order. - link->SetRecordNode( _BI.insbefore( record ) ); - _BI--; - foundnew = Process_PointToLink_Crossings() != 0 || foundnew; - delete record; - _BI.remove(); - break; - } - case LINKLINK: - //is the new record a flat link - { - kbLine flatline = kbLine( link, _GC ); - foundnew = Process_LinkToLink_Flat( &flatline ) || foundnew; - //flatlinks are not part of the beams, still they are used to find new beams - //they can be processed now if the beginnode does not change, since this is used to - //to find new beams. and its position does not change - //ProcessCrossings does take care of this - flatline.ProcessCrossings( _I ); - break; - } - case LINKHOLES : //holes are never to flatlinks - assert( true ); - default: - break; - } - } - else - { - //normal link in beam - kbRecord* record = new kbRecord( link, _GC ); - // yp_new will always be the y of low node since all new links are - // from this node - record->SetYsp( _low->GetY() ); - record->Set_Flags(); - // put new item left of the one that is lower in the beam - // The last one inserted in this loop, is already left of the current - // iterator position. So the new links are inserted in proper order. - link->SetRecordNode( _BI.insbefore( record ) ); - lastinserted++; - - //_GC->Write_Log( "after insert" ); - writebeam(); - - switch( scantype ) - { - case NODELINK: - _BI--; - foundnew = Process_PointToLink_Crossings() != 0 || foundnew; - _BI++; - break; - case INOUT: - { - _BI--; - //now we can set the _inc flag - Generate_INOUT( record->GetLink()->GetGraphNum() ); - _BI++; - } - break; - case GENLR: - { - //now we can set the a/b group flags based on the above link - _BI--; - _BI--; - kbRecord* above = 0; - if ( !_BI.hitroot() ) - above = _BI.item(); - _BI++; - - //something to do for winding rule - - if ( record->Calc_Left_Right( above ) ) - { - delete record; - _BI.remove(); - lastinserted--; - } - else - _BI++; - } - break; - case LINKHOLES: - _BI--; - holes = ProcessHoles( true, _I ) || holes; - _BI++; - break; - - default: - break; - } - } - link->SetBeenHere(); - } - - writebeam(); - - return foundnew; -} - -bool ScanBeam::RemoveOld( SCANTYPE scantype, TDLI* _I, bool& holes ) -{ - bool found = false; - bool foundnew = false; - DL_Iter _BBI = DL_Iter(); - - _low = _I->item()->GetBeginNode(); - - switch( scantype ) - { - case INOUT: - case GENLR: - case LINKHOLES: - if ( _type == NORMAL ) - { - if ( _low->GetBinHighest( true ) ) //is there something to remove - { - if ( scantype == LINKHOLES ) - { - // Tophole links can be linked at the begin or end point, depending on - // which is higher in Y. - // A link pointing to the low node, and which is a tophole link, - // and which was not linked in sofar should be linked now. - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - //records containing links towards the new low node - //are links to be removed - if ( ( record->GetLink()->GetEndNode() == _low ) || - ( record->GetLink()->GetBeginNode() == _low ) - ) - { - holes = ProcessHoles( false, _I ) || holes; - } - _BI++; - } - } - - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - //records containing links towards the new low node - //are links to be removed - if ( ( record->GetLink()->GetEndNode() == _low ) || - ( record->GetLink()->GetBeginNode() == _low ) - ) - { - delete _BI.item(); - _BI.remove(); - found = true; - } - else - { - //recalculate ysp for the new scanline - record->Calc_Ysp( _low ); - _BI++; - } - } - - // all records are renewed in Ysp. - // found links to remove, we search the new insert position for new links. - if ( found ) - { - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - if ( record->Ysp() < _low->GetY() ) - { - break; - } - _BI++; - } - } - } - else - { - // nothing is removed from the beam, still we moved forward with the scanline - // at the new _low, so we need to recalculate the intersections of the links - // with the new scanline. - // Also the the insert position for new links is determined, being the first - // link below _low. - _BBI.Attach( this ); - _BBI.toroot(); - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - - record->Calc_Ysp( _low ); - if ( !found && ( record->Ysp() < _low->GetY() ) ) - { - found = true; - _BBI.toiter( &_BI ); - } - _BI++; - } - _BI.toiter( &_BBI ); - _BBI.Detach(); - } - } - else // _type == NORMAL - { //because the previous beam was flat the links to remove are - //below the last insert position - if ( _low->GetBinHighest( true ) ) //is there something to remove - { - - if ( scantype == LINKHOLES ) - { - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - //records containing links towards the new low node - //are links to be removed - if ( ( record->GetLink()->GetEndNode() == _low ) || - ( record->GetLink()->GetBeginNode() == _low ) - ) - { - holes = ProcessHoles( false, _I ) || holes; - } - _BI++; - } - } - - //on record back bring us to the last inserted record - //or if nothing was inserted the record before the last deleted record - //if there was no record before the last deleted record this means - //we where at the beginning of the beam, so at root - - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - //records containing links towards the new low node - //are links to be removed - if ( ( record->GetLink()->GetEndNode() == _low ) || - ( record->GetLink()->GetBeginNode() == _low ) - ) - { - delete _BI.item(); - _BI.remove(); - found = true; - } - else if ( found ) //only once in here - break; - else if ( record->Ysp() < _low->GetY() ) - //if flatlinks are not in the beam nothing will be found - //this will bring us to the right insertion point - break; - else - _BI++; - } - } - else - { - //on record back bring us to the last inserted record - //or if nothing was inserted the record before the last deleted record - //if there was no record before the last deleted record this means - //we where at the beginning of the beam, so at root - - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - if ( record->Ysp() < _low->GetY() ) - break; - _BI++; - } - } - } - break; - - case NODELINK: - case LINKLINK: - { - if ( _type == NORMAL ) - { - Calc_Ysp(); - if ( scantype == LINKLINK ) - foundnew = Process_LinkToLink_Crossings() != 0 || foundnew; - else - SortTheBeam( false ); - } - //else beam is already sorted because the added/removed flat links - //do not change the ysp of links already there, new non flat links - //are inserted in order, as result the beam stays sorted - - if ( _low->GetBinHighest( true ) ) //is there something to remove - { - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - //records containing links towards the new low node - //are links to be removed - if ( ( record->GetLink()->GetEndNode() == _low ) || - ( record->GetLink()->GetBeginNode() == _low ) - ) - { - kbLine * line = record->GetLine(); - if ( scantype == NODELINK ) - foundnew = Process_PointToLink_Crossings() != 0 || foundnew; - line->ProcessCrossings( _I ); - delete _BI.item(); - _BI.remove(); - found = true; - } - //because the beam is sorted on ysp, stop when nothing can be there to remove - //and the right insertion point for new links has been found - else if ( ( record->Ysp() < _low->GetY() ) ) - break; - else - _BI++; - } - } - else - { - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); - //because the beam is sorted on ysp, stop when - //the right insertion point for new links has been found - if ( ( record->Ysp() < _low->GetY() ) ) - break; - _BI++; - } - } - } - break; - - default: - break; - } - - return foundnew; -} -/* -bool ScanBeam::RemoveOld(SCANTYPE scantype,TDLI* _I, bool& holes ) -{ - bool found = false; - bool foundnew = false; - DL_Iter _BBI=DL_Iter(); - bool attached=false; - - _low = _I->item()->GetBeginNode(); - - switch(scantype) - { - case INOUT: - case GENLR: - case LINKHOLES: - if (_type==NORMAL ) - { - kbLink* link = _low->GetBinHighest(true); - if ( link ) //is there something to remove - { - link->SetRecordNode( NULL ); - - if ( scantype == LINKHOLES ) - { - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record = _BI.item(); - //records containing links towards the new low node - //are links to be removed - if ((record->GetLink()->GetEndNode() == _low) || - (record->GetLink()->GetBeginNode() == _low) - ) - { - holes = ProcessHoles(false,_I) || holes; - } - _BI++; - } - } - - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record=_BI.item(); - //records containing links towards the new low node - //are links to be removed - if ((record->GetLink()->GetEndNode() == _low) || - (record->GetLink()->GetBeginNode() == _low) - ) - { - delete _BI.item(); - _BI.remove(); - found=true; - } - else if (found) //only once in here - { - attached=true; - found=false; - //recalculate ysp for the new scanline - record->Calc_Ysp(_low); - _BI++; - } - else - { - //recalculate ysp for the new scanline - record->Calc_Ysp(_low); - _BI++; - } - } - } - else - { - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record=_BI.item(); - record->Calc_Ysp(_low); - _BI++; - } - } - } - else - { //because the previous beam was flat the links to remove are - //below the last insert position - kbLink* link; - link = _low->GetBinHighest(true); - if( link )//is there something to remove - { - link->SetRecordNode( NULL ); - - bool linkf = false; - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record = _BI.item(); - if (record->GetLink() == link) - linkf = true; - _BI++; - } - - if ( !linkf ) - _BI.tohead(); - - - if ( scantype == LINKHOLES ) - { - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record=_BI.item(); - //records containing links towards the new low node - //are links to be removed - if ((record->GetLink()->GetEndNode() == _low) || - (record->GetLink()->GetBeginNode() == _low) - ) - { - holes = ProcessHoles(false,_I) || holes; - } - _BI++; - } - } - - //_BI.tonode( link->GetRecordNode() ); - //delete _BI.item(); - //_BI.remove(); - - //on record back bring us to the last inserted record - //or if nothing was inserted the record before the last deleted record - //if there was no record before the last deleted record this means - //we where at the beginning of the beam, so at root - - //_BI << (lastinserted+1); - //_BI--; - //if (_BI.hitroot()) //only possible when at the begin of the beam - - //found=false; - - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record=_BI.item(); - //records containing links towards the new low node - //are links to be removed - if ((record->GetLink()->GetEndNode() == _low) || - (record->GetLink()->GetBeginNode() == _low) - ) - { - if ( link != record->GetLink() ) - { - break; - } - if ( link->GetRecordNode() != _BI.node() ) - { - delete _BI.item(); - _BI.remove(); - } - else - { - delete _BI.item(); - _BI.remove(); - } - found=true; - } - else if (found) //only once in here - break; - else if (record->Ysp() < _low->GetY()) - //if flatlinks are not in the beam nothing will be found - //this will bring us to the right insertion point - break; - else - _BI++; - } - - } - - else - { - - //on record back bring us to the last inserted record - //or if nothing was inserted the record before the last deleted record - //if there was no record before the last deleted record this means - //we where at the beginning of the beam, so at root - - //_BI << (lastinserted+ 1); - //_BI--; - //if (_BI.hitroot()) //only possible when at the begin of the beam - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record=_BI.item(); - if (record->Ysp() < _low->GetY()) - break; - _BI++; - } - - } - } - break; - - case NODELINK: - case LINKLINK: - { - if (_type == NORMAL) - { - Calc_Ysp(); - if (scantype==LINKLINK) - foundnew = Process_LinkToLink_Crossings() !=0 || foundnew; - else - SortTheBeam( false ); - } - //else beam is already sorted because the added/removed flat links - //do not change the ysp of links already there, new non flat links - //are inserted in order, as result the beam stays sorted - - if (_low->GetBinHighest(true)) //is there something to remove - { - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record=_BI.item(); - //records containing links towards the new low node - //are links to be removed - if ((record->GetLink()->GetEndNode() == _low) || - (record->GetLink()->GetBeginNode() == _low) - ) - { - kbLine* line=record->GetLine(); - if (scantype==NODELINK) - foundnew = Process_PointToLink_Crossings() !=0 || foundnew; - line->ProcessCrossings(_I); - delete _BI.item(); - _BI.remove(); - found=true; - } - //because the beam is sorted on ysp, stop when nothing can be there to remove - //and the right insertion point for new links has been found - else if ((record->Ysp() < _low->GetY())) - break; - else - _BI++; - } - } - else - { - _BI.tohead(); - while (!_BI.hitroot()) - { - kbRecord* record=_BI.item(); - //because the beam is sorted on ysp, stop when - //the right insertion point for new links has been found - if ((record->Ysp() < _low->GetY())) - break; - _BI++; - } - } - } - break; - - default: - break; - } - - return foundnew; -} -*/ - -void ScanBeam::SortTheBeam( bool backangle ) -{ - if ( backangle ) - _BI.mergesort( recordsorter_ysp_angle_back ); - else - _BI.mergesort( recordsorter_ysp_angle ); -} - -void ScanBeam::Calc_Ysp() -{ - _BI.tohead(); - while ( !_BI.hitroot() ) - { - kbRecord * record = _BI.item(); -// kbLink* link=_BI.item()->GetLink(); - record->Calc_Ysp( _low ); - _BI++; - } -} - -// this function will set for all the records which contain a link with the -// corresponding graphnumber the inc flag. -// The inc flag's function is to see in a beam if we go deeper in the graph or not -void ScanBeam::Generate_INOUT( int graphnumber ) -{ - DIRECTION first_dir = GO_LEFT; - int diepte = 0; - - DL_Iter _BBI = DL_Iter(); - _BBI.Attach( this ); - for( _BBI.tohead(); !_BBI.hitroot(); _BBI++ ) - { - // recalculate _inc again - if ( _BBI.item()->GetLink()->GetGraphNum() == graphnumber ) - { //found a link that belongs to the graph - if ( diepte == 0 ) - { // first link found or at depth zero again - // the direction is important since this is used to find out - // if we go further in or out for coming links - first_dir = _BBI.item()->Direction(); - _BBI.item()->GetLink()->SetInc( true ); - diepte = 1; - } - else - { // according to depth=1 links set depth - // verhoog of verlaag diepte - if ( _BBI.item()->Direction() == first_dir ) - { - diepte++; - _BBI.item()->GetLink()->SetInc( true ); - } - else - { - diepte--; - _BBI.item()->GetLink()->SetInc( false ); - } - } - } - if ( _BBI.item() == _BI.item() ) break; //not need to do the rest, will come in a later beam - } - _BBI.Detach(); -} - - -// function ProcessHoles -// -// this function will search the closest link to a hole -// step one, search for a link that is marked (this is a hole) -// step two, the closest link is the previous link in -// the beam, but only in the beam that contains the highest node -// from the marked link. -// why ? : if the marked link has for the begin and end node different -// x,y values, see below as link C -// B -// A +---------+ -// +----------+ -// ___--+ -// ___--- -// +--- C -// -// when we at first detect link C we would link it to link A, should work he -// but; we always link a hole at its topleft node, so the highest node -// and then we can't link to A but we should link to B -// so when we found the link, we will look if the node that will come -// in a later beam will be higher than the current, if so we will wait -// till that node comes around otherwise we will link this node to the -// closest link (prev in beam) -bool ScanBeam::ProcessHoles( bool atinsert, TDLI* _LI ) -{ - // The scanbeam must already be sorted at this moment - kbNode * topnode; - bool foundholes = false; - - kbRecord* record = _BI.item(); - kbLink* link = record->GetLink(); - kbNode* _low = _LI->item()->GetBeginNode(); - - if( _GC->GetAllowNonTopHoleLinking() ) - { - _BI++; - if ( !_BI.hitroot() && _BI.item()->GetLink()->IsTopHole() ) - { - - kbLink* linkToThis = _BI.item()->GetLink(); - //calculate linkToThis its Y at X of topnode. - kbLine line( _GC ); - line.Set( linkToThis ); - B_INT Y; - kbNode * leftnode; //left node of clossest link - //link right now - if ( linkToThis->GetEndNode()->GetX() == _low->GetX() ) - Y = linkToThis->GetEndNode()->GetY(); - else if ( linkToThis->GetBeginNode()->GetX() == _low->GetX() ) - Y = linkToThis->GetBeginNode()->GetY(); - else - Y = line.Calculate_Y( _low->GetX() ); - - if ( linkToThis->GetBeginNode()->GetX() < linkToThis->GetEndNode()->GetX() ) - leftnode = linkToThis->GetBeginNode(); - else - leftnode = linkToThis->GetEndNode(); - kbNode *topnode = new kbNode( _low->GetX(), Y, _GC ); - kbLink *link_A = new kbLink( 0, topnode, leftnode, _GC ); - // the orginal linkToThis - linkToThis->Replace( leftnode, topnode ); - _LI->insbegin( link_A ); - //reset mark to flag that this hole has been processed - linkToThis->SetTopHole( false ); - - kbLink *link_B = new kbLink( 0, _low, topnode, _GC ); - kbLink *link_BB = new kbLink( 0, topnode, _low, _GC ); - _LI->insbegin( link_B ); - _LI->insbegin( link_BB ); - //mark those two segments as hole linking segments - link_B->SetHoleLink( true ); - link_BB->SetHoleLink( true ); - - //is where we come from/link to a hole - bool closest_is_hole = linkToThis->GetHole(); - - // if the polygon linked to, is a hole, this hole here - // just gets bigger, so we take over the links its hole marking. - link_A->SetHole( closest_is_hole ); - link_B->SetHole( closest_is_hole ); - link_BB->SetHole( closest_is_hole ); - - // we have only one operation at the time, taking - // over the operation flags is enough, since the linking segments will - // be part of that output for any operation done. - link_A->TakeOverOperationFlags( linkToThis ); - link_B->TakeOverOperationFlags( linkToThis ); - link_BB->TakeOverOperationFlags( linkToThis ); - - foundholes = true; - - SortTheBeam( atinsert ); - } - _BI--; - } - - if ( !record->GetLine()->CrossListEmpty() ) - { - SortTheBeam( atinsert ); - - // link the holes in the graph to a link above. - // a the link where the linecrosslist is not empty, means that - // there are links which refer to this link (must be linked to this link) - // make new nodes and links and set them, re-use the old link, so the links - // that still stand in the linecrosslist will not be lost. - // There is a hole that must be linked to this link ! - - kbLink* linkToThis = link; - - TDLI I( record->GetLine()->GetCrossList() ); - I.tohead(); - while( !I.hitroot() ) - { - topnode = I.item(); - I.remove(); - - //calculate linkToThis its Y at X of topnode. - kbLine line( _GC ); - line.Set( linkToThis ); - - kbNode * leftnode; //left node of clossest link - B_INT Y; - //check if flatlink ( i think is always linkBB from a topnode at same X coordinate. - //but lets accept all flatlinks - if ( linkToThis->GetEndNode()->GetX() == linkToThis->GetBeginNode()->GetX() ) - { - //we take the lowest of the flatlink nodes, which is right for - // a second hole at same X - if ( linkToThis->GetEndNode()->GetY() >= linkToThis->GetBeginNode()->GetY() ) - { - Y = linkToThis->GetBeginNode()->GetY(); - leftnode = linkToThis->GetBeginNode(); - } - else - { - Y = linkToThis->GetEndNode()->GetY(); - leftnode = linkToThis->GetEndNode(); - } - } - else - { - if ( linkToThis->GetEndNode()->GetX() == topnode->GetX() ) - Y = linkToThis->GetEndNode()->GetY(); - else if ( linkToThis->GetBeginNode()->GetX() == topnode->GetX() ) - Y = linkToThis->GetBeginNode()->GetY(); - else - Y = line.Calculate_Y( topnode->GetX() ); - - if ( linkToThis->GetBeginNode()->GetX() < linkToThis->GetEndNode()->GetX() ) - leftnode = linkToThis->GetBeginNode(); - else - leftnode = linkToThis->GetEndNode(); - } - // Now we'll create new nodes and new links to make the link between - // the graphs. - - //holes are always linked in a non hole or hole - //for a non hole this link will be to the right - //because non holes are right around - //for holes this will be to the right also, - //because they are left around but the link is always on the - //bottom of the hole - - // linkA linkToThis - // o-------->--------NodeA------->------------o - // leftnode | | - // | | - // linkB v ^ linkBB - // | | - // | | - // outgoing* | | incoming* - // o------<---------topnode--------<----------o - // - // all holes are oriented left around - - - kbNode *node_A = new kbNode( topnode->GetX(), Y, _GC ); - kbLink *link_A = new kbLink( 0, leftnode, node_A, _GC ); - kbLink *link_B = new kbLink( 0, node_A, topnode, _GC ); - kbLink *link_BB = new kbLink( 0, topnode, node_A, _GC ); - // the orginal linkToThis - linkToThis->Replace( leftnode, node_A ); - _LI->insbegin( link_A ); - _LI->insbegin( link_B ); - _LI->insbegin( link_BB ); - - //mark those two segments as hole linking segments - link_B->SetHoleLink( true ); - link_BB->SetHoleLink( true ); - - //is where we come from/link to a hole - bool closest_is_hole = linkToThis->GetHole(); - - // if the polygon linked to, is a hole, this hole here - // just gets bigger, so we take over the links its hole marking. - link_A->SetHole( closest_is_hole ); - link_B->SetHole( closest_is_hole ); - link_BB->SetHole( closest_is_hole ); - - // we have only one operation at the time, taking - // over the operation flags is enough, since the linking segments will - // be part of that output for any operation done. - link_A->TakeOverOperationFlags( linkToThis ); - link_B->TakeOverOperationFlags( linkToThis ); - link_BB->TakeOverOperationFlags( linkToThis ); - - // check next top node is at same X - if ( !I.hitroot() ) - { - kbNode *newtopnode = I.item(); - if ( topnode->GetX() == newtopnode->GetX() ) - linkToThis = link_BB; - else - linkToThis = link; - } - } - } - - if ( link->IsTopHole() ) - { - SortTheBeam( atinsert ); - writebeam(); - } - - if ( link->IsTopHole() && !_BI.athead() ) - { - // now we check if this hole should now be linked, or later - // we always link on the node with the maximum y value, Why ? because i like it ! - // to link we put the node of the hole into the crosslist of the closest link ! - - assert( record->Direction() == GO_LEFT ); - // he goes to the left - if ( atinsert ) - { - if ( link->GetBeginNode()->GetY() <= link->GetEndNode()->GetY() ) - { - topnode = link->GetEndNode(); - //the previous link in the scanbeam == the closest link to the hole in vertical - //direction PUT this node into this link - _BI--; - _BI.item()->GetLine()->AddCrossing( topnode ); - _BI++; - //reset tophole flag, hole has been processed - link->SetTopHole( false ); - foundholes = true; - } - } - else //remove stage of links from te beam - { - //the tophole link was NOT linked at the insert stage, so it most be linked now - topnode = _BI.item()->GetLink()->GetBeginNode(); - //the previous link in the scanbeam == the closest link to the hole in vertical - //direction PUT this node into this link - _BI--; - _BI.item()->GetLine()->AddCrossing( topnode ); - _BI++; - //reset mark to flag that this hole has been processed - link->SetTopHole( false ); - foundholes = true; - } - } - return foundholes; -} - -//sort the records on Ysp if eqaul, sort on tangent at ysp -int recordsorter_ysp_angle( kbRecord* rec1, kbRecord* rec2 ) -{ - if ( rec1->Ysp() > rec2->Ysp() ) - return( 1 ); - if ( rec1->Ysp() < rec2->Ysp() ) - return( -1 ); - //it seems they are equal - B_INT rightY1; - if ( rec1->Direction() == GO_LEFT ) - rightY1 = rec1->GetLink()->GetBeginNode()->GetY(); - else - rightY1 = rec1->GetLink()->GetEndNode()->GetY(); - B_INT rightY2; - if ( rec2->Direction() == GO_LEFT ) - rightY2 = rec2->GetLink()->GetBeginNode()->GetY(); - else - rightY2 = rec2->GetLink()->GetEndNode()->GetY(); - - if ( rightY1 > rightY2 ) - return( 1 ); - if ( rightY1 < rightY2 ) - return( -1 ); - return( 0 ); -} - -//sort the records on Ysp if eqaul, sort on tangent at ysp -int recordsorter_ysp_angle_back( kbRecord* rec1, kbRecord* rec2 ) -{ - if ( rec1->Ysp() > rec2->Ysp() ) - return( 1 ); - if ( rec1->Ysp() < rec2->Ysp() ) - return( -1 ); - //it seems they are equal - B_INT leftY1; - if ( rec1->Direction() == GO_RIGHT ) - leftY1 = rec1->GetLink()->GetBeginNode()->GetY(); - else - leftY1 = rec1->GetLink()->GetEndNode()->GetY(); - B_INT leftY2; - if ( rec2->Direction() == GO_RIGHT ) - leftY2 = rec2->GetLink()->GetBeginNode()->GetY(); - else - leftY2 = rec2->GetLink()->GetEndNode()->GetY(); - - if ( leftY1 > leftY2 ) - return( 1 ); - if ( leftY1 < leftY2 ) - return( -1 ); - return( 0 ); -} - -// swap functie for cocktailsort ==> each swap means an intersection of links -bool swap_crossing_normal( kbRecord *a, kbRecord *b ) -{ - if ( !a->Equal( b ) ) // records NOT parallel - { - a->GetLine()->Intersect_simple( b->GetLine() ); - return true; - } - return false; -} - -int ScanBeam::Process_LinkToLink_Crossings() -{ - // sort on y value of next intersection; and find the intersections - return _BI.cocktailsort( recordsorter_ysp_angle_back, swap_crossing_normal ); -} - -//catch node to link crossings -// must be sorted on ysp -int ScanBeam::Process_PointToLink_Crossings() -{ - int merges = 0; - kbRecord* record; - - if ( _BI.count() > 1 ) - { - DL_Iter IL = DL_Iter( this ); - IL.toiter( &_BI ); - - //from IL search back for close links - IL--; - while( !IL.hitroot() ) - { - record = IL.item(); - - if ( record->Ysp() > _low->GetY() + _GC->GetInternalMarge() ) - break; - - // the distance to the lo/hi node is smaller then the _GC->GetInternalMarge() - if( ( record->GetLink()->GetBeginNode() != _low ) && - ( record->GetLink()->GetEndNode() != _low ) - ) - { // the link is not towards the lohi node - record->GetLine()->AddCrossing( _low ); - merges++; - } - IL--; - } - - //from IL search forward for close links - IL.toiter( &_BI ); - IL++; - while( !IL.hitroot() ) - { - record = IL.item(); - - if ( record->Ysp() < _low->GetY() - _GC->GetInternalMarge() ) - break; - - // the distance to the lohi node is smaller then the booleng->Get_Marge() - if( ( record->GetLink()->GetBeginNode() != _low ) && - ( record->GetLink()->GetEndNode() != _low ) - ) - { // the link is not towards the low node - record->GetLine()->AddCrossing( _low ); - merges++; - } - IL++; - } - - } - - return merges; -} - -int ScanBeam::Process_LinkToLink_Flat( kbLine* flatline ) -{ - int crossfound = 0; - kbRecord* record; - DL_Iter _BBI = DL_Iter(); - _BBI.Attach( this ); - _BBI.toiter( &_BI ); - - for( _BI.tohead(); !_BI.hitroot(); _BI++ ) - { - record = _BI.item(); - - if ( record->Ysp() < ( flatline->GetLink()->GetLowNode()->GetY() - _GC->GetInternalMarge() ) ) - break;//they are sorted so no other can be there - - if ( ( record->Ysp() > ( flatline->GetLink()->GetLowNode()->GetY() - _GC->GetInternalMarge() ) ) - && - ( record->Ysp() < ( flatline->GetLink()->GetHighNode()->GetY() + _GC->GetInternalMarge() ) ) - ) - { //it is in between the flat link region - //create a new node at ysp and insert it in both the flatlink and the crossing link - - if ( - ( record->GetLink()->GetEndNode() != flatline->GetLink()->GetHighNode() ) && - ( record->GetLink()->GetEndNode() != flatline->GetLink()->GetLowNode() ) && - ( record->GetLink()->GetBeginNode() != flatline->GetLink()->GetHighNode() ) && - ( record->GetLink()->GetBeginNode() != flatline->GetLink()->GetLowNode() ) - ) - { - kbNode * newnode = new kbNode( _low->GetX(), _BI.item()->Ysp(), _GC ); - flatline->AddCrossing( newnode ); - record->GetLine()->AddCrossing( newnode ); - crossfound++; - } - } - } - - _BI.toiter( &_BBI ); - _BBI.Detach(); - return crossfound; -} - -bool ScanBeam::checksort() -{ - // if empty then just insert - if ( empty() ) - return true; - - // put new item left of the one that is bigger - _BI.tohead(); - kbRecord* prev = _BI.item(); - _BI++; - while( !_BI.hitroot() ) - { - kbRecord * curr = _BI.item(); - if ( recordsorter_ysp_angle( prev, curr ) == -1 ) - { - recordsorter_ysp_angle( prev, curr ); - return false; - } - prev = _BI.item(); - _BI++; - } - return true; -} - -bool ScanBeam::writebeam() -{ -#if KBOOL_DEBUG == 1 - FILE * file = _GC->GetLogFile(); - - if ( file == NULL ) - return true; - - fprintf( file, "# beam %d \n", count() ); - fprintf( file, " low %I64d %I64d \n", _low->GetX() , _low->GetY() ); - fprintf( file, " type %d \n", _type ); - - if ( empty() ) - { - fprintf( file, " empty \n" ); - return true; - } - - DL_Iter _BI( this ); - - // put new item left of the one that is bigger - _BI.tohead(); - while( !_BI.hitroot() ) - { - kbRecord * cur = _BI.item(); - - fprintf( file, " ysp %I64d \n", cur->Ysp() ); - - kbLink* curl = cur->GetLink(); - - fprintf( file, " linkbegin %I64d %I64d \n", curl->GetBeginNode()->GetX(), curl->GetBeginNode()->GetY() ); - fprintf( file, " linkend %I64d %I64d \n", curl->GetEndNode()->GetX(), curl->GetEndNode()->GetY() ); - - if ( curl->GetEndNode()->GetX() == -2459565876494606883 ) - fprintf( file, " linkend %I64d %I64d \n", curl->GetEndNode()->GetX(), curl->GetEndNode()->GetY() ); - - _BI++; - } -#endif - - return true; -} diff --git a/polygon/math_for_graphics.cpp b/polygon/math_for_graphics.cpp index a1b06b393d..04f7cb4752 100644 --- a/polygon/math_for_graphics.cpp +++ b/polygon/math_for_graphics.cpp @@ -88,10 +88,10 @@ bool TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist ) bool FindSegmentIntersections( int xi, int yi, int xf, int yf, int xi2, int yi2, int xf2, int yf2 ) { - if( max( xi, xf ) < min( xi2, xf2 ) - || min( xi, xf ) > max( xi2, xf2 ) - || max( yi, yf ) < min( yi2, yf2 ) - || min( yi, yf ) > max( yi2, yf2 ) ) + if( std::max( xi, xf ) < std::min( xi2, xf2 ) + || std::min( xi, xf ) > std::max( xi2, xf2 ) + || std::max( yi, yf ) < std::min( yi2, yf2 ) + || std::min( yi, yf ) > std::max( yi2, yf2 ) ) return false; return TestForIntersectionOfStraightLineSegments( xi, yi, xf, yf, @@ -135,7 +135,7 @@ bool FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, in else { if( dist ) - *dist = min( abs( a - xi ), abs( a - xf ) ); + *dist = std::min( abs( a - xi ), abs( a - xf ) ); return false; } @@ -450,16 +450,16 @@ int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int w1, // check clearance between bounding rectangles int min_dist = max_cl + ( (w1 + w2) / 2 ); - if( min( x1i, x1f ) - max( x2i, x2f ) > min_dist ) + if( std::min( x1i, x1f ) - std::max( x2i, x2f ) > min_dist ) return max_cl+1; - if( min( x2i, x2f ) - max( x1i, x1f ) > min_dist ) + if( std::min( x2i, x2f ) - std::max( x1i, x1f ) > min_dist ) return max_cl+1; - if( min( y1i, y1f ) - max( y2i, y2f ) > min_dist ) + if( std::min( y1i, y1f ) - std::max( y2i, y2f ) > min_dist ) return max_cl+1; - if( min( y2i, y2f ) - max( y1i, y1f ) > min_dist ) + if( std::min( y2i, y2f ) - std::max( y1i, y1f ) > min_dist ) return max_cl+1; int xx, yy; @@ -535,7 +535,7 @@ double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int if( InRange( y, yi, yf ) ) return abs( x - xi ); else - return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); + return std::min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); } else if( yf==yi ) { @@ -543,7 +543,7 @@ double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int if( InRange( x, xi, xf ) ) return abs( y - yi ); else - return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); + return std::min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); } else { @@ -564,7 +564,7 @@ double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int if( InRange( xp, xi, xf ) && InRange( yp, yi, yf ) ) return Distance( x, y, xp, yp ); else - return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); + return std::min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) ); } }