Commit b8ea76fe authored by charras's avatar charras

Solved netlist problems for multiple parts per package components in complex hierarchies.

B.O.M. generation still have a minor problem wih this.
parent 88055164
...@@ -5,6 +5,15 @@ Started 2007-June-11 ...@@ -5,6 +5,15 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with Please add newer entries at the top, list the date and your name with
email address. email address.
2008-May-15 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+eeschema:
Solved netlist problems for multiple parts per package components
in complex hierarchies.
B.O.M. generation still have a minor problem wih this.
2008-May-5 UPDATE Dick Hollenbeck <dick@softplc.com> 2008-May-5 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================ ================================================================================
+common.c +common.c
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
****************************************************************/ ****************************************************************/
#include "fctsys.h" #include "fctsys.h"
#include "gr_basic.h"
#include "common.h" #include "common.h"
#include "program.h" #include "program.h"
...@@ -15,8 +14,6 @@ ...@@ -15,8 +14,6 @@
#include "dialog_backanno.cpp" #include "dialog_backanno.cpp"
#include "protos.h"
/**************************************************************/ /**************************************************************/
SCH_COMPONENT * WinEDA_SchematicFrame::FindComponentByRef( SCH_COMPONENT * WinEDA_SchematicFrame::FindComponentByRef(
const wxString& reference ) const wxString& reference )
...@@ -72,7 +69,7 @@ bool WinEDA_SchematicFrame::ProcessStuffFile( FILE* StuffFile ) ...@@ -72,7 +69,7 @@ bool WinEDA_SchematicFrame::ProcessStuffFile( FILE* StuffFile )
continue; continue;
#if defined(DEBUG) #if defined(DEBUG)
printf( " %s %s\n", CONV_TO_UTF8(Cmp->m_Field[REFERENCE].m_Text), printf( " %s %s\n", CONV_TO_UTF8(Cmp->m_Field[REFERENCE].m_Text),
CONV_TO_UTF8(Cmp->m_Field[VALUE].m_Text) ); CONV_TO_UTF8(Cmp->m_Field[VALUE].m_Text) );
#endif #endif
TextField = &Cmp->m_Field[FOOTPRINT]; TextField = &Cmp->m_Field[FOOTPRINT];
......
...@@ -293,9 +293,7 @@ SCH_COMPONENT::SCH_COMPONENT( const wxPoint& aPos ) : ...@@ -293,9 +293,7 @@ SCH_COMPONENT::SCH_COMPONENT( const wxPoint& aPos ) :
m_Pos = aPos; m_Pos = aPos;
//m_FlagControlMulti = 0; m_Convert = 0; /* De Morgan Handling */
m_UsedOnSheets.Clear();
m_Convert = 0; /* Gestion des mutiples representations (conversion De Morgan) */
/* The rotation/mirror transformation matrix. pos normal*/ /* The rotation/mirror transformation matrix. pos normal*/
m_Transform[0][0] = 1; m_Transform[0][0] = 1;
...@@ -469,32 +467,40 @@ void SCH_COMPONENT::ClearAnnotation( DrawSheetPath* aSheet ) ...@@ -469,32 +467,40 @@ void SCH_COMPONENT::ClearAnnotation( DrawSheetPath* aSheet )
defRef.Append( wxT( "?" ) ); defRef.Append( wxT( "?" ) );
wxString multi = wxT( "1" ); wxString multi = wxT( "1" );
wxString NewHref;
wxString path; if ( KeepMulti ) // We cannot remove all annotations: part selection must be kept
if( aSheet )
path = GetPath( aSheet );;
for( unsigned int ii = 0; ii< m_PathsAndReferences.GetCount(); ii++ )
{ {
// Break hierachical reference in path, ref and multi selection: wxString NewHref;
reference_fields = wxStringTokenize( m_PathsAndReferences[ii], separators ); wxString path;
if( aSheet == NULL || reference_fields[0].Cmp( path ) == 0 ) if( aSheet )
path = GetPath( aSheet );;
for( unsigned int ii = 0; ii< m_PathsAndReferences.GetCount(); ii++ )
{ {
if( KeepMulti ) // Get and keep part selection // Break hierachical reference in path, ref and multi selection:
multi = reference_fields[2]; reference_fields = wxStringTokenize( m_PathsAndReferences[ii], separators );
NewHref = reference_fields[0]; if( aSheet == NULL || reference_fields[0].Cmp( path ) == 0 )
NewHref << wxT( " " ) << defRef << wxT( " " ) << multi; {
m_PathsAndReferences[ii] = NewHref; if( KeepMulti ) // Get and keep part selection
multi = reference_fields[2];
NewHref = reference_fields[0];
NewHref << wxT( " " ) << defRef << wxT( " " ) << multi;
m_PathsAndReferences[ii] = NewHref;
}
} }
} }
else
{
m_PathsAndReferences.Empty(); // Empty strings, but does not free memory because a new annotation will reuse it
m_Multi = 1;
}
// These 2 changes do not work in complex hierarchy. // These 2 changes do not work in complex hierarchy.
// When a clear annotation is made, the calling function must call a // When a clear annotation is made, the calling function must call a
// UpdateAllScreenReferences for the active sheet. // UpdateAllScreenReferences for the active sheet.
// But this call does not made here. // But this call cannot made here.
m_Field[REFERENCE].m_Text = defRef; //for drawing. m_Field[REFERENCE].m_Text = defRef; //for drawing.
if( !KeepMulti )
m_Multi = 1;
} }
...@@ -510,8 +516,6 @@ SCH_COMPONENT* SCH_COMPONENT::GenCopy() ...@@ -510,8 +516,6 @@ SCH_COMPONENT* SCH_COMPONENT::GenCopy()
new_item->m_ChipName = m_ChipName; new_item->m_ChipName = m_ChipName;
new_item->m_PrefixString = m_PrefixString; new_item->m_PrefixString = m_PrefixString;
//new_item->m_FlagControlMulti = m_FlagControlMulti;
new_item->m_UsedOnSheets = m_UsedOnSheets;
new_item->m_Convert = m_Convert; new_item->m_Convert = m_Convert;
new_item->m_Transform[0][0] = m_Transform[0][0]; new_item->m_Transform[0][0] = m_Transform[0][0];
new_item->m_Transform[0][1] = m_Transform[0][1]; new_item->m_Transform[0][1] = m_Transform[0][1];
......
...@@ -100,8 +100,6 @@ public: ...@@ -100,8 +100,6 @@ public:
* determined, upon file load, by the first non-digits in the reference fields. */ * determined, upon file load, by the first non-digits in the reference fields. */
PartTextStruct m_Field[NUMBER_OF_FIELDS]; PartTextStruct m_Field[NUMBER_OF_FIELDS];
//int m_FlagControlMulti;
ArrayOfSheetLists m_UsedOnSheets; // Used as flags when calculating netlist
int m_Convert; /* Gestion (management) des mutiples representations (ex: conversion De Morgan) */ int m_Convert; /* Gestion (management) des mutiples representations (ex: conversion De Morgan) */
int m_Transform[2][2]; /* The rotation/mirror transformation matrix. */ int m_Transform[2][2]; /* The rotation/mirror transformation matrix. */
......
...@@ -402,7 +402,7 @@ DanglingEndHandle* RebuildEndList( EDA_BaseStruct* DrawList ) ...@@ -402,7 +402,7 @@ DanglingEndHandle* RebuildEndList( EDA_BaseStruct* DrawList )
#undef STRUCT #undef STRUCT
#define STRUCT ( (SCH_COMPONENT*) DrawItem ) #define STRUCT ( (SCH_COMPONENT*) DrawItem )
EDA_LibComponentStruct* Entry; EDA_LibComponentStruct* Entry;
Entry = FindLibPart( STRUCT->m_ChipName, wxEmptyString, FIND_ROOT ); Entry = FindLibPart( STRUCT->m_ChipName.GetData(), wxEmptyString, FIND_ROOT );
if( Entry == NULL ) if( Entry == NULL )
break; break;
......
...@@ -691,13 +691,6 @@ void WinEDA_Build_BOM_Frame::GenereListeOfItems( const wxString& FullFileName ) ...@@ -691,13 +691,6 @@ void WinEDA_Build_BOM_Frame::GenereListeOfItems( const wxString& FullFileName )
GenListeCmp( List ); GenListeCmp( List );
#if 0
for( int i = 0; i<NbItems; i++ )
{
printf( "found component: %s\n", List[i].m_Ref );
}
#endif
/* generation du fichier listing */ /* generation du fichier listing */
DateAndTime( Line ); DateAndTime( Line );
wxString Title = g_Main_Title + wxT( " " ) + GetBuildVersion(); wxString Title = g_Main_Title + wxT( " " ) + GetBuildVersion();
...@@ -707,13 +700,7 @@ void WinEDA_Build_BOM_Frame::GenereListeOfItems( const wxString& FullFileName ) ...@@ -707,13 +700,7 @@ void WinEDA_Build_BOM_Frame::GenereListeOfItems( const wxString& FullFileName )
qsort( List, NbItems, sizeof( ListComponent ), qsort( List, NbItems, sizeof( ListComponent ),
( int( * ) ( const void*, const void* ) )ListTriComposantByRef ); ( int( * ) ( const void*, const void* ) )ListTriComposantByRef );
#if 0
printf( "sorted by reference:\n" );
for( int i = 0; i<NbItems; i++ )
{
printf( "found component: %s\n", List[i].m_Ref );
}
#endif
// if( ! s_ListWithSubCmponents ) // if( ! s_ListWithSubCmponents )
if( !m_ListSubCmpItems->GetValue() ) if( !m_ListSubCmpItems->GetValue() )
DeleteSubCmp( List, NbItems ); DeleteSubCmp( List, NbItems );
...@@ -785,20 +772,17 @@ void WinEDA_Build_BOM_Frame::GenereListeOfItems( const wxString& FullFileName ) ...@@ -785,20 +772,17 @@ void WinEDA_Build_BOM_Frame::GenereListeOfItems( const wxString& FullFileName )
int GenListeCmp( ListComponent* List ) int GenListeCmp( ListComponent* List )
/****************************************/ /****************************************/
/* Routine de generation de la liste des elements utiles du dessin /* Creates the list of components in the schematic
* Si List == NULL: comptage des elements
* Sinon remplissage de la liste
* Initialise "FlagControlMulti" a SheetNumber pour la sortie des listes
* et m_Father comme pointeur sur la sheet d'appartenance
* *
* routine for generating a list of the used components. * routine for generating a list of the used components.
* if List == null, just returns the count. if not, fills the list. * if List == null, just returns the count. if not, fills the list.
* goes through the sheets, not the screens, so that we account for * goes through the sheets, not the screens, so that we account for
* multiple instances of a given screen. * multiple instances of a given screen.
* Also Initialise m_Father as pointer pointeur of the SCH_SCREN parent
*/ */
{ {
int ItemCount = 0; int ItemCount = 0;
EDA_BaseStruct* DrawList; EDA_BaseStruct* SchItem;
SCH_COMPONENT* DrawLibItem; SCH_COMPONENT* DrawLibItem;
DrawSheetPath* sheet; DrawSheetPath* sheet;
...@@ -807,31 +791,23 @@ int GenListeCmp( ListComponent* List ) ...@@ -807,31 +791,23 @@ int GenListeCmp( ListComponent* List )
for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() )
{ {
DrawList = sheet->LastDrawList(); for ( SchItem = sheet->LastDrawList(); SchItem;SchItem = SchItem->Next() )
while( DrawList )
{ {
switch( DrawList->Type() ) if( SchItem->Type() != TYPE_SCH_COMPONENT )
{ continue;
case TYPE_SCH_COMPONENT:
ItemCount++;
DrawLibItem = (SCH_COMPONENT*) DrawList;
DrawLibItem->m_Parent = sheet->LastScreen();
if( List )
{
List->m_Comp = DrawLibItem;
List->m_SheetList = *sheet;
strncpy( List->m_Ref,
CONV_TO_UTF8( DrawLibItem->GetRef( sheet ) ),
sizeof( List->m_Ref ) );
List++;
}
break;
default: ItemCount++;
break; DrawLibItem = (SCH_COMPONENT*) SchItem;
DrawLibItem->m_Parent = sheet->LastScreen();
if( List )
{
List->m_Comp = DrawLibItem;
List->m_SheetList = *sheet;
strncpy( List->m_Ref,
CONV_TO_UTF8( DrawLibItem->GetRef( sheet ) ),
sizeof( List->m_Ref ) );
List++;
} }
DrawList = DrawList->Pnext;
} }
} }
......
...@@ -23,19 +23,24 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f, bool use_ ...@@ -23,19 +23,24 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f, bool use_
static void WriteGENERICListOfNets( FILE* f, ObjetNetListStruct* ObjNet ); static void WriteGENERICListOfNets( FILE* f, ObjetNetListStruct* ObjNet );
static void AddPinToComponentPinList( SCH_COMPONENT* Component, static void AddPinToComponentPinList( SCH_COMPONENT* Component,
DrawSheetPath* sheet, DrawSheetPath* sheet,
LibDrawPin* PinEntry ); LibDrawPin* PinEntry );
static void FindOthersUnits( SCH_COMPONENT* Component, DrawSheetPath* Sheet_in); static void FindAllsInstancesOfComponent( SCH_COMPONENT* Component,
EDA_LibComponentStruct* Entry,
DrawSheetPath* Sheet_in );
static int SortPinsByNum( ObjetNetListStruct** Pin1, ObjetNetListStruct** Pin2 ); static int SortPinsByNum( ObjetNetListStruct** Pin1, ObjetNetListStruct** Pin2 );
static void EraseDuplicatePins( ObjetNetListStruct** TabPin, int NbrPin ); static void EraseDuplicatePins( ObjetNetListStruct** TabPin, int NbrPin );
static void ClearUsedFlags( WinEDA_SchematicFrame* frame ); static void ClearUsedFlags( void );
/* Variable locales */ /* Local variables */
static int s_SortedPinCount; static int s_SortedPinCount;
static ObjetNetListStruct** s_SortedComponentPinList; static ObjetNetListStruct** s_SortedComponentPinList;
// list of references arready found for multi part per packages components
// (used to avoid to used more than one time a component)
static wxArrayString s_ReferencesAlreadyFound;
/******************************************************************************/ /******************************************************************************/
void WriteNetList( WinEDA_SchematicFrame* frame, const wxString& FileNameNL, void WriteNetList( WinEDA_SchematicFrame* frame, const wxString& FileNameNL,
...@@ -82,16 +87,16 @@ void WriteNetList( WinEDA_SchematicFrame* frame, const wxString& FileNameNL, ...@@ -82,16 +87,16 @@ void WriteNetList( WinEDA_SchematicFrame* frame, const wxString& FileNameNL,
fclose( f ); fclose( f );
break; break;
default: default:
Write_GENERIC_NetList( frame, FileNameNL ); Write_GENERIC_NetList( frame, FileNameNL );
break; break;
} }
} }
/****************************************************************************/ /****************************************************************************/
static SCH_COMPONENT* FindNextComponentAndCreatPinList( static SCH_COMPONENT* FindNextComponentAndCreatPinList(
EDA_BaseStruct* DrawList, DrawSheetPath* sheet) EDA_BaseStruct* DrawList, DrawSheetPath* sheet )
/****************************************************************************/ /****************************************************************************/
/* Find a "suitable" component from the DrawList /* Find a "suitable" component from the DrawList
...@@ -103,7 +108,7 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList( ...@@ -103,7 +108,7 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList(
* Must be deallocated by the user * Must be deallocated by the user
*/ */
{ {
SCH_COMPONENT* Component = NULL; SCH_COMPONENT* Component = NULL;
EDA_LibComponentStruct* Entry; EDA_LibComponentStruct* Entry;
LibEDA_BaseStruct* DEntry; LibEDA_BaseStruct* DEntry;
...@@ -115,15 +120,12 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList( ...@@ -115,15 +120,12 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList(
continue; continue;
Component = (SCH_COMPONENT*) DrawList; Component = (SCH_COMPONENT*) DrawList;
/* already tested ? : */ /* Power symbol and other component which have the reference starting by
bool found = false; * "#" are not included in netlist (pseudo or virtual components) */
for(unsigned int i =0; i<Component->m_UsedOnSheets.GetCount(); i++){ wxString str = Component->GetRef( sheet );
if( Component->m_UsedOnSheets.Item(i) == *sheet ){ if( str[0] == '#' ) // ignore it
found = true; continue;
break;
}
}
if( found ) continue;
//if( Component->m_FlagControlMulti == 1 ) //if( Component->m_FlagControlMulti == 1 )
// continue; /* yes */ // continue; /* yes */
// removed because with multiple instances of one schematic // removed because with multiple instances of one schematic
...@@ -133,11 +135,26 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList( ...@@ -133,11 +135,26 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList(
if( Entry == NULL ) if( Entry == NULL )
continue; continue;
/* Power symbol and other component which have the reference starting by if( Entry->m_UnitCount > 1 ) // Multi parts per package: test if already visited:
* "#" are not included in netlist (pseudo components) */ {
wxString str = Component->GetRef(sheet); bool found = false;
if( str[0] == '#' ) for( unsigned jj = 0; jj < s_ReferencesAlreadyFound.GetCount(); jj++ )
continue; {
if( str == s_ReferencesAlreadyFound[jj] ) // Already visited
{
found = true;
break;
}
}
if( found )
continue;
else
{
s_ReferencesAlreadyFound.Add( str ); // Mark as visited
}
}
/* Create the pin table for this component */ /* Create the pin table for this component */
int ii = sizeof(ObjetNetListStruct*) * MAXPIN; int ii = sizeof(ObjetNetListStruct*) * MAXPIN;
...@@ -146,32 +163,31 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList( ...@@ -146,32 +163,31 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList(
memset( s_SortedComponentPinList, 0, ii ); memset( s_SortedComponentPinList, 0, ii );
DEntry = Entry->m_Drawings; DEntry = Entry->m_Drawings;
for( ; DEntry != NULL; DEntry = DEntry->Next() ) if( Entry->m_UnitCount <= 1 ) // One part per package
{ {
if( DEntry->Type() != COMPONENT_PIN_DRAW_TYPE ) for( ; DEntry != NULL; DEntry = DEntry->Next() )
continue;
if( DEntry->m_Unit
&& (DEntry->m_Unit != Component->m_Multi) )
continue;
if( DEntry->m_Convert
&& (DEntry->m_Convert != Component->m_Convert) )
continue;
{ {
AddPinToComponentPinList( Component, sheet, (LibDrawPin*) DEntry ); if( DEntry->Type() != COMPONENT_PIN_DRAW_TYPE )
continue;
if( DEntry->m_Unit
&& ( DEntry->m_Unit != Component->GetUnitSelection( sheet ) ) )
continue;
if( DEntry->m_Convert
&& (DEntry->m_Convert != Component->m_Convert) )
continue;
{
AddPinToComponentPinList( Component, sheet, (LibDrawPin*) DEntry );
}
} }
} }
else // Multiple parts per package: Collect all parts ans pins for this reference
FindAllsInstancesOfComponent( Component, Entry, sheet );
//Component->m_FlagControlMulti = 1; /* Sort Pins in s_SortedComponentPinList by pin number */
Component->m_UsedOnSheets.Add(*sheet);
if( Entry->m_UnitCount > 1 )
FindOthersUnits( Component, sheet);
/* Tri sur le numero de Pin de TabListePin */
qsort( s_SortedComponentPinList, s_SortedPinCount, sizeof(ObjetNetListStruct*), qsort( s_SortedComponentPinList, s_SortedPinCount, sizeof(ObjetNetListStruct*),
( int( * ) ( const void*, const void* ) )SortPinsByNum ); ( int( * ) ( const void*, const void* ) )SortPinsByNum );
/* Elimination des Pins redondantes du s_SortedComponentPinList */ /* Remove duplicate Pins in s_SortedComponentPinList */
EraseDuplicatePins( s_SortedComponentPinList, s_SortedPinCount ); EraseDuplicatePins( s_SortedComponentPinList, s_SortedPinCount );
return Component; return Component;
...@@ -209,7 +225,7 @@ static wxString ReturnPinNetName( ObjetNetListStruct* Pin, ...@@ -209,7 +225,7 @@ static wxString ReturnPinNetName( ObjetNetListStruct* Pin,
continue; continue;
if( ( g_TabObjNet[jj].m_Type != NET_HIERLABEL) if( ( g_TabObjNet[jj].m_Type != NET_HIERLABEL)
&& ( g_TabObjNet[jj].m_Type != NET_LABEL) && ( g_TabObjNet[jj].m_Type != NET_LABEL)
&& ( g_TabObjNet[jj].m_Type != NET_PINLABEL) ) && ( g_TabObjNet[jj].m_Type != NET_PINLABEL) )
continue; continue;
NetName = *g_TabObjNet[jj].m_Label; NetName = *g_TabObjNet[jj].m_Label;
...@@ -218,11 +234,13 @@ static wxString ReturnPinNetName( ObjetNetListStruct* Pin, ...@@ -218,11 +234,13 @@ static wxString ReturnPinNetName( ObjetNetListStruct* Pin,
if( !NetName.IsEmpty() ) if( !NetName.IsEmpty() )
{ {
if( g_TabObjNet[jj].m_Type != NET_PINLABEL ){ if( g_TabObjNet[jj].m_Type != NET_PINLABEL )
{
NetName = g_TabObjNet[jj].m_SheetList.PathHumanReadable() NetName = g_TabObjNet[jj].m_SheetList.PathHumanReadable()
+ NetName; + NetName;
} }
//NetName << wxT("_") << g_TabObjNet[jj].m_SheetList.PathHumanReadable();
//NetName << wxT("_") << g_TabObjNet[jj].m_SheetList.PathHumanReadable();
} }
else else
{ {
...@@ -232,6 +250,7 @@ static wxString ReturnPinNetName( ObjetNetListStruct* Pin, ...@@ -232,6 +250,7 @@ static wxString ReturnPinNetName( ObjetNetListStruct* Pin,
return NetName; return NetName;
} }
/***********************************************************************/ /***********************************************************************/
void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame, void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame,
const wxString& FullFileName ) const wxString& FullFileName )
...@@ -239,17 +258,16 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame, ...@@ -239,17 +258,16 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame,
/* Create a generic netlist, and call an external netlister /* Create a generic netlist, and call an external netlister
* to change the netlist syntax and create the file * to change the netlist syntax and create the file
* -- does this still work?
*/ */
{ {
wxString Line, FootprintName; wxString Line, FootprintName;
DrawSheetPath* sheet; DrawSheetPath* sheet;
EDA_BaseStruct* DrawList; EDA_BaseStruct* SchItem;
SCH_COMPONENT* Component; SCH_COMPONENT* Component;
wxString netname; wxString netname;
int ii; int ii;
FILE* tmpfile; FILE* tmpfile;
wxString TmpFullFileName = FullFileName; wxString TmpFullFileName = FullFileName;
ChangeFileNameExt( TmpFullFileName, wxT( ".tmp" ) ); ChangeFileNameExt( TmpFullFileName, wxT( ".tmp" ) );
...@@ -260,7 +278,7 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame, ...@@ -260,7 +278,7 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame,
return; return;
} }
ClearUsedFlags( frame ); /* Reset the flags FlagControlMulti in all schematic files*/ ClearUsedFlags( ); /* Reset the flags FlagControlMulti in all schematic files*/
fprintf( tmpfile, "$BeginNetlist\n" ); fprintf( tmpfile, "$BeginNetlist\n" );
/* Create netlist module section */ /* Create netlist module section */
...@@ -269,12 +287,12 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame, ...@@ -269,12 +287,12 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame,
for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() )
{ {
for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Pnext ) for( SchItem = sheet->LastDrawList(); SchItem != NULL; SchItem = SchItem->Pnext )
{ {
DrawList = Component = FindNextComponentAndCreatPinList( DrawList, sheet ); SchItem = Component = FindNextComponentAndCreatPinList( SchItem, sheet );
if( Component == NULL ) if( Component == NULL )
break; // No component left break; // No component left
FootprintName.Empty(); FootprintName.Empty();
if( !Component->m_Field[FOOTPRINT].IsVoid() ) if( !Component->m_Field[FOOTPRINT].IsVoid() )
...@@ -286,7 +304,7 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame, ...@@ -286,7 +304,7 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame,
fprintf( tmpfile, "\n$BeginComponent\n" ); fprintf( tmpfile, "\n$BeginComponent\n" );
fprintf( tmpfile, "TimeStamp=%8.8lX\n", Component->m_TimeStamp ); fprintf( tmpfile, "TimeStamp=%8.8lX\n", Component->m_TimeStamp );
fprintf( tmpfile, "Footprint=%s\n", CONV_TO_UTF8( FootprintName ) ); fprintf( tmpfile, "Footprint=%s\n", CONV_TO_UTF8( FootprintName ) );
Line = wxT( "Reference=" ) + Component->GetRef(sheet) + wxT( "\n" ); Line = wxT( "Reference=" ) + Component->GetRef( sheet ) + wxT( "\n" );
Line.Replace( wxT( " " ), wxT( "_" ) ); Line.Replace( wxT( " " ), wxT( "_" ) );
fprintf( tmpfile, CONV_TO_UTF8( Line ) ); fprintf( tmpfile, CONV_TO_UTF8( Line ) );
...@@ -346,30 +364,12 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame, ...@@ -346,30 +364,12 @@ void Write_GENERIC_NetList( WinEDA_SchematicFrame* frame,
} }
/********************************************************/ /**********************************/
static void ClearUsedFlags( WinEDA_SchematicFrame* frame ) static void ClearUsedFlags( void )
/********************************************************/ /*********************************/
/* Clear flag list, used in netlist generation */ /* Clear flag list, used in netlist generation */
{ {
SCH_SCREEN* screen; s_ReferencesAlreadyFound.Clear();
EDA_BaseStruct* DrawList;
EDA_ScreenList ScreenList;
for( screen = ScreenList.GetFirst(); screen != NULL; screen = ScreenList.GetNext() )
{
DrawList = screen->EEDrawList;
while( DrawList )
{
if( DrawList->Type() == TYPE_SCH_COMPONENT )
{
SCH_COMPONENT* Component = (SCH_COMPONENT*) DrawList;
//Component->m_FlagControlMulti = 0;
Component->m_UsedOnSheets.Clear();
}
DrawList = DrawList->Pnext;
}
}
} }
...@@ -384,22 +384,22 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f, ...@@ -384,22 +384,22 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f,
* sinon les nodes sont identifies par le netnumber * sinon les nodes sont identifies par le netnumber
* *
* tous les textes graphiques commen�ant par [.-+]pspice ou [.-+]gnucap * tous les textes graphiques commen�ant par [.-+]pspice ou [.-+]gnucap
* sont consid�r�s comme des commandes a placer dans la netliste * sont consideres comme des commandes a placer dans la netliste
* [.-]pspice ou gnucap sont en debut * [.-]pspice ou gnucap sont en debut
+pspice et +gnucap sont en fin de netliste +pspice et +gnucap sont en fin de netliste
*/ */
{ {
char Line[1024]; char Line[1024];
DrawSheetPath* sheet; DrawSheetPath* sheet;
EDA_BaseStruct* DrawList; EDA_BaseStruct* DrawList;
SCH_COMPONENT* Component; SCH_COMPONENT* Component;
int ii, nbitems; int ii, nbitems;
wxString text; wxString text;
wxArrayString SpiceCommandAtBeginFile, SpiceCommandAtEndFile; wxArrayString SpiceCommandAtBeginFile, SpiceCommandAtEndFile;
wxString msg; wxString msg;
#define BUFYPOS_LEN 4 #define BUFYPOS_LEN 4
wxChar bufnum[BUFYPOS_LEN + 1]; wxChar bufnum[BUFYPOS_LEN + 1];
DateAndTime( Line ); DateAndTime( Line );
fprintf( f, "* %s (Spice format) creation date: %s\n\n", NETLIST_HEAD_STRING, Line ); fprintf( f, "* %s (Spice format) creation date: %s\n\n", NETLIST_HEAD_STRING, Line );
...@@ -417,7 +417,7 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f, ...@@ -417,7 +417,7 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f,
if( DrawList->Type() != TYPE_SCH_TEXT ) if( DrawList->Type() != TYPE_SCH_TEXT )
continue; continue;
#define DRAWTEXT ( (SCH_TEXT*) DrawList ) #define DRAWTEXT ( (SCH_TEXT*) DrawList )
text = DRAWTEXT->m_Text; if( text.IsEmpty() ) text = DRAWTEXT->m_Text; if( text.IsEmpty() )
continue; continue;
ident = text.GetChar( 0 ); ident = text.GetChar( 0 );
if( ident != '.' && ident != '-' && ident != '+' ) if( ident != '.' && ident != '-' && ident != '+' )
...@@ -461,7 +461,7 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f, ...@@ -461,7 +461,7 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f,
/* Create component list */ /* Create component list */
ClearUsedFlags( frame ); /* Reset the flags FlagControlMulti in all schematic files*/ ClearUsedFlags(); /* Reset the flags FlagControlMulti in all schematic files*/
for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() )
{ {
for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Pnext ) for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Pnext )
...@@ -524,7 +524,7 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with ...@@ -524,7 +524,7 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with
/*****************************************************************************************/ /*****************************************************************************************/
/* Routine de generation du fichier netliste ( Format ORCAD PCB 2 ameliore ) /* Routine de generation du fichier netliste ( Format ORCAD PCB 2 ameliore )
* si with_pcbnew = FALSE * si with_pcbnew = TRUE
* format PCBNEW (OrcadPcb2 + commentaires et liste des nets) * format PCBNEW (OrcadPcb2 + commentaires et liste des nets)
* si with_pcbnew = FALSE * si with_pcbnew = FALSE
* Format ORCADPCB2 strict * Format ORCADPCB2 strict
...@@ -546,8 +546,8 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with ...@@ -546,8 +546,8 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with
fprintf( f, "( { %s created %s }\n", NETLIST_HEAD_STRING, Buf ); fprintf( f, "( { %s created %s }\n", NETLIST_HEAD_STRING, Buf );
/* Create netlist module section */ /* Create netlist module section */
ClearUsedFlags( frame ); /* Reset the flags FlagControlMulti in all schematic files*/ ClearUsedFlags( ); /* Reset the flags FlagControlMulti in all schematic files*/
EDA_SheetList SheetList( NULL ); EDA_SheetList SheetList( NULL );
...@@ -555,7 +555,7 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with ...@@ -555,7 +555,7 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with
{ {
for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Pnext ) for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Pnext )
{ {
DrawList = Component = FindNextComponentAndCreatPinList( DrawList, sheet); DrawList = Component = FindNextComponentAndCreatPinList( DrawList, sheet );
if( Component == NULL ) if( Component == NULL )
break; break;
...@@ -566,9 +566,10 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with ...@@ -566,9 +566,10 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with
{ {
if( Entry->m_FootprintList.GetCount() != 0 ) /* Put in list */ if( Entry->m_FootprintList.GetCount() != 0 ) /* Put in list */
{ {
if( CmpList == NULL ){ if( CmpList == NULL )
{
CmpList = (ListComponent*) CmpList = (ListComponent*)
MyZMalloc( sizeof(ListComponent) * CmpListSize ); MyZMalloc( sizeof(ListComponent) * CmpListSize );
} }
if( CmpListCount >= CmpListSize ) if( CmpListCount >= CmpListSize )
{ {
...@@ -578,7 +579,7 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with ...@@ -578,7 +579,7 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with
sizeof(ListComponent) * CmpListSize ); sizeof(ListComponent) * CmpListSize );
} }
CmpList[CmpListCount].m_Comp = Component; CmpList[CmpListCount].m_Comp = Component;
strcpy(CmpList[CmpListCount].m_Ref, Component->GetRef( sheet ).mb_str()); strcpy( CmpList[CmpListCount].m_Ref, Component->GetRef( sheet ).mb_str() );
CmpListCount++; CmpListCount++;
} }
} }
...@@ -591,9 +592,9 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with ...@@ -591,9 +592,9 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with
else else
FootprintName = wxT( "$noname" ); FootprintName = wxT( "$noname" );
Line = Component->GetRef(sheet); Line = Component->GetRef( sheet );
fprintf( f, " ( %s %s", fprintf( f, " ( %s %s",
CONV_TO_UTF8(Component->GetPath(sheet)), CONV_TO_UTF8( Component->GetPath( sheet ) ),
CONV_TO_UTF8( FootprintName ) ); CONV_TO_UTF8( FootprintName ) );
fprintf( f, " %s", CONV_TO_UTF8( Line ) ); fprintf( f, " %s", CONV_TO_UTF8( Line ) );
...@@ -640,13 +641,16 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with ...@@ -640,13 +641,16 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with
{ {
Component = CmpList[ii].m_Comp; Component = CmpList[ii].m_Comp;
Entry = FindLibPart( Component->m_ChipName.GetData(), wxEmptyString, FIND_ROOT ); Entry = FindLibPart( Component->m_ChipName.GetData(), wxEmptyString, FIND_ROOT );
//Line.Printf(_("%s"), CmpList[ii].m_Ref); //Line.Printf(_("%s"), CmpList[ii].m_Ref);
//Line.Replace( wxT( " " ), wxT( "_" ) ); //Line.Replace( wxT( " " ), wxT( "_" ) );
unsigned int i; unsigned int i;
for(i=0; i<sizeof(CmpList[ii].m_Ref) && CmpList[ii].m_Ref[i]; i++){ for( i = 0; i<sizeof(CmpList[ii].m_Ref) && CmpList[ii].m_Ref[i]; i++ )
if(CmpList[ii].m_Ref[i] == ' ') {
if( CmpList[ii].m_Ref[i] == ' ' )
CmpList[ii].m_Ref[i] = '_'; CmpList[ii].m_Ref[i] = '_';
} }
fprintf( f, "$component %s\n", CmpList[ii].m_Ref ); fprintf( f, "$component %s\n", CmpList[ii].m_Ref );
/* Write the footprint list */ /* Write the footprint list */
for( unsigned int jj = 0; jj < Entry->m_FootprintList.GetCount(); jj++ ) for( unsigned int jj = 0; jj < Entry->m_FootprintList.GetCount(); jj++ )
...@@ -714,10 +718,12 @@ static void EraseDuplicatePins( ObjetNetListStruct** TabPin, int NbrPin ) ...@@ -714,10 +718,12 @@ static void EraseDuplicatePins( ObjetNetListStruct** TabPin, int NbrPin )
/**********************************************************************/ /**********************************************************************/
/* /*
* Routine qui elimine les Pins de meme Numero de la liste des objets * Function to remove duplicate Pins in the TabPin pin list
* (Liste des Pins d'un boitier) passee en entree * (This is a list of pins found in the whole schematic, for a given component)
* Ces pins redondantes proviennent des pins (alims... ) communes a plusieurs * These duplicate pins were put in list because some pins (powers... )
* elements d'un boitier a multiple parts. * are found more than one time when we have a multiple parts per package component
* for instance, a 74ls00 has 4 parts, and therefor the VCC pin and GND pin apperas 4 times
* in the list.
*/ */
{ {
int ii, jj; int ii, jj;
...@@ -725,7 +731,7 @@ static void EraseDuplicatePins( ObjetNetListStruct** TabPin, int NbrPin ) ...@@ -725,7 +731,7 @@ static void EraseDuplicatePins( ObjetNetListStruct** TabPin, int NbrPin )
for( ii = 0; ii < NbrPin - 1; ii++ ) for( ii = 0; ii < NbrPin - 1; ii++ )
{ {
if( TabPin[ii] == NULL ) if( TabPin[ii] == NULL )
continue; /* Deja supprime */ continue; /* Deja supprime */
if( TabPin[ii]->m_PinNum != TabPin[ii + 1]->m_PinNum ) if( TabPin[ii]->m_PinNum != TabPin[ii + 1]->m_PinNum )
continue; continue;
/* 2 Pins doublees */ /* 2 Pins doublees */
...@@ -739,82 +745,56 @@ static void EraseDuplicatePins( ObjetNetListStruct** TabPin, int NbrPin ) ...@@ -739,82 +745,56 @@ static void EraseDuplicatePins( ObjetNetListStruct** TabPin, int NbrPin )
} }
/**********************************************************************/ /**********************************************************************************/
static void FindOthersUnits( SCH_COMPONENT* Component_in, DrawSheetPath* Sheet_in) static void FindAllsInstancesOfComponent( SCH_COMPONENT* Component_in,
/**********************************************************************/ EDA_LibComponentStruct* Entry,
DrawSheetPath* Sheet_in )
/**********************************************************************************/
/* Recherche les autres parts du boitier auquel appartient la part Component, /**
* pour les boitiers a parts multiples. * Used for multiple parts per package components
* Appelle AddPinToComponentPinList() pour classer les pins des parts trouvees * Search all instances of Component_in,
* Calls AddPinToComponentPinList() to and pins founds to the current component pin list
*/ */
{ {
EDA_BaseStruct* DrawList; EDA_BaseStruct* SchItem;
SCH_COMPONENT* Component2; SCH_COMPONENT* Component2;
EDA_LibComponentStruct* Entry;
LibEDA_BaseStruct* DEntry; LibEDA_BaseStruct* DEntry;
DrawSheetPath* sheet; DrawSheetPath* sheet;
wxString str; wxString str, Reference = Component_in->GetRef( Sheet_in );
EDA_SheetList SheetList( NULL ); EDA_SheetList SheetList( NULL );
unsigned int i;
bool found;
for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() )
{ {
DrawList = sheet->LastDrawList(); for( SchItem = sheet->LastDrawList(); SchItem; SchItem = SchItem->Pnext )
while( DrawList )
{ {
switch( DrawList->Type() ) if( SchItem->Type() != TYPE_SCH_COMPONENT )
{ continue;
case TYPE_SCH_COMPONENT:
Component2 = (SCH_COMPONENT*) DrawList;
found = false;
for( i =0; i<Component2->m_UsedOnSheets.GetCount(); i++){
if( Component2->m_UsedOnSheets.Item(i) == *Sheet_in ){
found = true;
}
}
if( found ) break;
//if( Component2->m_FlagControlMulti == 1 ) //has it been used? (on this sheet?)
// break;
str = Component2->GetRef(sheet);
if( str.CmpNoCase( Component_in->GetRef(Sheet_in) ) != 0 )
break;
Entry = FindLibPart( Component2->m_ChipName.GetData(), wxEmptyString, FIND_ROOT ); Component2 = (SCH_COMPONENT*) SchItem;
if( Entry == NULL )
break;
if( str[0] == '#' ) str = Component2->GetRef( sheet );
break; if( str.CmpNoCase( Reference ) != 0 )
continue;
if( Entry->m_Drawings != NULL ) if( Entry && Entry->m_Drawings != NULL )
{
DEntry = Entry->m_Drawings;
for( ; DEntry != NULL; DEntry = DEntry->Next() )
{ {
DEntry = Entry->m_Drawings; if( DEntry->Type() != COMPONENT_PIN_DRAW_TYPE )
for( ; DEntry != NULL; DEntry = DEntry->Next() ) continue;
{ if( DEntry->m_Unit
if( DEntry->Type() != COMPONENT_PIN_DRAW_TYPE ) && ( DEntry->m_Unit != Component2->GetUnitSelection( sheet ) ) )
continue; continue;
if( DEntry->m_Unit if( DEntry->m_Convert
&& (DEntry->m_Unit != Component2->m_Multi) ) && (DEntry->m_Convert != Component2->m_Convert) )
continue; continue;
if( DEntry->m_Convert // A suitable pin in found: add it to the current list
&& (DEntry->m_Convert != Component2->m_Convert) ) AddPinToComponentPinList( Component2, sheet, (LibDrawPin*) DEntry );
continue;
{
AddPinToComponentPinList( Component2, sheet, (LibDrawPin*) DEntry );
}
}
} }
Component2->m_UsedOnSheets.Add(*Sheet_in);
//Component2->m_FlagControlMulti = 1; //mark it as used..
break;
default:
break;
} }
DrawList = DrawList->Pnext;
} }
} }
} }
...@@ -858,11 +838,11 @@ static void WriteGENERICListOfNets( FILE* f, ObjetNetListStruct* ObjNet ) ...@@ -858,11 +838,11 @@ static void WriteGENERICListOfNets( FILE* f, ObjetNetListStruct* ObjNet )
for( ii = 0; ii < g_NbrObjNet; ii++ ) for( ii = 0; ii < g_NbrObjNet; ii++ )
{ {
if( (NetCode = ObjNet[ii].GetNet()) != LastNetCode ) // New net found, write net id; if( ( NetCode = ObjNet[ii].GetNet() ) != LastNetCode ) // New net found, write net id;
{ {
SameNetcodeCount = 0; // Items count for this net SameNetcodeCount = 0; // Items count for this net
NetName.Empty(); NetName.Empty();
for( jj = 0; jj < g_NbrObjNet; jj++ ) // Find a label (if exists) for this net for( jj = 0; jj < g_NbrObjNet; jj++ ) // Find a label (if exists) for this net
{ {
if( ObjNet[jj].GetNet() != NetCode ) if( ObjNet[jj].GetNet() != NetCode )
continue; continue;
...@@ -879,10 +859,12 @@ static void WriteGENERICListOfNets( FILE* f, ObjetNetListStruct* ObjNet ) ...@@ -879,10 +859,12 @@ static void WriteGENERICListOfNets( FILE* f, ObjetNetListStruct* ObjNet )
if( !NetName.IsEmpty() ) if( !NetName.IsEmpty() )
{ {
NetcodeName += NetName; NetcodeName += NetName;
if( g_TabObjNet[jj].m_Type != NET_PINLABEL ){ if( g_TabObjNet[jj].m_Type != NET_PINLABEL )
{
// usual net name, add in the sheet path // usual net name, add in the sheet path
NetcodeName = g_TabObjNet[jj].m_SheetList.PathHumanReadable() NetcodeName = g_TabObjNet[jj].m_SheetList.PathHumanReadable()
+ NetcodeName; + NetcodeName;
//NetcodeName << wxT("_") << //NetcodeName << wxT("_") <<
// g_TabObjNet[jj].m_SheetList.PathHumanReadable(); // g_TabObjNet[jj].m_SheetList.PathHumanReadable();
} }
...@@ -895,9 +877,9 @@ static void WriteGENERICListOfNets( FILE* f, ObjetNetListStruct* ObjNet ) ...@@ -895,9 +877,9 @@ static void WriteGENERICListOfNets( FILE* f, ObjetNetListStruct* ObjNet )
continue; continue;
Cmp = (SCH_COMPONENT*) ObjNet[ii].m_Link; Cmp = (SCH_COMPONENT*) ObjNet[ii].m_Link;
CmpRef = Cmp->GetRef(&ObjNet[ii].m_SheetList); //is this correct? CmpRef = Cmp->GetRef( &ObjNet[ii].m_SheetList ); //is this correct?
if( CmpRef.StartsWith( wxT( "#" ) ) ) if( CmpRef.StartsWith( wxT( "#" ) ) )
continue; // Pseudo component (Like Power symbol) continue; // Pseudo component (Like Power symbol)
// Print the pin list for this net, if 2 or more items are connected: // Print the pin list for this net, if 2 or more items are connected:
SameNetcodeCount++; SameNetcodeCount++;
...@@ -971,14 +953,14 @@ static void WriteNetListCADSTAR( WinEDA_SchematicFrame* frame, FILE* f ) ...@@ -971,14 +953,14 @@ static void WriteNetListCADSTAR( WinEDA_SchematicFrame* frame, FILE* f )
fprintf( f, "\n" ); fprintf( f, "\n" );
/* Create netlist module section */ /* Create netlist module section */
ClearUsedFlags( frame ); /* Reset the flags FlagControlMulti in all schematic files*/ ClearUsedFlags( ); /* Reset the flags FlagControlMulti in all schematic files*/
EDA_SheetList SheetList( NULL ); EDA_SheetList SheetList( NULL );
for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() ) for( sheet = SheetList.GetFirst(); sheet != NULL; sheet = SheetList.GetNext() )
{ {
for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Pnext ) for( DrawList = sheet->LastDrawList(); DrawList != NULL; DrawList = DrawList->Pnext )
{ {
DrawList = Component = FindNextComponentAndCreatPinList( DrawList, sheet); DrawList = Component = FindNextComponentAndCreatPinList( DrawList, sheet );
if( Component == NULL ) if( Component == NULL )
break; break;
...@@ -990,7 +972,7 @@ static void WriteNetListCADSTAR( WinEDA_SchematicFrame* frame, FILE* f ) ...@@ -990,7 +972,7 @@ static void WriteNetListCADSTAR( WinEDA_SchematicFrame* frame, FILE* f )
else else
FootprintName = wxT( "$noname" ); FootprintName = wxT( "$noname" );
msg = Component->GetRef(sheet); msg = Component->GetRef( sheet );
fprintf( f, "%s ", CONV_TO_UTF8( StartCmpDesc ) ); fprintf( f, "%s ", CONV_TO_UTF8( StartCmpDesc ) );
fprintf( f, "%s", CONV_TO_UTF8( msg ) ); fprintf( f, "%s", CONV_TO_UTF8( msg ) );
...@@ -1038,7 +1020,7 @@ static void WriteListOfNetsCADSTAR( FILE* f, ObjetNetListStruct* ObjNet ) ...@@ -1038,7 +1020,7 @@ static void WriteListOfNetsCADSTAR( FILE* f, ObjetNetListStruct* ObjNet )
for( ii = 0; ii < g_NbrObjNet; ii++ ) for( ii = 0; ii < g_NbrObjNet; ii++ )
{ {
// Get the NetName of the current net : // Get the NetName of the current net :
if( (NetCode = ObjNet[ii].GetNet()) != LastNetCode ) if( ( NetCode = ObjNet[ii].GetNet() ) != LastNetCode )
{ {
NetName.Empty(); NetName.Empty();
for( jj = 0; jj < g_NbrObjNet; jj++ ) for( jj = 0; jj < g_NbrObjNet; jj++ )
...@@ -1057,9 +1039,11 @@ static void WriteListOfNetsCADSTAR( FILE* f, ObjetNetListStruct* ObjNet ) ...@@ -1057,9 +1039,11 @@ static void WriteListOfNetsCADSTAR( FILE* f, ObjetNetListStruct* ObjNet )
if( !NetName.IsEmpty() ) if( !NetName.IsEmpty() )
{ {
NetcodeName += NetName; NetcodeName += NetName;
if( g_TabObjNet[jj].m_Type != NET_PINLABEL ){ if( g_TabObjNet[jj].m_Type != NET_PINLABEL )
{
NetcodeName = g_TabObjNet[jj].m_SheetList.PathHumanReadable() NetcodeName = g_TabObjNet[jj].m_SheetList.PathHumanReadable()
+ NetcodeName; + NetcodeName;
//NetcodeName << wxT("_") << //NetcodeName << wxT("_") <<
// g_TabObjNet[jj].m_SheetList.PathHumanReadable(); // g_TabObjNet[jj].m_SheetList.PathHumanReadable();
} }
...@@ -1079,7 +1063,7 @@ static void WriteListOfNetsCADSTAR( FILE* f, ObjetNetListStruct* ObjNet ) ...@@ -1079,7 +1063,7 @@ static void WriteListOfNetsCADSTAR( FILE* f, ObjetNetListStruct* ObjNet )
continue; continue;
Cmp = (SCH_COMPONENT*) ObjNet[ii].m_Link; Cmp = (SCH_COMPONENT*) ObjNet[ii].m_Link;
wxString refstr = Cmp->GetRef(&(ObjNet[ii].m_SheetList)); wxString refstr = Cmp->GetRef( &(ObjNet[ii].m_SheetList) );
if( refstr[0] == '#' ) if( refstr[0] == '#' )
continue; // Pseudo composant (symboles d'alims) continue; // Pseudo composant (symboles d'alims)
...@@ -1127,9 +1111,9 @@ static void WriteListOfNetsCADSTAR( FILE* f, ObjetNetListStruct* ObjNet ) ...@@ -1127,9 +1111,9 @@ static void WriteListOfNetsCADSTAR( FILE* f, ObjetNetListStruct* ObjNet )
continue; continue;
SCH_COMPONENT* tstcmp = SCH_COMPONENT* tstcmp =
(SCH_COMPONENT*) ObjNet[jj].m_Link; (SCH_COMPONENT*) ObjNet[jj].m_Link;
wxString p = Cmp->GetPath( &( ObjNet[ii].m_SheetList ) ); wxString p = Cmp->GetPath( &( ObjNet[ii].m_SheetList ) );
wxString tstp = tstcmp->GetPath( &( ObjNet[jj].m_SheetList ) ); wxString tstp = tstcmp->GetPath( &( ObjNet[jj].m_SheetList ) );
if( p.Cmp(tstp) != 0 ) if( p.Cmp( tstp ) != 0 )
continue; continue;
if( ObjNet[jj].m_PinNum == ObjNet[ii].m_PinNum ) if( ObjNet[jj].m_PinNum == ObjNet[ii].m_PinNum )
......
...@@ -17,8 +17,7 @@ ...@@ -17,8 +17,7 @@
/* Routines locales */ /* Routines locales */
static void PropageNetCode( int OldNetCode, int NewNetCode, int IsBus ); static void PropageNetCode( int OldNetCode, int NewNetCode, int IsBus );
static void SheetLabelConnect( ObjetNetListStruct* SheetLabel ); static void SheetLabelConnect( ObjetNetListStruct* SheetLabel );
static int ListeObjetConnection( WinEDA_SchematicFrame* frame, static int ListeObjetConnection( DrawSheetPath* sheetlist,
DrawSheetPath* sheetlist,
ObjetNetListStruct* ObjNet ); ObjetNetListStruct* ObjNet );
static int ConvertBusToMembers( ObjetNetListStruct* ObjNet ); static int ConvertBusToMembers( ObjetNetListStruct* ObjNet );
static void PointToPointConnect( ObjetNetListStruct* Ref, int IsBus, static void PointToPointConnect( ObjetNetListStruct* Ref, int IsBus,
...@@ -165,7 +164,7 @@ void* WinEDA_SchematicFrame::BuildNetListBase() ...@@ -165,7 +164,7 @@ void* WinEDA_SchematicFrame::BuildNetListBase()
/* Build the sheet (not screen) list (flattened)*/ /* Build the sheet (not screen) list (flattened)*/
EDA_SheetList SheetListList( NULL ); EDA_SheetList SheetListList( NULL );
i=0; i=0;
/* 1ere passe : Comptage du nombre d'objet de Net */ /* first pass : count objects used in connectivty calculation */
g_NbrObjNet = 0; g_NbrObjNet = 0;
g_TabObjNet = NULL; /* Init pour le 1er passage dans ListeObjetConnection */ g_TabObjNet = NULL; /* Init pour le 1er passage dans ListeObjetConnection */
...@@ -174,7 +173,7 @@ void* WinEDA_SchematicFrame::BuildNetListBase() ...@@ -174,7 +173,7 @@ void* WinEDA_SchematicFrame::BuildNetListBase()
for( sheet = SheetListList.GetFirst(); sheet != NULL; sheet = SheetListList.GetNext() ) for( sheet = SheetListList.GetFirst(); sheet != NULL; sheet = SheetListList.GetNext() )
{ {
g_NbrObjNet += ListeObjetConnection( this, sheet, NULL ); g_NbrObjNet += ListeObjetConnection( sheet, NULL );
} }
if( g_NbrObjNet == 0 ) if( g_NbrObjNet == 0 )
...@@ -188,8 +187,7 @@ void* WinEDA_SchematicFrame::BuildNetListBase() ...@@ -188,8 +187,7 @@ void* WinEDA_SchematicFrame::BuildNetListBase()
if( g_TabObjNet == NULL ) if( g_TabObjNet == NULL )
return NULL; return NULL;
/* 2eme passe : Remplissage des champs des structures des objets de Net */ /* second pass: fill the fields of the structures used in connectivty calculation */
/* second pass: fill the fields of the structures in the Net */
s_PassNumber++; s_PassNumber++;
...@@ -197,15 +195,14 @@ void* WinEDA_SchematicFrame::BuildNetListBase() ...@@ -197,15 +195,14 @@ void* WinEDA_SchematicFrame::BuildNetListBase()
for( ObjetNetListStruct* tabObjNet = g_TabObjNet; for( ObjetNetListStruct* tabObjNet = g_TabObjNet;
sheet != NULL; sheet = SheetListList.GetNext() ) sheet != NULL; sheet = SheetListList.GetNext() )
{ {
tabObjNet += ListeObjetConnection( this, sheet, tabObjNet ); tabObjNet += ListeObjetConnection( sheet, tabObjNet );
} }
activity.Empty(); activity.Empty();
activity << wxT(" ") << _( "NbItems" ) << wxT(" ") << g_NbrObjNet; activity << wxT(" ") << _( "NbItems" ) << wxT(" ") << g_NbrObjNet;
SetStatusText( activity ); SetStatusText( activity );
/* Recherche des connections pour les Segments et les Pins */ /* Sort objects by Sheet */
/* Tri du Tableau des objets de Net par Sheet */
qsort( g_TabObjNet, g_NbrObjNet, sizeof(ObjetNetListStruct), TriBySheet ); qsort( g_TabObjNet, g_NbrObjNet, sizeof(ObjetNetListStruct), TriBySheet );
...@@ -363,7 +360,7 @@ void* WinEDA_SchematicFrame::BuildNetListBase() ...@@ -363,7 +360,7 @@ void* WinEDA_SchematicFrame::BuildNetListBase()
SheetLabelConnect( g_TabObjNet + i ); SheetLabelConnect( g_TabObjNet + i );
} }
/* Tri du Tableau des objets de Net par NetCode */ /* Sort objects by NetCode */
qsort( g_TabObjNet, g_NbrObjNet, sizeof(ObjetNetListStruct), TriNetCode ); qsort( g_TabObjNet, g_NbrObjNet, sizeof(ObjetNetListStruct), TriNetCode );
...@@ -438,17 +435,14 @@ static void SheetLabelConnect( ObjetNetListStruct* SheetLabel ) ...@@ -438,17 +435,14 @@ static void SheetLabelConnect( ObjetNetListStruct* SheetLabel )
} }
/*****************************************************************************/ /**************************************************************************************/
static int ListeObjetConnection( WinEDA_SchematicFrame* frame, DrawSheetPath* sheetlist, static int ListeObjetConnection( DrawSheetPath* sheetlist, ObjetNetListStruct* ObjNet )
ObjetNetListStruct* ObjNet ) /**************************************************************************************/
/*****************************************************************************/
/* Routine generant la liste des objets relatifs aux connection /** Function ListeObjetConnection
* entree: * Creates the list of objects related to connections (pins of components, wires, labels, junctions ...)
* sheetlist: pointer to a sheetlist. * @param sheetlist: pointer to a sheetlist.
* ObjNet: * @param ObjNet: if NULL, objects count else list to fill
* si NULL: la routine compte seulement le nombre des objets
* sinon: pointe le tableau a remplir
*/ */
{ {
int ii, NbrItem = 0; int ii, NbrItem = 0;
...@@ -596,8 +590,7 @@ static int ListeObjetConnection( WinEDA_SchematicFrame* frame, DrawSheetPath* sh ...@@ -596,8 +590,7 @@ static int ListeObjetConnection( WinEDA_SchematicFrame* frame, DrawSheetPath* sh
if( DEntry->Type() != COMPONENT_PIN_DRAW_TYPE ) if( DEntry->Type() != COMPONENT_PIN_DRAW_TYPE )
continue; continue;
if( DEntry->m_Unit if( DEntry->m_Unit && (DEntry->m_Unit != DrawLibItem->GetUnitSelection( sheetlist ) ) )
&& (DEntry->m_Unit != DrawLibItem->m_Multi) )
continue; continue;
if( DEntry->m_Convert if( DEntry->m_Convert
...@@ -684,7 +677,7 @@ static int ListeObjetConnection( WinEDA_SchematicFrame* frame, DrawSheetPath* sh ...@@ -684,7 +677,7 @@ static int ListeObjetConnection( WinEDA_SchematicFrame* frame, DrawSheetPath* sh
break; break;
case DRAW_HIERARCHICAL_PIN_SHEET_STRUCT_TYPE: case DRAW_HIERARCHICAL_PIN_SHEET_STRUCT_TYPE:
DisplayError( frame, wxT( "Netlist: Type DRAW_SHEETLABEL inattendu" ) ); DisplayError( NULL, wxT( "Netlist: Type DRAW_SHEETLABEL inattendu" ) );
break; break;
default: default:
...@@ -692,7 +685,7 @@ static int ListeObjetConnection( WinEDA_SchematicFrame* frame, DrawSheetPath* sh ...@@ -692,7 +685,7 @@ static int ListeObjetConnection( WinEDA_SchematicFrame* frame, DrawSheetPath* sh
wxString msg; wxString msg;
msg.Printf( wxT( "Netlist: unexpected type struct %d" ), msg.Printf( wxT( "Netlist: unexpected type struct %d" ),
DrawList->Type() ); DrawList->Type() );
DisplayError( frame, msg ); DisplayError( NULL, msg );
break; break;
} }
} }
......
...@@ -26,7 +26,7 @@ typedef enum { ...@@ -26,7 +26,7 @@ typedef enum {
* NET_TYPE_CUSTOM1+CUSTOMPANEL_COUNTMAX-1 * NET_TYPE_CUSTOM1+CUSTOMPANEL_COUNTMAX-1
* is the last id for user netlist format * is the last id for user netlist format
*/ */
NET_TYPE_CUSTOM_MAX = NET_TYPE_CUSTOM1+CUSTOMPANEL_COUNTMAX-1 NET_TYPE_CUSTOM_MAX = NET_TYPE_CUSTOM1 + CUSTOMPANEL_COUNTMAX - 1
} TypeNetForm; } TypeNetForm;
...@@ -39,7 +39,7 @@ enum NetObjetType { /* Type des objets de Net */ ...@@ -39,7 +39,7 @@ enum NetObjetType { /* Type des objets de Net */
NET_JONCTION, NET_JONCTION,
NET_LABEL, NET_LABEL,
NET_GLOBLABEL, NET_GLOBLABEL,
NET_HIERLABEL, //on a screen to indicate connection to a higher-level sheet NET_HIERLABEL, //on a screen to indicate connection to a higher-level sheet
NET_SHEETLABEL, //on a drawscreen element to indicate connection to a lower-level sheet. NET_SHEETLABEL, //on a drawscreen element to indicate connection to a lower-level sheet.
NET_BUSLABELMEMBER, NET_BUSLABELMEMBER,
NET_GLOBBUSLABELMEMBER, NET_GLOBBUSLABELMEMBER,
...@@ -51,9 +51,9 @@ enum NetObjetType { /* Type des objets de Net */ ...@@ -51,9 +51,9 @@ enum NetObjetType { /* Type des objets de Net */
}; };
enum IsConnectType { /* Valeur du Flag de connection */ enum IsConnectType { /* Valeur du Flag de connection */
UNCONNECT, /* Pin ou Label non connecte */ UNCONNECT, /* Pin ou Label non connecte */
NOCONNECT, /* Pin volontairement non connectee (Symb. NoConnect utilise) */ NOCONNECT, /* Pin volontairement non connectee (Symb. NoConnect utilise) */
PAD_CONNECT /* connexion normale */ PAD_CONNECT /* connexion normale */
}; };
...@@ -62,23 +62,23 @@ enum IsConnectType { /* Valeur du Flag de connection */ ...@@ -62,23 +62,23 @@ enum IsConnectType { /* Valeur du Flag de connection */
class ObjetNetListStruct class ObjetNetListStruct
{ {
public: public:
EDA_BaseStruct* m_Comp; /* Pointeur sur la definition de l'objet */ EDA_BaseStruct* m_Comp; /* Pointeur sur la definition de l'objet */
void* m_Link; /* Pour SheetLabelStruct: Pointeur sur la feuille de hierarchie void* m_Link; /* Pour SheetLabelStruct: Pointeur sur la feuille de hierarchie
* Pour les Pins: pointeur sur le composant */ * Pour les Pins: pointeur sur le composant */
int m_Flag; /* flag pour calculs internes */ int m_Flag; /* flag pour calculs internes */
DrawSheetPath m_SheetList; DrawSheetPath m_SheetList;
NetObjetType m_Type; NetObjetType m_Type;
int m_ElectricalType;/* Pour Pins et sheet labels: type electrique */ int m_ElectricalType; /* Pour Pins et sheet labels: type electrique */
private: private:
int m_NetCode; /* pour elements simples */ int m_NetCode; /* pour elements simples */
public: public:
int m_BusNetCode; /* pour connexions type bus */ int m_BusNetCode; /* pour connexions type bus */
int m_Member; /* pour les labels type BUSWIRE ( labels de bus eclate ) int m_Member; /* pour les labels type BUSWIRE ( labels de bus eclate )
* numero de membre */ * numero de membre */
IsConnectType m_FlagOfConnection; IsConnectType m_FlagOfConnection;
DrawSheetPath m_SheetListInclude; /* sheet that the hierarchal label connects to.*/ DrawSheetPath m_SheetListInclude; /* sheet that the hierarchal label connects to.*/
long m_PinNum; /* numero de pin( 4 octets -> 4 codes ascii) */ long m_PinNum; /* numero de pin( 4 octets -> 4 codes ascii) */
const wxString* m_Label; /* Tous types Labels:pointeur sur la wxString definissant le label */ const wxString* m_Label; /* Tous types Labels:pointeur sur la wxString definissant le label */
wxPoint m_Start, m_End; wxPoint m_Start, m_End;
#if defined (DEBUG) #if defined (DEBUG)
...@@ -93,15 +93,17 @@ public: ...@@ -93,15 +93,17 @@ public:
/* Structures pour memo et liste des elements */ /* Structures pour memo et liste des elements */
typedef struct ListLabel typedef struct ListLabel
{ {
int m_LabelType; int m_LabelType;
void * m_Label; void* m_Label;
char m_SheetPath[64]; char m_SheetPath[64];
} ListLabel; } ListLabel;
typedef struct ListComponent typedef struct ListComponent
{ {
SCH_COMPONENT * m_Comp; SCH_COMPONENT* m_Comp;
char m_Ref[32]; char m_Ref[32];
//have to store it here since the object refrerences will be duplicated.
//have to store it here since the object references will be duplicated.
DrawSheetPath m_SheetList; //composed of UIDs DrawSheetPath m_SheetList; //composed of UIDs
} ListComponent; } ListComponent;
...@@ -109,19 +111,19 @@ typedef struct ListComponent ...@@ -109,19 +111,19 @@ typedef struct ListComponent
struct CmpListStruct struct CmpListStruct
{ {
public: public:
SCH_COMPONENT* m_Cmp; /* Pointeur sur le composant */ SCH_COMPONENT* m_Cmp; /* Pointeur sur le composant */
int m_NbParts; /* Nombre de parts par boitier */ int m_NbParts; /* Nombre de parts par boitier */
bool m_PartsLocked; // For multi part components: True if the part cannot be changed bool m_PartsLocked; // For multi part components: True if the part cannot be changed
int m_Unit; /* Numero de part */ int m_Unit; /* Numero de part */
DrawSheetPath m_SheetList; DrawSheetPath m_SheetList;
unsigned long m_TimeStamp; /* unique identification number */ unsigned long m_TimeStamp; /* unique identification number */
int m_IsNew; /* != 0 pour composants non annotes */ int m_IsNew; /* != 0 pour composants non annotes */
char m_TextValue[32]; /* Valeur */ char m_TextValue[32]; /* Valeur */
char m_TextRef[32]; /* Reference ( hors numero ) */ char m_TextRef[32]; /* Reference ( hors numero ) */
int m_NumRef; /* Numero de reference */ int m_NumRef; /* Numero de reference */
int m_Flag; /* flag pour calculs internes */ int m_Flag; /* flag pour calculs internes */
wxPoint m_Pos; /* position components */ wxPoint m_Pos; /* position components */
char m_Path[128]; // the 'path' of the object in the sheet hierarchy. char m_Path[128]; // the 'path' of the object in the sheet hierarchy.
}; };
......
...@@ -610,7 +610,7 @@ void WinEDA_SchematicFrame::Process_Special_Functions( wxCommandEvent& event ) ...@@ -610,7 +610,7 @@ void WinEDA_SchematicFrame::Process_Special_Functions( wxCommandEvent& event )
{ {
EDA_LibComponentStruct* LibEntry; EDA_LibComponentStruct* LibEntry;
LibEntry = FindLibPart( LibEntry = FindLibPart(
( (SCH_COMPONENT*) screen->GetCurItem() )->m_ChipName, ( (SCH_COMPONENT*) screen->GetCurItem() )->m_ChipName.GetData(),
wxEmptyString, wxEmptyString,
FIND_ALIAS ); FIND_ALIAS );
if( LibEntry && LibEntry->m_DocFile != wxEmptyString ) if( LibEntry && LibEntry->m_DocFile != wxEmptyString )
......
...@@ -253,7 +253,7 @@ wxClientDC dc(DrawPanel); ...@@ -253,7 +253,7 @@ wxClientDC dc(DrawPanel);
g_ViewUnit = 1; g_ViewUnit = 1;
g_ViewConvert = 1; g_ViewConvert = 1;
LibEntry = FindLibPart(CmpName,Lib->m_Name, FIND_ALIAS); LibEntry = FindLibPart(CmpName.GetData(),Lib->m_Name, FIND_ALIAS);
g_CurrentViewComponentName = CmpName; g_CurrentViewComponentName = CmpName;
DisplayLibInfos(); DisplayLibInfos();
Zoom_Automatique(FALSE); Zoom_Automatique(FALSE);
......
...@@ -208,24 +208,24 @@ ...@@ -208,24 +208,24 @@
#include "../bitmaps/Auto_track_width.xpm" #include "../bitmaps/Auto_track_width.xpm"
#include "../bitmaps/fill_zone.xpm" #include "../bitmaps/fill_zone.xpm"
#include "../bitmaps/Width_Segment.xpm" #include "../bitmaps/Width_Segment.xpm"
#include "../bitmaps/annotate_right_down.xpm" #include "../bitmaps/annotate_right_down.xpm"
#include "../bitmaps/annotate_down_right.xpm" #include "../bitmaps/annotate_down_right.xpm"
#include "../bitmaps/new_sch.xpm" // #include "../bitmaps/new_sch.xpm"
#include "../bitmaps/Open_Project.xpm" #include "../bitmaps/Open_Project.xpm"
#include "../bitmaps/new_cvpcb.xpm" // #include "../bitmaps/new_cvpcb.xpm"
#include "../bitmaps/zip.xpm" #include "../bitmaps/zip.xpm"
#include "../bitmaps/icon_gerbview_small.xpm" #include "../bitmaps/icon_gerbview_small.xpm"
#include "../bitmaps/zip_tool.xpm" // #include "../bitmaps/zip_tool.xpm"
#include "../bitmaps/unzip.xpm" #include "../bitmaps/unzip.xpm"
#include "../bitmaps/Browse_Files.xpm" #include "../bitmaps/Browse_Files.xpm"
#include "../bitmaps/New_Project.xpm" #include "../bitmaps/New_Project.xpm"
#include "../bitmaps/new_gerb.xpm" // #include "../bitmaps/new_gerb.xpm"
#include "../bitmaps/new_python.xpm" // #include "../bitmaps/new_python.xpm"
#include "../bitmaps/icon_cvpcb_small.xpm" #include "../bitmaps/icon_cvpcb_small.xpm"
#include "../bitmaps/unknown.xpm" #include "../bitmaps/unknown.xpm"
#include "../bitmaps/new_pcb.xpm" // #include "../bitmaps/new_pcb.xpm"
#include "../bitmaps/reload.xpm" #include "../bitmaps/reload.xpm"
......
...@@ -280,7 +280,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, ...@@ -280,7 +280,7 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
{ {
std::vector<CPolyLine*> * pa = new std::vector<CPolyLine*>; std::vector<CPolyLine*> * pa = new std::vector<CPolyLine*>;
curr_polygon->Undraw(); curr_polygon->Undraw();
int n_poly = CurrArea->m_Poly->NormalizeWithGpc( pa, bRetainArcs ); int n_poly = CurrArea->m_Poly->NormalizeAreaOutlines( pa, bRetainArcs );
if( n_poly > 1 ) // i.e if clipping has created some polygons, we must add these new copper areas if( n_poly > 1 ) // i.e if clipping has created some polygons, we must add these new copper areas
{ {
ZONE_CONTAINER* NewArea; ZONE_CONTAINER* NewArea;
...@@ -310,7 +310,8 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea, ...@@ -310,7 +310,8 @@ int BOARD::ClipAreaPolygon( ZONE_CONTAINER* CurrArea,
* itself and the polygons for any other areas on the same net. * itself and the polygons for any other areas on the same net.
* This may change the number and order of copper areas in the net. * This may change the number and order of copper areas in the net.
* @param modified_area = area to test * @param modified_area = area to test
* @param bMessageBox : if true, shows message boxes when clipping occurs. * @param bMessageBoxInt == true, shows message when clipping occurs.
* @param bMessageBoxArc == true, shows message when clipping can't be done due to arcs.
* @return : * @return :
* -1 if arcs intersect other sides, so polygon can't be clipped * -1 if arcs intersect other sides, so polygon can't be clipped
* 0 if no intersecting sides * 0 if no intersecting sides
...@@ -697,8 +698,11 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi ...@@ -697,8 +698,11 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi
CPolyLine* poly2 = area_to_combine->m_Poly; CPolyLine* poly2 = area_to_combine->m_Poly;
std::vector<CArc> arc_array1; std::vector<CArc> arc_array1;
std::vector<CArc> arc_array2; std::vector<CArc> arc_array2;
poly1->MakeGpcPoly( -1, &arc_array1 );
poly2->MakeGpcPoly( -1, &arc_array2 ); poly1->MakePolygonFromAreaOutlines( -1, &arc_array1 );
poly2->MakePolygonFromAreaOutlines( -1, &arc_array2 );
#ifdef USE_GPC_POLY_LIB
int n_ext_cont1 = 0; int n_ext_cont1 = 0;
for( int ic = 0; ic<poly1->GetGpcPoly()->num_contours; ic++ ) for( int ic = 0; ic<poly1->GetGpcPoly()->num_contours; ic++ )
if( !( (poly1->GetGpcPoly()->hole)[ic] ) ) if( !( (poly1->GetGpcPoly()->hole)[ic] ) )
...@@ -776,7 +780,97 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi ...@@ -776,7 +780,97 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi
area_ref->m_Poly->Draw(); area_ref->m_Poly->Draw();
gpc_free_polygon( union_gpc ); gpc_free_polygon( union_gpc );
delete union_gpc; delete union_gpc;
return 1; return 1;
#endif
#ifdef USE_GPL_POLY_LIB
//@todo
#warning work in progress
wxString msg;
int n_ext_cont1 = poly1->GetPhpPoly()->m_cnt;
int n_ext_cont2 = poly2->GetPhpPoly()->m_cnt;
polygon* union_polygon = NULL;
union_polygon = poly1->GetPhpPoly()->boolean( poly2->GetPhpPoly(), A_OR_B );
if ( union_polygon == NULL )
return 0;
// get number of outside contours
int n_union_ext_cont = union_polygon->m_cnt;
msg.Printf(wxT("cnt res = %d, pts1,2 = %d,%d"), n_union_ext_cont , n_ext_cont1, n_ext_cont2);
wxMessageBox(msg);
// if no intersection, free new gpc and return
#if 0
if( n_union_ext_cont == n_ext_cont1 + n_ext_cont2 )
{
wxMessageBox(wxT("no change polys"));
delete union_polygon;
return 0;
}
#endif
wxMessageBox(wxT("merge areas"));
// intersection, replace area_ref->m_Poly with combined areas and remove area_to_combine
RemoveArea( area_to_combine );
area_ref->m_Poly->RemoveAllContours();
// create area with external contour
// for( int ic = 0; ic < union_polygon->m_cnt; ic++ )
{
// if( !(union_gpc->hole)[ic] ) // Recreate only area edges, NOT holes (todo..)
{
// external contour, replace this poly
vertex * curr_vertex = union_polygon->getFirst();
for( int ii = 0; ii < union_polygon->m_cnt; ii++ )
{
int x = (int) curr_vertex->X();
int y = (int) curr_vertex->Y();
msg.Printf(wxT("ii = %d, pts = %d,%d, wid = %d"), ii , x, y, curr_vertex->id());
wxMessageBox(msg);
if( ii==0 )
{
area_ref->m_Poly->Start( area_ref->GetLayer(
), x, y, area_ref->m_Poly->GetHatchStyle() );
}
else
area_ref->m_Poly->AppendCorner( x, y );
curr_vertex = curr_vertex->Next();
// if( curr_vertex->id() == union_polygon->getFirst()->id() ) break;
}
area_ref->m_Poly->Close();
}
}
// add holes
#if 0
for( int ic = 0; ic<union_gpc->num_contours; ic++ )
{
if( (union_gpc->hole)[ic] )
{
// hole
for( int i = 0; i<union_gpc->contour[ic].num_vertices; i++ )
{
int x = (int) ( (union_gpc->contour)[ic].vertex )[i].x;
int y = (int) ( (union_gpc->contour)[ic].vertex )[i].y;
area_ref->m_Poly->AppendCorner( x, y );
}
area_ref->m_Poly->Close();
}
}
#endif
area_ref->utility = 1;
area_ref->m_Poly->RestoreArcs( &arc_array1 );
area_ref->m_Poly->RestoreArcs( &arc_array2 );
area_ref->m_Poly->Draw();
delete union_polygon;
return 0;
#endif
} }
...@@ -785,7 +879,7 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi ...@@ -785,7 +879,7 @@ int BOARD::CombineAreas( ZONE_CONTAINER* area_ref, ZONE_CONTAINER* area_to_combi
/** /**
* Function Is_Area_Inside_Area * Function Is_Area_Inside_Area
* Test a given area to see if it is inside an other area, or an other area is inside the given area * Test a given area to see if it is inside an other area, or an other area is inside the given area
* an area is inside an other are if ALL its corners are inside * an area is inside an other are if ALL its edges are inside the other area
* @param Area_Ref: the given area to compare with other areas * @param Area_Ref: the given area to compare with other areas
* used to remove redundant areas * used to remove redundant areas
*/ */
...@@ -1007,7 +1101,7 @@ int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_E ...@@ -1007,7 +1101,7 @@ int BOARD::Test_Drc_Areas_Outlines_To_Areas_Outlines( ZONE_CONTAINER* aArea_To_E
bool DRC::doEdgeZoneDrc( ZONE_CONTAINER * aArea, int aCornerIndex ) bool DRC::doEdgeZoneDrc( ZONE_CONTAINER * aArea, int aCornerIndex )
{ {
wxString str; wxString str;
wxPoint start = aArea->GetCornerPosition(aCornerIndex); wxPoint start = aArea->GetCornerPosition(aCornerIndex);
wxPoint end; wxPoint end;
// Search the end point of the edge starting at aCornerIndex // Search the end point of the edge starting at aCornerIndex
......
// PolyLine.cpp ... implementation of CPolyLine class from FreePCB. // PolyLine.cpp ... implementation of CPolyLine class from FreePCB.
// //
// implementation for kicad // implementation for kicad
// //
...@@ -12,33 +13,47 @@ using namespace std; ...@@ -12,33 +13,47 @@ using namespace std;
#include "PolyLine.h" #include "PolyLine.h"
#define to_int(x) (int)round((x)) #define to_int( x ) (int) round( (x) )
#define pi 3.14159265359 #define pi 3.14159265359
#define DENOM 10 // to use mils for php clipping
//#define DENOM 1 // to use internal units for php clipping
CPolyLine::CPolyLine() CPolyLine::CPolyLine()
{ {
m_HatchStyle = 0; m_HatchStyle = 0;
m_Width = 0; m_Width = 0;
utility = 0; utility = 0;
m_gpc_poly = new gpc_polygon; #ifdef USE_GPC_POLY_LIB
m_gpc_poly->num_contours = 0; m_gpc_poly = new gpc_polygon;
m_php_poly = new polygon; m_gpc_poly->num_contours = 0;
#else
m_gpc_poly = NULL;
#endif
#ifdef USE_GPL_POLY_LIB
m_php_poly = new polygon;
#else
m_php_poly = NULL;
#endif
} }
// destructor, removes display elements // destructor, removes display elements
// //
CPolyLine::~CPolyLine() CPolyLine::~CPolyLine()
{ {
Undraw(); Undraw();
FreeGpcPoly(); #ifdef USE_GPC_POLY_LIB
delete m_gpc_poly; FreeGpcPoly();
delete m_php_poly; delete m_gpc_poly;
#endif
#ifdef USE_GPL_POLY_LIB
delete m_php_poly;
#endif
} }
#ifdef USE_GPC_POLY_LIB
// Use the General Polygon Clipping Library to clip contours // Use the General Polygon Clipping Library to clip contours
// If this results in new polygons, return them as std::vector p // If this results in new polygons, return them as std::vector p
// If bRetainArcs == TRUE, try to retain arcs in polys // If bRetainArcs == TRUE, try to retain arcs in polys
...@@ -46,546 +61,613 @@ CPolyLine::~CPolyLine() ...@@ -46,546 +61,613 @@ CPolyLine::~CPolyLine()
// //
int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, bool bRetainArcs ) int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, bool bRetainArcs )
{ {
std::vector<CArc> arc_array; std::vector<CArc> arc_array;
if( bRetainArcs ) if( bRetainArcs )
MakeGpcPoly( -1, &arc_array ); MakeGpcPoly( -1, &arc_array );
else else
MakeGpcPoly( -1, NULL ); MakeGpcPoly( -1, NULL );
Undraw(); Undraw();
// now, recreate poly // now, recreate poly
// first, find outside contours and create new CPolyLines if necessary // first, find outside contours and create new CPolyLines if necessary
int n_ext_cont = 0; int n_ext_cont = 0;
for( int ic=0; ic<m_gpc_poly->num_contours; ic++ ) for( int ic = 0; ic<m_gpc_poly->num_contours; ic++ )
{ {
if( !(m_gpc_poly->hole)[ic] ) if( !(m_gpc_poly->hole)[ic] )
{ {
if( n_ext_cont == 0 ) if( n_ext_cont == 0 )
{ {
// first external contour, replace this poly // first external contour, replace this poly
corner.clear(); corner.clear();
side_style.clear(); side_style.clear();
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ ) for( int i = 0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{ {
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x); int x = to_int( ( (m_gpc_poly->contour)[ic].vertex )[i].x );
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y); int y = to_int( ( (m_gpc_poly->contour)[ic].vertex )[i].y );
if( i==0 ) if( i==0 )
Start( m_layer, x, y, m_HatchStyle ); Start( m_layer, x, y, m_HatchStyle );
else else
AppendCorner( x, y, STRAIGHT, FALSE ); AppendCorner( x, y, STRAIGHT, FALSE );
} }
Close();
n_ext_cont++; Close();
} n_ext_cont++;
else if( pa ) }
{ else if( pa )
// next external contour, create new poly {
CPolyLine * poly = new CPolyLine; // next external contour, create new poly
pa->push_back(poly); // put in array CPolyLine* poly = new CPolyLine;
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ ) pa->push_back( poly ); // put in array
{ for( int i = 0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x); {
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y); int x = to_int( ( (m_gpc_poly->contour)[ic].vertex )[i].x );
if( i==0 ) int y = to_int( ( (m_gpc_poly->contour)[ic].vertex )[i].y );
poly->Start( m_layer, x, y, m_HatchStyle ); if( i==0 )
else poly->Start( m_layer, x, y, m_HatchStyle );
poly->AppendCorner( x, y, STRAIGHT, FALSE ); else
} poly->AppendCorner( x, y, STRAIGHT, FALSE );
poly->Close( STRAIGHT, FALSE ); }
n_ext_cont++;
} poly->Close( STRAIGHT, FALSE );
} n_ext_cont++;
} }
}
}
// now add cutouts to the CPolyLine(s)
for( int ic=0; ic<m_gpc_poly->num_contours; ic++ ) // now add cutouts to the CPolyLine(s)
{ for( int ic = 0; ic<m_gpc_poly->num_contours; ic++ )
if( (m_gpc_poly->hole)[ic] ) {
{ if( (m_gpc_poly->hole)[ic] )
CPolyLine * ext_poly = NULL; {
if( n_ext_cont == 1 ) CPolyLine* ext_poly = NULL;
{ if( n_ext_cont == 1 )
ext_poly = this; {
} ext_poly = this;
else }
{ else
// find the polygon that contains this hole {
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ ) // find the polygon that contains this hole
{ for( int i = 0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x); {
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y); int x = to_int( ( (m_gpc_poly->contour)[ic].vertex )[i].x );
if( TestPointInside( x, y ) ) int y = to_int( ( (m_gpc_poly->contour)[ic].vertex )[i].y );
ext_poly = this; if( TestPointInside( x, y ) )
else ext_poly = this;
{ else
for( int ext_ic=0; ext_ic<n_ext_cont-1; ext_ic++ ) {
{ for( int ext_ic = 0; ext_ic<n_ext_cont - 1; ext_ic++ )
if( (*pa)[ext_ic]->TestPointInside( x, y ) ) {
{ if( (*pa)[ext_ic]->TestPointInside( x, y ) )
ext_poly = (*pa)[ext_ic]; {
break; ext_poly = (*pa)[ext_ic];
} break;
} }
} }
if( ext_poly ) }
break; if( ext_poly )
} break;
} }
if( !ext_poly ) }
wxASSERT(0); if( !ext_poly )
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ ) wxASSERT( 0 );
{ for( int i = 0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x); {
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y); int x = to_int( ( (m_gpc_poly->contour)[ic].vertex )[i].x );
ext_poly->AppendCorner( x, y, STRAIGHT, FALSE ); int y = to_int( ( (m_gpc_poly->contour)[ic].vertex )[i].y );
} ext_poly->AppendCorner( x, y, STRAIGHT, FALSE );
ext_poly->Close( STRAIGHT, FALSE ); }
}
} ext_poly->Close( STRAIGHT, FALSE );
if( bRetainArcs ) }
RestoreArcs( &arc_array, pa ); }
FreeGpcPoly();
if( bRetainArcs )
return n_ext_cont; RestoreArcs( &arc_array, pa );
FreeGpcPoly();
return n_ext_cont;
} }
#endif
#ifdef USE_GPL_POLY_LIB
// make a php_polygon from first contour // make a php_polygon from first contour
int CPolyLine::MakePhpPoly() int CPolyLine::MakePhpPoly()
{ {
FreePhpPoly(); FreePhpPoly();
polygon test_poly; int nv = GetContourEnd( 0 );
int nv = GetContourEnd(0); for( int iv = 0; iv <= nv; iv++ )
for( int iv=0; iv<=nv; iv++ ) m_php_poly->addv( GetX( iv ), GetY( iv ) );
{
int x = GetX(iv)/DENOM; m_php_poly->getFirst()->m_id = 1;
int y = GetY(iv)/DENOM; return 0;
m_php_poly->addv( x, y );
}
return 0;
} }
void CPolyLine::FreePhpPoly() void CPolyLine::FreePhpPoly()
{ {
// delete all vertices // delete all vertices
while( m_php_poly->m_cnt > 1 ) while( m_php_poly->m_cnt > 1 )
{ {
vertex * fv = m_php_poly->getFirst(); vertex* fv = m_php_poly->getFirst();
m_php_poly->del( fv->m_nextV ); m_php_poly->del( fv->m_nextV );
} }
delete m_php_poly->m_first;
m_php_poly->m_first = NULL; delete m_php_poly->m_first;
m_php_poly->m_cnt = 0; m_php_poly->m_first = NULL;
m_php_poly->m_cnt = 0;
} }
// Use the php clipping lib to clip this poly against poly // Use the php clipping lib to clip this poly against poly
// //
void CPolyLine::ClipPhpPolygon( int php_op, CPolyLine * poly ) void CPolyLine::ClipPhpPolygon( int php_op, CPolyLine* poly )
{ {
Undraw(); Undraw();
poly->MakePhpPoly(); poly->MakePhpPoly();
MakePhpPoly(); MakePhpPoly();
polygon * p = m_php_poly->boolean( poly->m_php_poly, php_op ); polygon* p = m_php_poly->boolean( poly->m_php_poly, php_op );
poly->FreePhpPoly(); poly->FreePhpPoly();
FreePhpPoly(); FreePhpPoly();
if( p ) if( p )
{ {
// now screw with the PolyLine // now screw with the PolyLine
corner.clear(); corner.clear();
side_style.clear(); side_style.clear();
do
{ do
vertex * v = p->getFirst(); {
Start( m_layer, to_int(v->X()*DENOM), to_int(v->Y()*DENOM), m_HatchStyle ); vertex* v = p->getFirst();
do Start( m_layer, to_int( v->X() ), to_int( v->Y() ), m_HatchStyle );
{
vertex * n = v->Next(); do
AppendCorner( to_int(v->X()*DENOM), to_int((v->Y()*DENOM )) ); {
v = n; vertex* n = v->Next();
} AppendCorner( to_int( v->X() ), to_int( (v->Y()) ) );
while( v->id() != p->getFirst()->id() ); v = n;
Close(); } while( v->id() != p->getFirst()->id() );
Close();
// p = p->NextPoly(); // p = p->NextPoly();
delete p; delete p;
p = NULL; p = NULL;
} } while( p );
while( p ); }
} Draw();
Draw();
} }
// make a gpc_polygon for a closed polyline contour
// approximates arcs with multiple straight-line segments #endif
// if icontour = -1, make polygon with all contours,
// combining intersecting contours if possible int CPolyLine::MakePolygonFromAreaOutlines( int icontour, std::vector<CArc> * arc_array )
// returns data on arcs in arc_array {
// #ifdef USE_GPC_POLY_LIB
return MakeGpcPoly( icontour, arc_array );
#endif
#ifdef USE_GPL_POLY_LIB
return MakePhpPoly( );
#endif
}
void CPolyLine::FreePolygon()
{
#ifdef USE_GPC_POLY_LIB
FreeGpcPoly();
#endif
#ifdef USE_GPL_POLY_LIB
FreePhpPoly();
#endif
}
int CPolyLine::NormalizeAreaOutlines( std::vector<CPolyLine*> * pa, bool bRetainArcs )
{
#ifdef USE_GPC_POLY_LIB
return NormalizeWithGpc( pa, bRetainArcs );
#endif
#ifdef USE_GPL_POLY_LIB
#warning NormalizeAreaOutlines with GPL lib must be finished (TODO)
return 1;
#endif
}
#ifdef USE_GPC_POLY_LIB
/** Function MakeGpcPoly
* make a gpc_polygon for a closed polyline contour
* approximates arcs with multiple straight-line segments
* @param icontour : if icontour = -1, make polygon with all contours,
* combining intersecting contours if possible
* @param arc_array : return data on arcs in arc_array
* @return error: 0 if Ok, 1 if error
*/
int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array ) int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array )
{ {
if( m_gpc_poly->num_contours ) if( m_gpc_poly->num_contours )
FreeGpcPoly(); FreeGpcPoly();
if( !GetClosed() && (icontour == (GetNumContours()-1) || icontour == -1)) if( !GetClosed() && (icontour == (GetNumContours() - 1) || icontour == -1) )
return 1; // error return 1; // error
// initialize m_gpc_poly // initialize m_gpc_poly
m_gpc_poly->num_contours = 0; m_gpc_poly->num_contours = 0;
m_gpc_poly->hole = NULL; m_gpc_poly->hole = NULL;
m_gpc_poly->contour = NULL; m_gpc_poly->contour = NULL;
int n_arcs = 0; int n_arcs = 0;
int first_contour = icontour; int first_contour = icontour;
int last_contour = icontour; int last_contour = icontour;
if( icontour == -1 ) if( icontour == -1 )
{ {
first_contour = 0; first_contour = 0;
last_contour = GetNumContours() - 1; last_contour = GetNumContours() - 1;
} }
if( arc_array ) if( arc_array )
arc_array->clear(); arc_array->clear();
int iarc = 0; int iarc = 0;
for( int icont=first_contour; icont<=last_contour; icont++ ) for( int icont = first_contour; icont<=last_contour; icont++ )
{ {
// make gpc_polygon for this contour // make gpc_polygon for this contour
gpc_polygon * gpc = new gpc_polygon; gpc_polygon* gpc = new gpc_polygon;
gpc->num_contours = 0; gpc->num_contours = 0;
gpc->hole = NULL; gpc->hole = NULL;
gpc->contour = NULL; gpc->contour = NULL;
// first, calculate number of vertices in contour // first, calculate number of vertices in contour
int n_vertices = 0; int n_vertices = 0;
int ic_st = GetContourStart(icont); int ic_st = GetContourStart( icont );
int ic_end = GetContourEnd(icont); int ic_end = GetContourEnd( icont );
for( int ic=ic_st; ic<=ic_end; ic++ ) for( int ic = ic_st; ic<=ic_end; ic++ )
{ {
int style = side_style[ic]; int style = side_style[ic];
int x1 = corner[ic].x; int x1 = corner[ic].x;
int y1 = corner[ic].y; int y1 = corner[ic].y;
int x2, y2; int x2, y2;
if( ic < ic_end ) if( ic < ic_end )
{ {
x2 = corner[ic+1].x; x2 = corner[ic + 1].x;
y2 = corner[ic+1].y; y2 = corner[ic + 1].y;
} }
else else
{ {
x2 = corner[ic_st].x; x2 = corner[ic_st].x;
y2 = corner[ic_st].y; y2 = corner[ic_st].y;
} }
if( style == STRAIGHT ) if( style == STRAIGHT )
n_vertices++; n_vertices++;
else else
{ {
// style is ARC_CW or ARC_CCW // style is ARC_CW or ARC_CCW
int n; // number of steps for arcs int n; // number of steps for arcs
n = (abs(x2-x1)+abs(y2-y1))/(CArc::MAX_STEP); n = ( abs( x2 - x1 ) + abs( y2 - y1 ) ) / (CArc::MAX_STEP);
n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc
n_vertices += n; n_vertices += n;
n_arcs++; n_arcs++;
} }
} }
// now create gcp_vertex_list for this contour
gpc_vertex_list * g_v_list = new gpc_vertex_list; // now create gcp_vertex_list for this contour
g_v_list->vertex = (gpc_vertex*)calloc( sizeof(gpc_vertex), n_vertices ); gpc_vertex_list* g_v_list = new gpc_vertex_list;
g_v_list->num_vertices = n_vertices; g_v_list->vertex = (gpc_vertex*) calloc( sizeof(gpc_vertex), n_vertices );
int ivtx = 0; g_v_list->num_vertices = n_vertices;
for( int ic=ic_st; ic<=ic_end; ic++ ) int ivtx = 0;
{ for( int ic = ic_st; ic<=ic_end; ic++ )
int style = side_style[ic]; {
int x1 = corner[ic].x; int style = side_style[ic];
int y1 = corner[ic].y; int x1 = corner[ic].x;
int x2, y2; int y1 = corner[ic].y;
if( ic < ic_end ) int x2, y2;
{ if( ic < ic_end )
x2 = corner[ic+1].x; {
y2 = corner[ic+1].y; x2 = corner[ic + 1].x;
} y2 = corner[ic + 1].y;
else }
{ else
x2 = corner[ic_st].x; {
y2 = corner[ic_st].y; x2 = corner[ic_st].x;
} y2 = corner[ic_st].y;
if( style == STRAIGHT ) }
{ if( style == STRAIGHT )
g_v_list->vertex[ivtx].x = x1; {
g_v_list->vertex[ivtx].y = y1; g_v_list->vertex[ivtx].x = x1;
ivtx++; g_v_list->vertex[ivtx].y = y1;
} ivtx++;
else }
{ else
// style is arc_cw or arc_ccw {
int n; // number of steps for arcs // style is arc_cw or arc_ccw
n = (abs(x2-x1)+abs(y2-y1))/(CArc::MAX_STEP); int n; // number of steps for arcs
n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc n = ( abs( x2 - x1 ) + abs( y2 - y1 ) ) / (CArc::MAX_STEP);
double xo, yo, theta1, theta2, a, b; n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc
a = fabs( (double)(x1 - x2) ); double xo, yo, theta1, theta2, a, b;
b = fabs( (double)(y1 - y2) ); a = fabs( (double) (x1 - x2) );
if( style == CPolyLine::ARC_CW ) b = fabs( (double) (y1 - y2) );
{ if( style == CPolyLine::ARC_CW )
// clockwise arc (ie.quadrant of ellipse) {
if( x2 > x1 && y2 > y1 ) // clockwise arc (ie.quadrant of ellipse)
{ if( x2 > x1 && y2 > y1 )
// first quadrant, draw second quadrant of ellipse {
xo = x2; // first quadrant, draw second quadrant of ellipse
yo = y1; xo = x2;
theta1 = pi; yo = y1;
theta2 = pi/2.0; theta1 = pi;
} theta2 = pi / 2.0;
else if( x2 < x1 && y2 > y1 ) }
{ else if( x2 < x1 && y2 > y1 )
// second quadrant, draw third quadrant of ellipse {
xo = x1; // second quadrant, draw third quadrant of ellipse
yo = y2; xo = x1;
theta1 = 3.0*pi/2.0; yo = y2;
theta2 = pi; theta1 = 3.0 * pi / 2.0;
} theta2 = pi;
else if( x2 < x1 && y2 < y1 ) }
{ else if( x2 < x1 && y2 < y1 )
// third quadrant, draw fourth quadrant of ellipse {
xo = x2; // third quadrant, draw fourth quadrant of ellipse
yo = y1; xo = x2;
theta1 = 2.0*pi; yo = y1;
theta2 = 3.0*pi/2.0; theta1 = 2.0 * pi;
} theta2 = 3.0 * pi / 2.0;
else }
{ else
xo = x1; // fourth quadrant, draw first quadrant of ellipse {
yo = y2; xo = x1; // fourth quadrant, draw first quadrant of ellipse
theta1 = pi/2.0; yo = y2;
theta2 = 0.0; theta1 = pi / 2.0;
} theta2 = 0.0;
} }
else }
{ else
// counter-clockwise arc {
if( x2 > x1 && y2 > y1 ) // counter-clockwise arc
{ if( x2 > x1 && y2 > y1 )
xo = x1; // first quadrant, draw fourth quadrant of ellipse {
yo = y2; xo = x1; // first quadrant, draw fourth quadrant of ellipse
theta1 = 3.0*pi/2.0; yo = y2;
theta2 = 2.0*pi; theta1 = 3.0 * pi / 2.0;
} theta2 = 2.0 * pi;
else if( x2 < x1 && y2 > y1 ) }
{ else if( x2 < x1 && y2 > y1 )
xo = x2; // second quadrant {
yo = y1; xo = x2; // second quadrant
theta1 = 0.0; yo = y1;
theta2 = pi/2.0; theta1 = 0.0;
} theta2 = pi / 2.0;
else if( x2 < x1 && y2 < y1 ) }
{ else if( x2 < x1 && y2 < y1 )
xo = x1; // third quadrant {
yo = y2; xo = x1; // third quadrant
theta1 = pi/2.0; yo = y2;
theta2 = pi; theta1 = pi / 2.0;
} theta2 = pi;
else }
{ else
xo = x2; // fourth quadrant {
yo = y1; xo = x2; // fourth quadrant
theta1 = pi; yo = y1;
theta2 = 3.0*pi/2.0; theta1 = pi;
} theta2 = 3.0 * pi / 2.0;
} }
// now write steps for arc }
if( arc_array )
{ // now write steps for arc
CArc new_arc; if( arc_array )
new_arc.style = style; {
new_arc.n_steps = n; CArc new_arc;
new_arc.xi = x1; new_arc.style = style;
new_arc.yi = y1; new_arc.n_steps = n;
new_arc.xf = x2; new_arc.xi = x1;
new_arc.yf = y2; new_arc.yi = y1;
arc_array->push_back(new_arc); new_arc.xf = x2;
iarc++; new_arc.yf = y2;
} arc_array->push_back( new_arc );
for( int is=0; is<n; is++ ) iarc++;
{ }
double theta = theta1 + ((theta2-theta1)*(double)is)/n; for( int is = 0; is<n; is++ )
double x = xo + a*cos(theta); {
double y = yo + b*sin(theta); double theta = theta1 + ( (theta2 - theta1) * (double) is ) / n;
if( is == 0 ) double x = xo + a* cos( theta );
{ double y = yo + b* sin( theta );
x = x1; if( is == 0 )
y = y1; {
} x = x1;
g_v_list->vertex[ivtx].x = x; y = y1;
g_v_list->vertex[ivtx].y = y; }
ivtx++; g_v_list->vertex[ivtx].x = x;
} g_v_list->vertex[ivtx].y = y;
} ivtx++;
} }
if( n_vertices != ivtx ) }
wxASSERT(0); }
// add vertex_list to gpc
gpc_add_contour( gpc, g_v_list, 0 ); if( n_vertices != ivtx )
// now clip m_gpc_poly with gpc, put new poly into result wxASSERT( 0 );
gpc_polygon * result = new gpc_polygon;
if( icontour == -1 && icont != 0 ) // add vertex_list to gpc
gpc_polygon_clip( GPC_DIFF, m_gpc_poly, gpc, result ); // hole gpc_add_contour( gpc, g_v_list, 0 );
else
gpc_polygon_clip( GPC_UNION, m_gpc_poly, gpc, result ); // outside // now clip m_gpc_poly with gpc, put new poly into result
// now copy result to m_gpc_poly gpc_polygon* result = new gpc_polygon;
gpc_free_polygon( m_gpc_poly ); if( icontour == -1 && icont != 0 )
delete m_gpc_poly; gpc_polygon_clip( GPC_DIFF, m_gpc_poly, gpc, result ); // hole
m_gpc_poly = result; else
gpc_free_polygon( gpc ); gpc_polygon_clip( GPC_UNION, m_gpc_poly, gpc, result ); // outside
delete gpc; // now copy result to m_gpc_poly
free( g_v_list->vertex ); gpc_free_polygon( m_gpc_poly );
free( g_v_list ); delete m_gpc_poly;
} m_gpc_poly = result;
return 0; gpc_free_polygon( gpc );
delete gpc;
free( g_v_list->vertex );
free( g_v_list );
}
return 0;
} }
int CPolyLine::FreeGpcPoly()
void CPolyLine::FreeGpcPoly()
{ {
if( m_gpc_poly->num_contours ) if( m_gpc_poly->num_contours )
{ {
delete m_gpc_poly->contour->vertex; delete m_gpc_poly->contour->vertex;
delete m_gpc_poly->contour; delete m_gpc_poly->contour;
delete m_gpc_poly->hole; delete m_gpc_poly->hole;
} }
m_gpc_poly->num_contours = 0; m_gpc_poly->num_contours = 0;
return 0;
} }
#endif
// Restore arcs to a polygon where they were replaced with steps // Restore arcs to a polygon where they were replaced with steps
// If pa != NULL, also use polygons in pa array // If pa != NULL, also use polygons in pa array
// //
int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa ) int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa )
{ {
// get poly info // get poly info
int n_polys = 1; int n_polys = 1;
if( pa )
n_polys += pa->size(); if( pa )
CPolyLine * poly; n_polys += pa->size();
CPolyLine* poly;
// undraw polys and clear utility flag for all corners
for( int ip=0; ip<n_polys; ip++ ) // undraw polys and clear utility flag for all corners
{ for( int ip = 0; ip<n_polys; ip++ )
if( ip == 0 ) {
poly = this; if( ip == 0 )
else poly = this;
poly = (*pa)[ip-1]; else
poly->Undraw(); poly = (*pa)[ip - 1];
for( int ic=0; ic<poly->GetNumCorners(); ic++ ) poly->Undraw();
poly->SetUtility( ic, 0 ); // clear utility flag for( int ic = 0; ic<poly->GetNumCorners(); ic++ )
} poly->SetUtility( ic, 0 ); // clear utility flag
// find arcs and replace them }
bool bFound;
int arc_start = 0; // find arcs and replace them
int arc_end = 0; bool bFound;
for( unsigned iarc=0; iarc<arc_array->size(); iarc++ ) int arc_start = 0;
{ int arc_end = 0;
int arc_xi = (*arc_array)[iarc].xi; for( unsigned iarc = 0; iarc<arc_array->size(); iarc++ )
int arc_yi = (*arc_array)[iarc].yi; {
int arc_xf = (*arc_array)[iarc].xf; int arc_xi = (*arc_array)[iarc].xi;
int arc_yf = (*arc_array)[iarc].yf; int arc_yi = (*arc_array)[iarc].yi;
int n_steps = (*arc_array)[iarc].n_steps; int arc_xf = (*arc_array)[iarc].xf;
int style = (*arc_array)[iarc].style; int arc_yf = (*arc_array)[iarc].yf;
bFound = FALSE; int n_steps = (*arc_array)[iarc].n_steps;
// loop through polys int style = (*arc_array)[iarc].style;
for( int ip=0; ip<n_polys; ip++ ) bFound = FALSE;
{
if( ip == 0 ) // loop through polys
poly = this; for( int ip = 0; ip<n_polys; ip++ )
else {
poly = (*pa)[ip-1]; if( ip == 0 )
for( int icont=0; icont<poly->GetNumContours(); icont++ ) poly = this;
{ else
int ic_start = poly->GetContourStart(icont); poly = (*pa)[ip - 1];
int ic_end = poly->GetContourEnd(icont); for( int icont = 0; icont<poly->GetNumContours(); icont++ )
if( (ic_end-ic_start) > n_steps ) {
{ int ic_start = poly->GetContourStart( icont );
for( int ic=ic_start; ic<=ic_end; ic++ ) int ic_end = poly->GetContourEnd( icont );
{ if( (ic_end - ic_start) > n_steps )
int ic_next = ic+1; {
if( ic_next > ic_end ) for( int ic = ic_start; ic<=ic_end; ic++ )
ic_next = ic_start; {
int xi = poly->GetX(ic); int ic_next = ic + 1;
int yi = poly->GetY(ic); if( ic_next > ic_end )
if( xi == arc_xi && yi == arc_yi ) ic_next = ic_start;
{ int xi = poly->GetX( ic );
// test for forward arc int yi = poly->GetY( ic );
int ic2 = ic + n_steps; if( xi == arc_xi && yi == arc_yi )
if( ic2 > ic_end ) {
ic2 = ic2 - ic_end + ic_start - 1; // test for forward arc
int xf = poly->GetX(ic2); int ic2 = ic + n_steps;
int yf = poly->GetY(ic2); if( ic2 > ic_end )
if( xf == arc_xf && yf == arc_yf ) ic2 = ic2 - ic_end + ic_start - 1;
{ int xf = poly->GetX( ic2 );
// arc from ic to ic2 int yf = poly->GetY( ic2 );
bFound = TRUE; if( xf == arc_xf && yf == arc_yf )
arc_start = ic; {
arc_end = ic2; // arc from ic to ic2
} bFound = TRUE;
else arc_start = ic;
{ arc_end = ic2;
// try reverse arc }
ic2 = ic - n_steps; else
if( ic2 < ic_start ) {
ic2 = ic2 - ic_start + ic_end + 1; // try reverse arc
xf = poly->GetX(ic2); ic2 = ic - n_steps;
yf = poly->GetY(ic2); if( ic2 < ic_start )
if( xf == arc_xf && yf == arc_yf ) ic2 = ic2 - ic_start + ic_end + 1;
{ xf = poly->GetX( ic2 );
// arc from ic2 to ic yf = poly->GetY( ic2 );
bFound = TRUE; if( xf == arc_xf && yf == arc_yf )
arc_start = ic2; {
arc_end = ic; // arc from ic2 to ic
style = 3 - style; bFound = TRUE;
} arc_start = ic2;
} arc_end = ic;
if( bFound ) style = 3 - style;
{ }
poly->side_style[arc_start] = style; }
// mark corners for deletion from arc_start+1 to arc_end-1 if( bFound )
for( int i=arc_start+1; i!=arc_end; ) {
{ poly->side_style[arc_start] = style;
if( i > ic_end )
i = ic_start; // mark corners for deletion from arc_start+1 to arc_end-1
poly->SetUtility( i, 1 ); for( int i = arc_start + 1; i!=arc_end; )
if( i == ic_end ) {
i = ic_start; if( i > ic_end )
else i = ic_start;
i++; poly->SetUtility( i, 1 );
} if( i == ic_end )
break; i = ic_start;
} else
} i++;
if( bFound ) }
break;
} break;
} }
if( bFound ) }
break; if( bFound )
} break;
} }
if( bFound ) }
(*arc_array)[iarc].bFound = TRUE; if( bFound )
} break;
}
// now delete all marked corners }
for( int ip=0; ip<n_polys; ip++ )
{ if( bFound )
if( ip == 0 ) (*arc_array)[iarc].bFound = TRUE;
poly = this; }
else
poly = (*pa)[ip-1]; // now delete all marked corners
for( int ic=poly->GetNumCorners()-1; ic>=0; ic-- ) for( int ip = 0; ip<n_polys; ip++ )
{ {
if( poly->GetUtility(ic) ) if( ip == 0 )
poly->DeleteCorner( ic, FALSE ); poly = this;
} else
} poly = (*pa)[ip - 1];
return 0; for( int ic = poly->GetNumCorners() - 1; ic>=0; ic-- )
{
if( poly->GetUtility( ic ) )
poly->DeleteCorner( ic, FALSE );
}
}
return 0;
} }
// initialize new polyline // initialize new polyline
// set layer, width, selection box size, starting point, id and pointer // set layer, width, selection box size, starting point, id and pointer
// //
...@@ -605,147 +687,154 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine ...@@ -605,147 +687,154 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine
// //
void CPolyLine::Start( int layer, int x, int y, int hatch ) void CPolyLine::Start( int layer, int x, int y, int hatch )
{ {
m_layer = layer; m_layer = layer;
m_HatchStyle = hatch; m_HatchStyle = hatch;
CPolyPt poly_pt( x, y ); CPolyPt poly_pt( x, y );
poly_pt.end_contour = FALSE; poly_pt.end_contour = FALSE;
corner.push_back(poly_pt); corner.push_back( poly_pt );
side_style.push_back(0); side_style.push_back( 0 );
} }
// add a corner to unclosed polyline // add a corner to unclosed polyline
// //
void CPolyLine::AppendCorner( int x, int y, int style, bool bDraw ) void CPolyLine::AppendCorner( int x, int y, int style, bool bDraw )
{ {
Undraw(); Undraw();
CPolyPt poly_pt( x, y ); CPolyPt poly_pt( x, y );
poly_pt.end_contour = FALSE; poly_pt.end_contour = FALSE;
// add entries for new corner and side // add entries for new corner and side
corner.push_back(poly_pt); corner.push_back( poly_pt );
side_style.push_back(style); side_style.push_back( style );
if( corner.size() > 0 && !corner[corner.size()-1].end_contour ) if( corner.size() > 0 && !corner[corner.size() - 1].end_contour )
side_style[corner.size()-1] = style; side_style[corner.size() - 1] = style;
int dl_type; int dl_type;
if( style == CPolyLine::STRAIGHT ) if( style == CPolyLine::STRAIGHT )
dl_type = DL_LINE; dl_type = DL_LINE;
else if( style == CPolyLine::ARC_CW ) else if( style == CPolyLine::ARC_CW )
dl_type = DL_ARC_CW; dl_type = DL_ARC_CW;
else if( style == CPolyLine::ARC_CCW ) else if( style == CPolyLine::ARC_CCW )
dl_type = DL_ARC_CCW; dl_type = DL_ARC_CCW;
else else
wxASSERT(0); wxASSERT( 0 );
if( bDraw ) if( bDraw )
Draw(); Draw();
} }
// close last polyline contour // close last polyline contour
// //
void CPolyLine::Close( int style, bool bDraw ) void CPolyLine::Close( int style, bool bDraw )
{ {
if( GetClosed() ) if( GetClosed() )
wxASSERT(0); wxASSERT( 0 );
Undraw(); Undraw();
side_style[corner.size()-1] = style; side_style[corner.size() - 1] = style;
corner[corner.size()-1].end_contour = TRUE; corner[corner.size() - 1].end_contour = TRUE;
if( bDraw ) if( bDraw )
Draw(); Draw();
} }
// move corner of polyline // move corner of polyline
// //
void CPolyLine::MoveCorner( int ic, int x, int y ) void CPolyLine::MoveCorner( int ic, int x, int y )
{ {
Undraw(); Undraw();
corner[ic].x = x; corner[ic].x = x;
corner[ic].y = y; corner[ic].y = y;
Draw(); Draw();
} }
// delete corner and adjust arrays // delete corner and adjust arrays
// //
void CPolyLine::DeleteCorner( int ic, bool bDraw ) void CPolyLine::DeleteCorner( int ic, bool bDraw )
{ {
Undraw(); Undraw();
int icont = GetContour( ic ); int icont = GetContour( ic );
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
bool bClosed = icont < GetNumContours()-1 || GetClosed(); bool bClosed = icont < GetNumContours() - 1 || GetClosed();
if( !bClosed ) if( !bClosed )
{ {
// open contour, must be last contour // open contour, must be last contour
corner.erase( corner.begin() + ic ); corner.erase( corner.begin() + ic );
if( ic != istart ) if( ic != istart )
side_style.erase( side_style.begin() + ic-1 ); side_style.erase( side_style.begin() + ic - 1 );
} }
else else
{ {
// closed contour // closed contour
corner.erase( corner.begin() + ic ); corner.erase( corner.begin() + ic );
side_style.erase( side_style.begin() + ic ); side_style.erase( side_style.begin() + ic );
if( ic == iend ) if( ic == iend )
corner[ic-1].end_contour = TRUE; corner[ic - 1].end_contour = TRUE;
} }
if( bClosed && GetContourSize(icont) < 3 ) if( bClosed && GetContourSize( icont ) < 3 )
{ {
// delete the entire contour // delete the entire contour
RemoveContour( icont ); RemoveContour( icont );
} }
if( bDraw ) if( bDraw )
Draw(); Draw();
} }
/******************************************/ /******************************************/
void CPolyLine::RemoveContour( int icont ) void CPolyLine::RemoveContour( int icont )
/******************************************/ /******************************************/
/** /**
* Function RemoveContour * Function RemoveContour
* @param icont = contour number to remove * @param icont = contour number to remove
* remove a contour only if there is more than 1 contour * remove a contour only if there is more than 1 contour
*/ */
{ {
Undraw(); Undraw();
int istart = GetContourStart( icont ); int istart = GetContourStart( icont );
int iend = GetContourEnd( icont ); int iend = GetContourEnd( icont );
if( icont == 0 && GetNumContours() == 1 ) if( icont == 0 && GetNumContours() == 1 )
{ {
// remove the only contour // remove the only contour
wxASSERT(0); wxASSERT( 0 );
} }
else if( icont == GetNumContours()-1 ) else if( icont == GetNumContours() - 1 )
{ {
// remove last contour // remove last contour
corner.erase( corner.begin() + istart, corner.end() ); corner.erase( corner.begin() + istart, corner.end() );
side_style.erase( side_style.begin() + istart, side_style.end() ); side_style.erase( side_style.begin() + istart, side_style.end() );
} }
else else
{ {
// remove closed contour // remove closed contour
for( int ic=iend; ic>=istart; ic-- ) for( int ic = iend; ic>=istart; ic-- )
{ {
corner.erase( corner.begin() + ic ); corner.erase( corner.begin() + ic );
side_style.erase( side_style.begin() + ic ); side_style.erase( side_style.begin() + ic );
} }
} }
Draw(); Draw();
} }
/******************************************/ /******************************************/
void CPolyLine::RemoveAllContours( void ) void CPolyLine::RemoveAllContours( void )
/******************************************/ /******************************************/
/** /**
* function RemoveAllContours * function RemoveAllContours
* removes all corners from the lists. * removes all corners from the lists.
* Others params are not chnaged * Others params are not chnaged
*/ */
{ {
corner.clear( ); corner.clear();
side_style.clear( ); side_style.clear();
} }
...@@ -756,594 +845,651 @@ void CPolyLine::RemoveAllContours( void ) ...@@ -756,594 +845,651 @@ void CPolyLine::RemoveAllContours( void )
*/ */
void CPolyLine::InsertCorner( int ic, int x, int y ) void CPolyLine::InsertCorner( int ic, int x, int y )
{ {
Undraw(); Undraw();
if ( (unsigned)(ic) >= corner.size() ) if( (unsigned) (ic) >= corner.size() )
{ {
corner.push_back( CPolyPt(x,y) ); corner.push_back( CPolyPt( x, y ) );
side_style.push_back( STRAIGHT ); side_style.push_back( STRAIGHT );
} }
else else
{ {
corner.insert( corner.begin() + ic + 1, CPolyPt(x,y) ); corner.insert( corner.begin() + ic + 1, CPolyPt( x, y ) );
side_style.insert( side_style.begin() + ic + 1, STRAIGHT ); side_style.insert( side_style.begin() + ic + 1, STRAIGHT );
} }
if( (unsigned)(ic+1) < corner.size() ) if( (unsigned) (ic + 1) < corner.size() )
{ {
if( corner[ic].end_contour ) if( corner[ic].end_contour )
{ {
corner[ic+1].end_contour = TRUE; corner[ic + 1].end_contour = TRUE;
corner[ic].end_contour = FALSE; corner[ic].end_contour = FALSE;
} }
} }
Draw(); Draw();
} }
// undraw polyline by removing all graphic elements from display list // undraw polyline by removing all graphic elements from display list
// //
void CPolyLine::Undraw() void CPolyLine::Undraw()
{ {
m_HatchLines.clear(); m_HatchLines.clear();
bDrawn = FALSE; bDrawn = FALSE;
} }
// draw polyline by adding all graphics to display list // draw polyline by adding all graphics to display list
// if side style is ARC_CW or ARC_CCW but endpoints are not angled, // if side style is ARC_CW or ARC_CCW but endpoints are not angled,
// convert to STRAIGHT // convert to STRAIGHT
// //
void CPolyLine::Draw( ) void CPolyLine::Draw()
{ {
// first, undraw if necessary
if( bDrawn )
Undraw();
// first, undraw if necessary Hatch();
if( bDrawn ) bDrawn = TRUE;
Undraw();
Hatch();
bDrawn = TRUE;
} }
int CPolyLine::GetX( int ic ) int CPolyLine::GetX( int ic )
{ {
return corner[ic].x; return corner[ic].x;
} }
int CPolyLine::GetY( int ic )
{ int CPolyLine::GetY( int ic )
return corner[ic].y; {
return corner[ic].y;
} }
int CPolyLine::GetEndContour( int ic )
{ int CPolyLine::GetEndContour( int ic )
return corner[ic].end_contour; {
return corner[ic].end_contour;
} }
CRect CPolyLine::GetBounds() CRect CPolyLine::GetBounds()
{ {
CRect r = GetCornerBounds(); CRect r = GetCornerBounds();
r.left -= m_Width/2;
r.right += m_Width/2; r.left -= m_Width / 2;
r.bottom -= m_Width/2; r.right += m_Width / 2;
r.top += m_Width/2; r.bottom -= m_Width / 2;
return r; r.top += m_Width / 2;
return r;
} }
CRect CPolyLine::GetCornerBounds() CRect CPolyLine::GetCornerBounds()
{ {
CRect r; CRect r;
r.left = r.bottom = INT_MAX;
r.right = r.top = INT_MIN; r.left = r.bottom = INT_MAX;
for( unsigned i=0; i<corner.size(); i++ ) r.right = r.top = INT_MIN;
{ for( unsigned i = 0; i<corner.size(); i++ )
r.left = min( r.left, corner[i].x ); {
r.right = max( r.right, corner[i].x ); r.left = min( r.left, corner[i].x );
r.bottom = min( r.bottom, corner[i].y ); r.right = max( r.right, corner[i].x );
r.top = max( r.top, corner[i].y ); r.bottom = min( r.bottom, corner[i].y );
} r.top = max( r.top, corner[i].y );
return r; }
return r;
} }
CRect CPolyLine::GetCornerBounds( int icont ) CRect CPolyLine::GetCornerBounds( int icont )
{ {
CRect r; CRect r;
r.left = r.bottom = INT_MAX;
r.right = r.top = INT_MIN; r.left = r.bottom = INT_MAX;
int istart = GetContourStart( icont ); r.right = r.top = INT_MIN;
int iend = GetContourEnd( icont ); int istart = GetContourStart( icont );
for( int i=istart; i<=iend; i++ ) int iend = GetContourEnd( icont );
{ for( int i = istart; i<=iend; i++ )
r.left = min( r.left, corner[i].x ); {
r.right = max( r.right, corner[i].x ); r.left = min( r.left, corner[i].x );
r.bottom = min( r.bottom, corner[i].y ); r.right = max( r.right, corner[i].x );
r.top = max( r.top, corner[i].y ); r.bottom = min( r.bottom, corner[i].y );
} r.top = max( r.top, corner[i].y );
return r; }
return r;
} }
int CPolyLine::GetNumCorners()
{ int CPolyLine::GetNumCorners()
return corner.size(); {
return corner.size();
} }
int CPolyLine::GetNumSides()
{ int CPolyLine::GetNumSides()
if( GetClosed() ) {
return corner.size(); if( GetClosed() )
else return corner.size();
return corner.size()-1; else
return corner.size() - 1;
} }
int CPolyLine::GetNumContours() int CPolyLine::GetNumContours()
{ {
int ncont = 0; int ncont = 0;
if( !corner.size() )
return 0; if( !corner.size() )
return 0;
for( unsigned ic=0; ic<corner.size(); ic++ )
if( corner[ic].end_contour ) for( unsigned ic = 0; ic<corner.size(); ic++ )
ncont++; if( corner[ic].end_contour )
if( !corner[corner.size()-1].end_contour ) ncont++;
ncont++;
return ncont; if( !corner[corner.size() - 1].end_contour )
ncont++;
return ncont;
} }
int CPolyLine::GetContour( int ic ) int CPolyLine::GetContour( int ic )
{ {
int ncont = 0; int ncont = 0;
for( int i=0; i<ic; i++ )
{ for( int i = 0; i<ic; i++ )
if( corner[i].end_contour ) {
ncont++; if( corner[i].end_contour )
} ncont++;
return ncont; }
return ncont;
} }
int CPolyLine::GetContourStart( int icont ) int CPolyLine::GetContourStart( int icont )
{ {
if( icont == 0 ) if( icont == 0 )
return 0; return 0;
int ncont = 0; int ncont = 0;
for( unsigned i=0; i<corner.size(); i++ ) for( unsigned i = 0; i<corner.size(); i++ )
{ {
if( corner[i].end_contour ) if( corner[i].end_contour )
{ {
ncont++; ncont++;
if( ncont == icont ) if( ncont == icont )
return i+1; return i + 1;
} }
} }
wxASSERT(0);
return 0; wxASSERT( 0 );
return 0;
} }
int CPolyLine::GetContourEnd( int icont ) int CPolyLine::GetContourEnd( int icont )
{ {
if( icont < 0 ) if( icont < 0 )
return 0; return 0;
if( icont == GetNumContours()-1 ) if( icont == GetNumContours() - 1 )
return corner.size()-1; return corner.size() - 1;
int ncont = 0; int ncont = 0;
for( unsigned i=0; i<corner.size(); i++ ) for( unsigned i = 0; i<corner.size(); i++ )
{ {
if( corner[i].end_contour ) if( corner[i].end_contour )
{ {
if( ncont == icont ) if( ncont == icont )
return i; return i;
ncont++; ncont++;
} }
} }
wxASSERT(0);
return 0; wxASSERT( 0 );
return 0;
} }
int CPolyLine::GetContourSize( int icont ) int CPolyLine::GetContourSize( int icont )
{ {
return GetContourEnd(icont) - GetContourStart(icont) + 1; return GetContourEnd( icont ) - GetContourStart( icont ) + 1;
} }
void CPolyLine::SetSideStyle( int is, int style ) void CPolyLine::SetSideStyle( int is, int style )
{ {
Undraw(); Undraw();
CPoint p1, p2; CPoint p1, p2;
if( is == (int)(corner.size()-1) ) if( is == (int) (corner.size() - 1) )
{ {
p1.x = corner[corner.size()-1].x; p1.x = corner[corner.size() - 1].x;
p1.y = corner[corner.size()-1].y; p1.y = corner[corner.size() - 1].y;
p2.x = corner[0].x; p2.x = corner[0].x;
p2.y = corner[0].y; p2.y = corner[0].y;
} }
else else
{ {
p1.x = corner[is].x; p1.x = corner[is].x;
p1.y = corner[is].y; p1.y = corner[is].y;
p2.x = corner[is+1].x; p2.x = corner[is + 1].x;
p2.y = corner[is+1].y; p2.y = corner[is + 1].y;
} }
if( p1.x == p2.x || p1.y == p2.y ) if( p1.x == p2.x || p1.y == p2.y )
side_style[is] = STRAIGHT; side_style[is] = STRAIGHT;
else else
side_style[is] = style; side_style[is] = style;
Draw(); Draw();
} }
int CPolyLine::GetSideStyle( int is )
{ int CPolyLine::GetSideStyle( int is )
return side_style[is]; {
return side_style[is];
} }
int CPolyLine::GetClosed() int CPolyLine::GetClosed()
{ {
if( corner.size() == 0 ) if( corner.size() == 0 )
return 0; return 0;
else else
return corner[corner.size()-1].end_contour; return corner[corner.size() - 1].end_contour;
} }
// draw hatch lines // draw hatch lines
// //
void CPolyLine::Hatch() void CPolyLine::Hatch()
{ {
m_HatchLines.clear(); m_HatchLines.clear();
if( m_HatchStyle == NO_HATCH ) if( m_HatchStyle == NO_HATCH )
{ {
return; return;
} }
int layer = m_layer; int layer = m_layer;
if( GetClosed() ) // If not closed, the poly is beeing created and not finalised. Not not hatch if( GetClosed() ) // If not closed, the poly is beeing created and not finalised. Not not hatch
{ {
enum { enum {
MAXPTS = 100, MAXPTS = 100,
}; };
int xx[MAXPTS], yy[MAXPTS]; int xx[MAXPTS], yy[MAXPTS];
// define range for hatch lines // define range for hatch lines
int min_x = corner[0].x; int min_x = corner[0].x;
int max_x = corner[0].x; int max_x = corner[0].x;
int min_y = corner[0].y; int min_y = corner[0].y;
int max_y = corner[0].y; int max_y = corner[0].y;
for( unsigned ic = 1; ic < corner.size(); ic++ ) for( unsigned ic = 1; ic < corner.size(); ic++ )
{ {
if( corner[ic].x < min_x ) if( corner[ic].x < min_x )
min_x = corner[ic].x; min_x = corner[ic].x;
if( corner[ic].x > max_x ) if( corner[ic].x > max_x )
max_x = corner[ic].x; max_x = corner[ic].x;
if( corner[ic].y < min_y ) if( corner[ic].y < min_y )
min_y = corner[ic].y; min_y = corner[ic].y;
if( corner[ic].y > max_y ) if( corner[ic].y > max_y )
max_y = corner[ic].y; max_y = corner[ic].y;
} }
int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1
double slope = 0.707106*slope_flag; int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1
int spacing; double slope = 0.707106 * slope_flag;
if( m_HatchStyle == DIAGONAL_EDGE ) int spacing;
spacing = 10*PCBU_PER_MIL; if( m_HatchStyle == DIAGONAL_EDGE )
else spacing = 10 * PCBU_PER_MIL;
spacing = 50*PCBU_PER_MIL; else
int max_a, min_a; spacing = 50 * PCBU_PER_MIL;
if( slope_flag == 1 ) int max_a, min_a;
{ if( slope_flag == 1 )
max_a = (int)(max_y - slope*min_x); {
min_a = (int)(min_y - slope*max_x); max_a = (int) (max_y - slope * min_x);
} min_a = (int) (min_y - slope * max_x);
else }
{ else
max_a = (int)(max_y - slope*max_x); {
min_a = (int)(min_y - slope*min_x); max_a = (int) (max_y - slope * max_x);
} min_a = (int) (min_y - slope * min_x);
min_a = (min_a/spacing)*spacing; }
// calculate an offset depending on layer number, for a better display of hatches on a multilayer board min_a = (min_a / spacing) * spacing;
int offset = (layer * 7) / 8;
min_a += offset; // calculate an offset depending on layer number, for a better display of hatches on a multilayer board
int offset = (layer * 7) / 8;
// now calculate and draw hatch lines min_a += offset;
int nc = corner.size();
// loop through hatch lines // now calculate and draw hatch lines
for( int a=min_a; a<max_a; a+=spacing ) int nc = corner.size();
{
// get intersection points for this hatch line // loop through hatch lines
int nloops = 0; for( int a = min_a; a<max_a; a += spacing )
int npts; {
// make this a loop in case my homebrew hatching algorithm screws up // get intersection points for this hatch line
do int nloops = 0;
{ int npts;
npts = 0;
int i_start_contour = 0; // make this a loop in case my homebrew hatching algorithm screws up
for( int ic=0; ic<nc; ic++ ) do
{ {
double x, y, x2, y2; npts = 0;
int ok; int i_start_contour = 0;
if( corner[ic].end_contour || (ic == (int)(corner.size()-1)) ) for( int ic = 0; ic<nc; ic++ )
{ {
ok = FindLineSegmentIntersection( a, slope, double x, y, x2, y2;
corner[ic].x, corner[ic].y, int ok;
corner[i_start_contour].x, corner[i_start_contour].y, if( corner[ic].end_contour || ( ic == (int) (corner.size() - 1) ) )
side_style[ic], {
&x, &y, &x2, &y2 ); ok = FindLineSegmentIntersection( a, slope,
i_start_contour = ic + 1; corner[ic].x, corner[ic].y,
} corner[i_start_contour].x, corner[i_start_contour].y,
else side_style[ic],
{ &x, &y, &x2, &y2 );
ok = FindLineSegmentIntersection( a, slope, i_start_contour = ic + 1;
corner[ic].x, corner[ic].y, }
corner[ic+1].x, corner[ic+1].y, else
side_style[ic], {
&x, &y, &x2, &y2 ); ok = FindLineSegmentIntersection( a, slope,
} corner[ic].x, corner[ic].y,
if( ok ) corner[ic + 1].x, corner[ic + 1].y,
{ side_style[ic],
xx[npts] = (int)x; &x, &y, &x2, &y2 );
yy[npts] = (int)y; }
npts++; if( ok )
wxASSERT( npts<MAXPTS ); // overflow {
} xx[npts] = (int) x;
if( ok == 2 ) yy[npts] = (int) y;
{ npts++;
xx[npts] = (int)x2; wxASSERT( npts<MAXPTS ); // overflow
yy[npts] = (int)y2; }
npts++; if( ok == 2 )
wxASSERT( npts<MAXPTS ); // overflow {
} xx[npts] = (int) x2;
} yy[npts] = (int) y2;
nloops++; npts++;
a += PCBU_PER_MIL/100; wxASSERT( npts<MAXPTS ); // overflow
} while( npts%2 != 0 && nloops < 3 ); }
}
nloops++;
a += PCBU_PER_MIL / 100;
} while( npts % 2 != 0 && nloops < 3 );
/* DICK 1/22/08: this was firing repeatedly on me, needed to comment out to get /* DICK 1/22/08: this was firing repeatedly on me, needed to comment out to get
my work done: * my work done:
wxASSERT( npts%2==0 ); // odd number of intersection points, error * wxASSERT( npts%2==0 ); // odd number of intersection points, error
*/ */
// sort points in order of descending x (if more than 2) // sort points in order of descending x (if more than 2)
if( npts>2 ) if( npts>2 )
{ {
for( int istart=0; istart<(npts-1); istart++ ) for( int istart = 0; istart<(npts - 1); istart++ )
{ {
int max_x = INT_MIN; int max_x = INT_MIN;
int imax = INT_MIN; int imax = INT_MIN;
for( int i=istart; i<npts; i++ ) for( int i = istart; i<npts; i++ )
{ {
if( xx[i] > max_x ) if( xx[i] > max_x )
{ {
max_x = xx[i]; max_x = xx[i];
imax = i; imax = i;
} }
} }
int temp = xx[istart];
xx[istart] = xx[imax]; int temp = xx[istart];
xx[imax] = temp; xx[istart] = xx[imax];
temp = yy[istart]; xx[imax] = temp;
yy[istart] = yy[imax]; temp = yy[istart];
yy[imax] = temp; yy[istart] = yy[imax];
} yy[imax] = temp;
} }
}
// draw lines
for( int ip=0; ip<npts; ip+=2 ) // draw lines
{ for( int ip = 0; ip<npts; ip += 2 )
double dx = xx[ip+1] - xx[ip]; {
if( m_HatchStyle == DIAGONAL_FULL || fabs(dx) < 40*NM_PER_MIL ) double dx = xx[ip + 1] - xx[ip];
{ if( m_HatchStyle == DIAGONAL_FULL || fabs( dx ) < 40 * NM_PER_MIL )
m_HatchLines.push_back(CSegment(xx[ip], yy[ip], xx[ip+1], yy[ip+1]) ); {
} m_HatchLines.push_back( CSegment( xx[ip], yy[ip], xx[ip + 1], yy[ip + 1] ) );
else }
{ else
double dy = yy[ip+1] - yy[ip]; {
double slope = dy/dx; double dy = yy[ip + 1] - yy[ip];
if( dx > 0 ) double slope = dy / dx;
dx = 20*NM_PER_MIL; if( dx > 0 )
else dx = 20 * NM_PER_MIL;
dx = -20*NM_PER_MIL; else
double x1 = xx[ip] + dx; dx = -20 * NM_PER_MIL;
double x2 = xx[ip+1] - dx; double x1 = xx[ip] + dx;
double y1 = yy[ip] + dx*slope; double x2 = xx[ip + 1] - dx;
double y2 = yy[ip+1] - dx*slope; double y1 = yy[ip] + dx * slope;
m_HatchLines.push_back(CSegment(xx[ip], yy[ip], to_int(x1), to_int(y1)) ); double y2 = yy[ip + 1] - dx * slope;
m_HatchLines.push_back(CSegment(xx[ip+1], yy[ip+1], to_int(x2), to_int(y2)) ); m_HatchLines.push_back( CSegment( xx[ip], yy[ip], to_int( x1 ), to_int( y1 ) ) );
} m_HatchLines.push_back( CSegment( xx[ip + 1], yy[ip + 1], to_int( x2 ),
} to_int( y2 ) ) );
} // end for }
} }
} // end for
}
} }
// test to see if a point is inside polyline // test to see if a point is inside polyline
// //
bool CPolyLine::TestPointInside( int x, int y ) bool CPolyLine::TestPointInside( int x, int y )
{ {
enum { MAXPTS = 100 }; enum {
if( !GetClosed() ) MAXPTS = 100
wxASSERT(0); };
if( !GetClosed() )
// define line passing through (x,y), with slope = 2/3; wxASSERT( 0 );
// get intersection points
double xx[MAXPTS], yy[MAXPTS]; // define line passing through (x,y), with slope = 2/3;
double slope = (double)2.0/3.0; // get intersection points
double a = y - slope*x; double xx[MAXPTS], yy[MAXPTS];
int nloops = 0; double slope = (double) 2.0 / 3.0;
int npts; double a = y - slope * x;
// make this a loop so if my homebrew algorithm screws up, we try it again int nloops = 0;
do int npts;
{
// now find all intersection points of line with polyline sides // make this a loop so if my homebrew algorithm screws up, we try it again
npts = 0; do
for( int icont=0; icont<GetNumContours(); icont++ ) {
{ // now find all intersection points of line with polyline sides
int istart = GetContourStart( icont ); npts = 0;
int iend = GetContourEnd( icont ); for( int icont = 0; icont<GetNumContours(); icont++ )
for( int ic=istart; ic<=iend; ic++ ) {
{ int istart = GetContourStart( icont );
double x, y, x2, y2; int iend = GetContourEnd( icont );
int ok; for( int ic = istart; ic<=iend; ic++ )
if( ic == istart ) {
ok = FindLineSegmentIntersection( a, slope, double x, y, x2, y2;
corner[iend].x, corner[iend].y, int ok;
corner[istart].x, corner[istart].y, if( ic == istart )
side_style[corner.size()-1], ok = FindLineSegmentIntersection( a, slope,
&x, &y, &x2, &y2 ); corner[iend].x, corner[iend].y,
else corner[istart].x, corner[istart].y,
ok = FindLineSegmentIntersection( a, slope, side_style[corner.size() - 1],
corner[ic-1].x, corner[ic-1].y, &x, &y, &x2, &y2 );
corner[ic].x, corner[ic].y, else
side_style[ic-1], ok = FindLineSegmentIntersection( a, slope,
&x, &y, &x2, &y2 ); corner[ic - 1].x, corner[ic - 1].y,
if( ok ) corner[ic].x, corner[ic].y,
{ side_style[ic - 1],
xx[npts] = (int)x; &x, &y, &x2, &y2 );
yy[npts] = (int)y; if( ok )
npts++; {
wxASSERT( npts<MAXPTS ); // overflow xx[npts] = (int) x;
} yy[npts] = (int) y;
if( ok == 2 ) npts++;
{ wxASSERT( npts<MAXPTS ); // overflow
xx[npts] = (int)x2; }
yy[npts] = (int)y2; if( ok == 2 )
npts++; {
wxASSERT( npts<MAXPTS ); // overflow xx[npts] = (int) x2;
} yy[npts] = (int) y2;
} npts++;
} wxASSERT( npts<MAXPTS ); // overflow
nloops++; }
a += PCBU_PER_MIL/100; }
} while( npts%2 != 0 && nloops < 3 ); }
wxASSERT( npts%2==0 ); // odd number of intersection points, error
nloops++;
// count intersection points to right of (x,y), if odd (x,y) is inside polyline a += PCBU_PER_MIL / 100;
int ncount = 0; } while( npts % 2 != 0 && nloops < 3 );
for( int ip=0; ip<npts; ip++ )
{ wxASSERT( npts % 2==0 ); // odd number of intersection points, error
if( xx[ip] == x && yy[ip] == y )
return FALSE; // (x,y) is on a side, call it outside // count intersection points to right of (x,y), if odd (x,y) is inside polyline
else if( xx[ip] > x ) int ncount = 0;
ncount++; for( int ip = 0; ip<npts; ip++ )
} {
if( ncount%2 ) if( xx[ip] == x && yy[ip] == y )
return TRUE; return FALSE; // (x,y) is on a side, call it outside
else else if( xx[ip] > x )
return FALSE; ncount++;
}
if( ncount % 2 )
return TRUE;
else
return FALSE;
} }
// test to see if a point is inside polyline contour // test to see if a point is inside polyline contour
// //
bool CPolyLine::TestPointInsideContour( int icont, int x, int y ) bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
{ {
if( icont >= GetNumContours() ) if( icont >= GetNumContours() )
return FALSE; return FALSE;
enum { MAXPTS = 100 }; enum {
if( !GetClosed() ) MAXPTS = 100
wxASSERT(0); };
if( !GetClosed() )
// define line passing through (x,y), with slope = 2/3; wxASSERT( 0 );
// get intersection points
double xx[MAXPTS], yy[MAXPTS]; // define line passing through (x,y), with slope = 2/3;
double slope = (double)2.0/3.0; // get intersection points
double a = y - slope*x; double xx[MAXPTS], yy[MAXPTS];
int nloops = 0; double slope = (double) 2.0 / 3.0;
int npts; double a = y - slope * x;
// make this a loop so if my homebrew algorithm screws up, we try it again int nloops = 0;
do int npts;
{
// now find all intersection points of line with polyline sides // make this a loop so if my homebrew algorithm screws up, we try it again
npts = 0; do
int istart = GetContourStart( icont ); {
int iend = GetContourEnd( icont ); // now find all intersection points of line with polyline sides
for( int ic=istart; ic<=iend; ic++ ) npts = 0;
{ int istart = GetContourStart( icont );
double x, y, x2, y2; int iend = GetContourEnd( icont );
int ok; for( int ic = istart; ic<=iend; ic++ )
if( ic == istart ) {
ok = FindLineSegmentIntersection( a, slope, double x, y, x2, y2;
corner[iend].x, corner[iend].y, int ok;
corner[istart].x, corner[istart].y, if( ic == istart )
side_style[corner.size()-1], ok = FindLineSegmentIntersection( a, slope,
&x, &y, &x2, &y2 ); corner[iend].x, corner[iend].y,
else corner[istart].x, corner[istart].y,
ok = FindLineSegmentIntersection( a, slope, side_style[corner.size() - 1],
corner[ic-1].x, corner[ic-1].y, &x, &y, &x2, &y2 );
corner[ic].x, corner[ic].y, else
side_style[ic-1], ok = FindLineSegmentIntersection( a, slope,
&x, &y, &x2, &y2 ); corner[ic - 1].x, corner[ic - 1].y,
if( ok ) corner[ic].x, corner[ic].y,
{ side_style[ic - 1],
xx[npts] = (int)x; &x, &y, &x2, &y2 );
yy[npts] = (int)y; if( ok )
npts++; {
wxASSERT( npts<MAXPTS ); // overflow xx[npts] = (int) x;
} yy[npts] = (int) y;
if( ok == 2 ) npts++;
{ wxASSERT( npts<MAXPTS ); // overflow
xx[npts] = (int)x2; }
yy[npts] = (int)y2; if( ok == 2 )
npts++; {
wxASSERT( npts<MAXPTS ); // overflow xx[npts] = (int) x2;
} yy[npts] = (int) y2;
} npts++;
nloops++; wxASSERT( npts<MAXPTS ); // overflow
a += PCBU_PER_MIL/100; }
} while( npts%2 != 0 && nloops < 3 ); }
wxASSERT( npts%2==0 ); // odd number of intersection points, error
nloops++;
// count intersection points to right of (x,y), if odd (x,y) is inside polyline a += PCBU_PER_MIL / 100;
int ncount = 0; } while( npts % 2 != 0 && nloops < 3 );
for( int ip=0; ip<npts; ip++ )
{ wxASSERT( npts % 2==0 ); // odd number of intersection points, error
if( xx[ip] == x && yy[ip] == y )
return FALSE; // (x,y) is on a side, call it outside // count intersection points to right of (x,y), if odd (x,y) is inside polyline
else if( xx[ip] > x ) int ncount = 0;
ncount++; for( int ip = 0; ip<npts; ip++ )
} {
if( ncount%2 ) if( xx[ip] == x && yy[ip] == y )
return TRUE; return FALSE; // (x,y) is on a side, call it outside
else else if( xx[ip] > x )
return FALSE; ncount++;
}
if( ncount % 2 )
return TRUE;
else
return FALSE;
} }
// copy data from another poly, but don't draw it // copy data from another poly, but don't draw it
// //
void CPolyLine::Copy( CPolyLine * src ) void CPolyLine::Copy( CPolyLine* src )
{ {
Undraw(); Undraw();
// copy corners // copy corners
for( unsigned ii=0; ii < src->corner.size(); ii++ ) for( unsigned ii = 0; ii < src->corner.size(); ii++ )
corner.push_back(src->corner[ii]); corner.push_back( src->corner[ii] );
// copy side styles
for( unsigned ii=0; ii < src->side_style.size(); ii++ ) // copy side styles
side_style.push_back(src->side_style[ii]); for( unsigned ii = 0; ii < src->side_style.size(); ii++ )
// don't copy the Gpc_poly, just clear the old one side_style.push_back( src->side_style[ii] );
FreeGpcPoly();
#ifdef USE_GPC_POLY_LIB
// don't copy the Gpc_poly, just clear the old one
FreeGpcPoly();
#endif
} }
/*******************************************/ /*******************************************/
bool CPolyLine::IsCutoutContour( int icont ) bool CPolyLine::IsCutoutContour( int icont )
/*******************************************/ /*******************************************/
/* /*
* return true if the corner icont is inside the outline (i.e it is a hole) * return true if the corner icont is inside the outline (i.e it is a hole)
*/ */
{ {
int ncont = GetContour( icont ); int ncont = GetContour( icont );
if ( ncont == 0 ) // the first contour is the main outline, not an hole
return false; if( ncont == 0 ) // the first contour is the main outline, not an hole
return true; return false;
return true;
} }
void CPolyLine::MoveOrigin( int x_off, int y_off ) void CPolyLine::MoveOrigin( int x_off, int y_off )
{ {
Undraw(); Undraw();
for( int ic=0; ic < GetNumCorners(); ic++ ) for( int ic = 0; ic < GetNumCorners(); ic++ )
{ {
SetX( ic, GetX(ic) + x_off ); SetX( ic, GetX( ic ) + x_off );
SetY( ic, GetY(ic) + y_off ); SetY( ic, GetY( ic ) + y_off );
} }
Draw();
Draw();
} }
...@@ -1351,191 +1497,208 @@ void CPolyLine::MoveOrigin( int x_off, int y_off ) ...@@ -1351,191 +1497,208 @@ void CPolyLine::MoveOrigin( int x_off, int y_off )
// the calling function should Undraw() before calling them, // the calling function should Undraw() before calling them,
// and Draw() after // and Draw() after
// //
void CPolyLine::SetX( int ic, int x ) { corner[ic].x = x; } void CPolyLine::SetX( int ic, int x )
void CPolyLine::SetY( int ic, int y ) { corner[ic].y = y; } {
corner[ic].x = x;
}
void CPolyLine::SetY( int ic, int y )
{
corner[ic].y = y;
}
void CPolyLine::SetEndContour( int ic, bool end_contour ) void CPolyLine::SetEndContour( int ic, bool end_contour )
{ {
corner[ic].end_contour = end_contour; corner[ic].end_contour = end_contour;
} }
// Create CPolyLine for a pad // Create CPolyLine for a pad
// //
CPolyLine * CPolyLine::MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle ) CPolyLine* CPolyLine::MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle )
{ {
CPolyLine * poly = new CPolyLine; CPolyLine* poly = new CPolyLine;
int dx = l/2; int dx = l / 2;
int dy = w/2; int dy = w / 2;
if( angle%180 == 90 )
{ if( angle % 180 == 90 )
dx = w/2; {
dy = l/2; dx = w / 2;
} dy = l / 2;
if( type == PAD_ROUND ) }
{ if( type == PAD_ROUND )
poly->Start( 0, x-dx, y, 0 ); {
poly->AppendCorner( x, y+dy, ARC_CW, 0 ); poly->Start( 0, x - dx, y, 0 );
poly->AppendCorner( x+dx, y, ARC_CW, 0 ); poly->AppendCorner( x, y + dy, ARC_CW, 0 );
poly->AppendCorner( x, y-dy, ARC_CW, 0 ); poly->AppendCorner( x + dx, y, ARC_CW, 0 );
poly->Close( ARC_CW ); poly->AppendCorner( x, y - dy, ARC_CW, 0 );
} poly->Close( ARC_CW );
return poly; }
return poly;
} }
// Add cutout for a pad // Add cutout for a pad
// Convert arcs to multiple straight lines // Convert arcs to multiple straight lines
// Do NOT draw or undraw // Do NOT draw or undraw
// //
void CPolyLine::AddContourForPadClearance( int type, int x, int y, int w, void CPolyLine::AddContourForPadClearance( int type,
int l, int r, int angle, int fill_clearance, int x,
int hole_w, int hole_clearance, bool bThermal, int spoke_w ) int y,
int w,
int l,
int r,
int angle,
int fill_clearance,
int hole_w,
int hole_clearance,
bool bThermal,
int spoke_w )
{ {
int dx = l/2; int dx = l / 2;
int dy = w/2; int dy = w / 2;
if( angle%180 == 90 )
{ if( angle % 180 == 90 )
dx = w/2; {
dy = l/2; dx = w / 2;
} dy = l / 2;
int x_clearance = max( fill_clearance, hole_clearance+hole_w/2-dx); }
int y_clearance = max( fill_clearance, hole_clearance+hole_w/2-dy); int x_clearance = max( fill_clearance, hole_clearance + hole_w / 2 - dx );
dx += x_clearance; int y_clearance = max( fill_clearance, hole_clearance + hole_w / 2 - dy );
dy += y_clearance; dx += x_clearance;
if( !bThermal ) dy += y_clearance;
{ if( !bThermal )
// normal clearance {
if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) ) // normal clearance
{ if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) )
AppendCorner( x-dx, y, ARC_CW, 0 ); {
AppendCorner( x, y+dy, ARC_CW, 0 ); AppendCorner( x - dx, y, ARC_CW, 0 );
AppendCorner( x+dx, y, ARC_CW, 0 ); AppendCorner( x, y + dy, ARC_CW, 0 );
AppendCorner( x, y-dy, ARC_CW, 0 ); AppendCorner( x + dx, y, ARC_CW, 0 );
Close( ARC_CW ); AppendCorner( x, y - dy, ARC_CW, 0 );
} Close( ARC_CW );
else if( type == PAD_SQUARE || type == PAD_RECT }
|| type == PAD_RRECT || type == PAD_OVAL ) else if( type == PAD_SQUARE || type == PAD_RECT
{ || type == PAD_RRECT || type == PAD_OVAL )
AppendCorner( x-dx, y-dy, STRAIGHT, 0 ); {
AppendCorner( x+dx, y-dy, STRAIGHT, 0 ); AppendCorner( x - dx, y - dy, STRAIGHT, 0 );
AppendCorner( x+dx, y+dy, STRAIGHT, 0 ); AppendCorner( x + dx, y - dy, STRAIGHT, 0 );
AppendCorner( x-dx, y+dy, STRAIGHT, 0 ); AppendCorner( x + dx, y + dy, STRAIGHT, 0 );
Close( STRAIGHT ); AppendCorner( x - dx, y + dy, STRAIGHT, 0 );
} Close( STRAIGHT );
} }
else }
{ else
// thermal relief {
if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) ) // thermal relief
{ if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) )
// draw 4 "wedges" {
double r = max(w/2 + fill_clearance, hole_w/2 + hole_clearance); // draw 4 "wedges"
double start_angle = asin( spoke_w/(2.0*r) ); double r = max( w / 2 + fill_clearance, hole_w / 2 + hole_clearance );
double th1, th2, corner_x, corner_y; double start_angle = asin( spoke_w / (2.0 * r) );
th1 = th2 = corner_x = corner_y = 0; // gcc warning fix double th1, th2, corner_x, corner_y;
for( int i=0; i<4; i++ ) th1 = th2 = corner_x = corner_y = 0; // gcc warning fix
{ for( int i = 0; i<4; i++ )
if( i == 0 ) {
{ if( i == 0 )
corner_x = spoke_w/2; {
corner_y = spoke_w/2; corner_x = spoke_w / 2;
th1 = start_angle; corner_y = spoke_w / 2;
th2 = pi/2.0 - start_angle; th1 = start_angle;
} th2 = pi / 2.0 - start_angle;
else if( i == 1 ) }
{ else if( i == 1 )
corner_x = -spoke_w/2; {
corner_y = spoke_w/2; corner_x = -spoke_w / 2;
th1 = pi/2.0 + start_angle; corner_y = spoke_w / 2;
th2 = pi - start_angle; th1 = pi / 2.0 + start_angle;
} th2 = pi - start_angle;
else if( i == 2 ) }
{ else if( i == 2 )
corner_x = -spoke_w/2; {
corner_y = -spoke_w/2; corner_x = -spoke_w / 2;
th1 = -pi + start_angle; corner_y = -spoke_w / 2;
th2 = -pi/2.0 - start_angle; th1 = -pi + start_angle;
} th2 = -pi / 2.0 - start_angle;
else if( i == 3 ) }
{ else if( i == 3 )
corner_x = spoke_w/2; {
corner_y = -spoke_w/2; corner_x = spoke_w / 2;
th1 = -pi/2.0 + start_angle; corner_y = -spoke_w / 2;
th2 = -start_angle; th1 = -pi / 2.0 + start_angle;
} th2 = -start_angle;
AppendCorner( to_int(x+corner_x), to_int(y+corner_y), STRAIGHT, 0 ); }
AppendCorner( to_int(x+r*cos(th1)), to_int(y+r*sin(th1)), STRAIGHT, 0 ); AppendCorner( to_int( x + corner_x ), to_int( y + corner_y ), STRAIGHT, 0 );
AppendCorner( to_int(x+r*cos(th2)), to_int(y+r*sin(th2)), ARC_CCW, 0 ); AppendCorner( to_int( x + r * cos( th1 ) ), to_int( y + r * sin(
Close( STRAIGHT ); th1 ) ), STRAIGHT, 0 );
} AppendCorner( to_int( x + r * cos( th2 ) ), to_int( y + r * sin(
} th2 ) ), ARC_CCW, 0 );
else if( type == PAD_SQUARE || type == PAD_RECT Close( STRAIGHT );
|| type == PAD_RRECT || type == PAD_OVAL ) }
{ }
// draw 4 rectangles else if( type == PAD_SQUARE || type == PAD_RECT
int xL = x - dx; || type == PAD_RRECT || type == PAD_OVAL )
int xR = x - spoke_w/2; {
int yB = y - dy; // draw 4 rectangles
int yT = y - spoke_w/2; int xL = x - dx;
AppendCorner( xL, yB, STRAIGHT, 0 ); int xR = x - spoke_w / 2;
AppendCorner( xR, yB, STRAIGHT, 0 ); int yB = y - dy;
AppendCorner( xR, yT, STRAIGHT, 0 ); int yT = y - spoke_w / 2;
AppendCorner( xL, yT, STRAIGHT, 0 ); AppendCorner( xL, yB, STRAIGHT, 0 );
Close( STRAIGHT ); AppendCorner( xR, yB, STRAIGHT, 0 );
xL = x + spoke_w/2; AppendCorner( xR, yT, STRAIGHT, 0 );
xR = x + dx; AppendCorner( xL, yT, STRAIGHT, 0 );
AppendCorner( xL, yB, STRAIGHT, 0 ); Close( STRAIGHT );
AppendCorner( xR, yB, STRAIGHT, 0 ); xL = x + spoke_w / 2;
AppendCorner( xR, yT, STRAIGHT, 0 ); xR = x + dx;
AppendCorner( xL, yT, STRAIGHT, 0 ); AppendCorner( xL, yB, STRAIGHT, 0 );
Close( STRAIGHT ); AppendCorner( xR, yB, STRAIGHT, 0 );
xL = x - dx; AppendCorner( xR, yT, STRAIGHT, 0 );
xR = x - spoke_w/2; AppendCorner( xL, yT, STRAIGHT, 0 );
yB = y + spoke_w/2; Close( STRAIGHT );
yT = y + dy; xL = x - dx;
AppendCorner( xL, yB, STRAIGHT, 0 ); xR = x - spoke_w / 2;
AppendCorner( xR, yB, STRAIGHT, 0 ); yB = y + spoke_w / 2;
AppendCorner( xR, yT, STRAIGHT, 0 ); yT = y + dy;
AppendCorner( xL, yT, STRAIGHT, 0 ); AppendCorner( xL, yB, STRAIGHT, 0 );
Close( STRAIGHT ); AppendCorner( xR, yB, STRAIGHT, 0 );
xL = x + spoke_w/2; AppendCorner( xR, yT, STRAIGHT, 0 );
xR = x + dx; AppendCorner( xL, yT, STRAIGHT, 0 );
AppendCorner( xL, yB, STRAIGHT, 0 ); Close( STRAIGHT );
AppendCorner( xR, yB, STRAIGHT, 0 ); xL = x + spoke_w / 2;
AppendCorner( xR, yT, STRAIGHT, 0 ); xR = x + dx;
AppendCorner( xL, yT, STRAIGHT, 0 ); AppendCorner( xL, yB, STRAIGHT, 0 );
Close( STRAIGHT ); AppendCorner( xR, yB, STRAIGHT, 0 );
} AppendCorner( xR, yT, STRAIGHT, 0 );
} AppendCorner( xL, yT, STRAIGHT, 0 );
return; Close( STRAIGHT );
}
}
return;
} }
void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num )
{
// get radius
double r = sqrt( (double)(xi-xc)*(xi-xc) + (double)(yi-yc)*(yi-yc) );
// get angles of start and finish
double th_i = atan2( (double)yi-yc, (double)xi-xc );
double th_f = atan2( (double)yf-yc, (double)xf-xc );
double th_d = (th_f - th_i)/(num-1);
double theta = th_i;
// generate arc
for( int ic=0; ic<num; ic++ )
{
int x = to_int(xc + r*cos(theta));
int y = to_int(yc + r*sin(theta));
AppendCorner( x, y, STRAIGHT, 0 );
theta += th_d;
}
Close( STRAIGHT );
}
void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num )
void CPolyLine::ClipGpcPolygon( gpc_op op, CPolyLine * clip_poly )
{ {
gpc_polygon * result = new gpc_polygon; // get radius
gpc_polygon_clip( op, m_gpc_poly, clip_poly->GetGpcPoly(), result ); double r = sqrt( (double) (xi - xc) * (xi - xc) + (double) (yi - yc) * (yi - yc) );
gpc_free_polygon( m_gpc_poly );
delete m_gpc_poly; // get angles of start and finish
m_gpc_poly = result; double th_i = atan2( (double) yi - yc, (double) xi - xc );
double th_f = atan2( (double) yf - yc, (double) xf - xc );
double th_d = (th_f - th_i) / (num - 1);
double theta = th_i;
// generate arc
for( int ic = 0; ic<num; ic++ )
{
int x = to_int( xc + r * cos( theta ) );
int y = to_int( yc + r * sin( theta ) );
AppendCorner( x, y, STRAIGHT, 0 );
theta += th_d;
}
Close( STRAIGHT );
} }
...@@ -5,10 +5,10 @@ ...@@ -5,10 +5,10 @@
// There may be multiple contours in a polyline. // There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed. // The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays, // All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of // separated by setting the end_contour flag of the last corner of
// each contour. // each contour.
// //
// When used for copper areas, the first contour is the outer edge // When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper. // of the area, subsequent ones are "holes" in the copper.
#ifndef POLYLINE_H #ifndef POLYLINE_H
...@@ -16,6 +16,9 @@ ...@@ -16,6 +16,9 @@
#include <vector> #include <vector>
#define USE_GPC_POLY_LIB
//#define USE_GPL_POLY_LIB
#include "defs-macros.h" #include "defs-macros.h"
#include "GenericPolygonClipperLibrary.h" #include "GenericPolygonClipperLibrary.h"
...@@ -37,12 +40,12 @@ public: ...@@ -37,12 +40,12 @@ public:
}; };
class CArc { class CArc {
public: public:
enum{ MAX_STEP = 50*25400 }; // max step is 20 mils enum{ MAX_STEP = 50*25400 }; // max step is 20 mils
enum{ MIN_STEPS = 18 }; // min step is 5 degrees enum{ MIN_STEPS = 18 }; // min step is 5 degrees
int style; int style;
int xi, yi, xf, yf; int xi, yi, xf, yf;
int n_steps; // number of straight-line segments in gpc_poly int n_steps; // number of straight-line segments in gpc_poly
bool bFound; bool bFound;
}; };
...@@ -117,22 +120,32 @@ public: ...@@ -117,22 +120,32 @@ public:
void SetEndContour( int ic, bool end_contour ); void SetEndContour( int ic, bool end_contour );
void SetSideStyle( int is, int style ); void SetSideStyle( int is, int style );
// GPC functions
int MakeGpcPoly( int icontour=0, std::vector<CArc> * arc_array=NULL );
int FreeGpcPoly();
gpc_polygon * GetGpcPoly(){ return m_gpc_poly; };
int NormalizeWithGpc( std::vector<CPolyLine*> * pa=NULL, bool bRetainArcs=FALSE );
int RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa=NULL ); int RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa=NULL );
CPolyLine * MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle ); CPolyLine * MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle );
void AddContourForPadClearance( int type, int x, int y, int w, void AddContourForPadClearance( int type, int x, int y, int w,
int l, int r, int angle, int fill_clearance, int l, int r, int angle, int fill_clearance,
int hole_w, int hole_clearance, bool bThermal=FALSE, int spoke_w=0 ); int hole_w, int hole_clearance, bool bThermal=FALSE, int spoke_w=0 );
void ClipGpcPolygon( gpc_op op, CPolyLine * poly );
int MakePolygonFromAreaOutlines( int icontour, std::vector<CArc> * arc_array );
void FreePolygon();
int NormalizeAreaOutlines( std::vector<CPolyLine*> * pa=NULL, bool bRetainArcs=FALSE );
#ifdef USE_GPC_POLY_LIB
// GPC functions
int MakeGpcPoly( int icontour=0, std::vector<CArc> * arc_array=NULL );
void FreeGpcPoly();
gpc_polygon * GetGpcPoly(){ return m_gpc_poly; };
int NormalizeWithGpc( std::vector<CPolyLine*> * pa=NULL, bool bRetainArcs=FALSE );
#endif
// PHP functions // PHP functions
#ifdef USE_GPL_POLY_LIB
int MakePhpPoly(); int MakePhpPoly();
void FreePhpPoly(); void FreePhpPoly();
void ClipPhpPolygon( int php_op, CPolyLine * poly ); void ClipPhpPolygon( int php_op, CPolyLine * poly );
polygon * GetPhpPoly(){ return m_php_poly; };
#endif
private: private:
int m_layer; // layer to draw on int m_layer; // layer to draw on
......
// file php_polygon.cpp // file php_polygon.cpp
// This is a port of a php class written by Brenor Brophy (see below) // This is a port of a php class written by Brenor Brophy (see below)
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
...@@ -44,6 +45,7 @@ ...@@ -44,6 +45,7 @@
** 1.1 09/04/2005 Added Move(), Rotate(), isPolyInside() and bRect() methods. ** 1.1 09/04/2005 Added Move(), Rotate(), isPolyInside() and bRect() methods.
** Added software license language to header comments ** Added software license language to header comments
*/ */
//#include "stdafx.h" //#include "stdafx.h"
#include <stdio.h> #include <stdio.h>
...@@ -57,108 +59,119 @@ ...@@ -57,108 +59,119 @@
#include "php_polygon.h" #include "php_polygon.h"
const double PT = 0.99999; const double PT = 0.99999;
//const double eps = (1.0 - PT)/10.0; //const double eps = (1.0 - PT)/10.0;
const double eps = 0.0; const double eps = 0.0;
polygon::polygon( vertex * first ) polygon::polygon( vertex* first )
{ {
m_first = first; m_first = first;
m_cnt = 0; m_cnt = 0;
} }
polygon::~polygon() polygon::~polygon()
{ {
while( m_cnt > 1 ) while( m_cnt > 1 )
{ {
vertex * v = getFirst(); vertex* v = getFirst();
del( v->m_nextV ); del( v->m_nextV );
} }
if( m_first )
{ if( m_first )
delete m_first; {
} delete m_first;
}
} }
vertex * polygon::getFirst()
{ vertex* polygon::getFirst()
return m_first; {
return m_first;
} }
polygon * polygon::NextPoly()
{ polygon* polygon::NextPoly()
return m_first->NextPoly(); {
return m_first->NextPoly();
} }
/* /*
** Add a vertex object to the polygon (vertex is added at the "end" of the list) ** Add a vertex object to the polygon (vertex is added at the "end" of the list)
** Which because polygons are closed lists means it is added just before the first ** Which because polygons are closed lists means it is added just before the first
** vertex. ** vertex.
*/ */
void polygon::add( vertex * nv ) void polygon::add( vertex* nv )
{ {
if ( m_cnt == 0 ) // If this is the first vertex in the polygon if( m_cnt == 0 ) // If this is the first vertex in the polygon
{ {
m_first = nv; // Save a reference to it in the polygon m_first = nv; // Save a reference to it in the polygon
m_first->setNext(nv); // Set its pointer to point to itself m_first->setNext( nv ); // Set its pointer to point to itself
m_first->setPrev(nv); // because it is the only vertex in the list m_first->setPrev( nv ); // because it is the only vertex in the list
segment * ps = m_first->Nseg(); // Get ref to the Next segment object segment* ps = m_first->Nseg(); // Get ref to the Next segment object
m_first->setPseg(ps); // and save it as Prev segment as well m_first->setPseg( ps ); // and save it as Prev segment as well
} }
else // At least one other vertex already exists else // At least one other vertex already exists
{ {
// p <-> nv <-> n // p <-> nv <-> n
// ps ns // ps ns
vertex * n = m_first; // Get a ref to the first vertex in the list vertex* n = m_first; // Get a ref to the first vertex in the list
vertex * p = n->Prev(); // Get ref to previous vertex vertex* p = n->Prev(); // Get ref to previous vertex
n->setPrev(nv); // Add at end of list (just before first) n->setPrev( nv ); // Add at end of list (just before first)
nv->setNext(n); // link the new vertex to it nv->setNext( n ); // link the new vertex to it
nv->setPrev(p); // link to the pervious EOL vertex nv->setPrev( p ); // link to the pervious EOL vertex
p->setNext(nv); // And finally link the previous EOL vertex p->setNext( nv ); // And finally link the previous EOL vertex
// Segments // Segments
segment * ns = nv->Nseg(); // Get ref to the new next segment segment* ns = nv->Nseg(); // Get ref to the new next segment
segment * ps = p->Nseg(); // Get ref to the previous segment segment* ps = p->Nseg(); // Get ref to the previous segment
n->setPseg(ns); // Set new previous seg for m_first n->setPseg( ns ); // Set new previous seg for m_first
nv->setPseg(ps); // Set previous seg of the new vertex nv->setPseg( ps ); // Set previous seg of the new vertex
} }
m_cnt++; // Increment the count of vertices m_cnt++; // Increment the count of vertices
} }
/* /*
** Create a vertex and then add it to the polygon ** Create a vertex and then add it to the polygon
*/ */
void polygon::addv ( double x, double y, void polygon::addv( double x, double y,
double xc, double yc, int d ) double xc, double yc, int d )
{ {
vertex * nv = new vertex( x, y, xc, yc, d ); vertex* nv = new vertex( x, y, xc, yc, d );
add( nv );
add( nv );
} }
/* /*
** Delete a vertex object from the polygon. This is not used by the main algorithm ** Delete a vertex object from the polygon. This is not used by the main algorithm
** but instead is used to clean-up a polygon so that a second boolean operation can ** but instead is used to clean-up a polygon so that a second boolean operation can
** be performed. ** be performed.
*/ */
vertex * polygon::del( vertex * v ) vertex* polygon::del( vertex* v )
{ {
// p <-> v <-> n Will delete v and ns // p <-> v <-> n Will delete v and ns
// ps ns // ps ns
vertex * p = v->Prev(); // Get ref to previous vertex vertex* p = v->Prev(); // Get ref to previous vertex
vertex * n = v->Next(); // Get ref to next vertex vertex* n = v->Next(); // Get ref to next vertex
p->setNext(n); // Link previous forward to next
n->setPrev(p); // Link next back to previous p->setNext( n ); // Link previous forward to next
// Segments n->setPrev( p ); // Link next back to previous
segment * ps = p->Nseg(); // Get ref to previous segment // Segments
segment * ns = v->Nseg(); // Get ref to next segment segment* ps = p->Nseg(); // Get ref to previous segment
n->setPseg(ps); // Link next back to previous segment segment* ns = v->Nseg(); // Get ref to next segment
delete ns; //AMW n->setPseg( ps ); // Link next back to previous segment
v->m_nSeg = NULL; // AMW delete ns; //AMW
delete v; //AMW v->m_nSeg = NULL; // AMW
// ns = NULL; delete v; //AMW
// ns = NULL;
// v = NULL; // Free the memory // v = NULL; // Free the memory
m_cnt--; // One less vertex m_cnt--; // One less vertex
return n; // Return a ref to the next valid vertex return n; // Return a ref to the next valid vertex
} }
/* /*
** Reset Polygon - Deletes all intersection vertices. This is used to ** Reset Polygon - Deletes all intersection vertices. This is used to
** restore a polygon that has been processed by the boolean method ** restore a polygon that has been processed by the boolean method
...@@ -166,33 +179,36 @@ vertex * polygon::del( vertex * v ) ...@@ -166,33 +179,36 @@ vertex * polygon::del( vertex * v )
*/ */
void polygon::res() void polygon::res()
{ {
vertex * v = getFirst(); // Get the first vertex vertex* v = getFirst(); // Get the first vertex
do
{ do
v = v->Next(); // Get the next vertex in the polygon {
while (v->isIntersect()) // Delete all intersection vertices v = v->Next(); // Get the next vertex in the polygon
v = del(v); while( v->isIntersect() ) // Delete all intersection vertices
} v = del( v );
while (v->id() != m_first->id()); } while( v->id() != m_first->id() );
} }
/* /*
** Copy Polygon - Returns a reference to a new copy of the poly object ** Copy Polygon - Returns a reference to a new copy of the poly object
** including all its vertices & their segments ** including all its vertices & their segments
*/ */
polygon * polygon::copy_poly() polygon* polygon::copy_poly()
{ {
polygon * n = new polygon; // Create a new instance of this class polygon* n = new polygon; // Create a new instance of this class
vertex * v = getFirst(); vertex* v = getFirst();
do
{ do
n->addv(v->X(),v->Y(),v->Xc(),v->Yc(), (int) v->d()); {
v = v->Next(); n->addv( v->X(), v->Y(), v->Xc(), v->Yc(), (int) v->d() );
} v = v->Next();
while (v->id() != m_first->id()); } while( v->id() != m_first->id() );
return n;
return n;
} }
/* /*
** Insert and Sort a vertex between a specified pair of vertices (start and end) ** Insert and Sort a vertex between a specified pair of vertices (start and end)
** **
...@@ -202,78 +218,92 @@ polygon * polygon::copy_poly() ...@@ -202,78 +218,92 @@ polygon * polygon::copy_poly()
** points between the two vertices then the new vertex is inserted based on its ** points between the two vertices then the new vertex is inserted based on its
** alpha value. ** alpha value.
*/ */
void polygon::insertSort( vertex * nv, vertex * s, vertex * e ) void polygon::insertSort( vertex* nv, vertex* s, vertex* e )
{ {
vertex * c = s; // Set current to the starting vertex vertex* c = s; // Set current to the starting vertex
// Move current past any intersections
// whose alpha is lower but don't go past // Move current past any intersections
// the end vertex // whose alpha is lower but don't go past
while( c->id() != e->id() && c->Alpha() < nv->Alpha() ) // the end vertex
c = c->Next(); while( c->id() != e->id() && c->Alpha() < nv->Alpha() )
// p <-> nv <-> c c = c->Next();
nv->setNext(c); // Link new vertex forward to curent one
vertex * p = c->Prev(); // Get a link to the previous vertex // p <-> nv <-> c
nv->setPrev(p); // Link the new vertex back to the previous one nv->setNext( c ); // Link new vertex forward to curent one
p->setNext(nv); // Link previous vertex forward to new vertex vertex* p = c->Prev(); // Get a link to the previous vertex
c->setPrev(nv); // Link current vertex back to the new vertex nv->setPrev( p ); // Link the new vertex back to the previous one
// Segments p->setNext( nv ); // Link previous vertex forward to new vertex
segment * ps = p->Nseg(); c->setPrev( nv ); // Link current vertex back to the new vertex
nv->setPseg(ps); // Segments
segment * ns = nv->Nseg(); segment* ps = p->Nseg();
c->setPseg(ns); nv->setPseg( ps );
m_cnt++; // Just added a new vertex segment* ns = nv->Nseg();
c->setPseg( ns );
m_cnt++; // Just added a new vertex
} }
/* /*
** return the next non intersecting vertex after the one specified ** return the next non intersecting vertex after the one specified
*/ */
vertex * polygon::nxt( vertex * v ) vertex* polygon::nxt( vertex* v )
{ {
vertex * c = v; // Initialize current vertex vertex* c = v; // Initialize current vertex
while (c && c->isIntersect()) // Move until a non-intersection
c = c->Next(); // vertex if found while( c && c->isIntersect() ) // Move until a non-intersection
return c; // return that vertex c = c->Next(); // vertex if found
return c; // return that vertex
} }
/* /*
** Check if any unchecked intersections remain in the polygon. The boolean ** Check if any unchecked intersections remain in the polygon. The boolean
** method is complete when all intersections have been checked. ** method is complete when all intersections have been checked.
*/ */
BOOL polygon::unckd_remain() BOOL polygon::unckd_remain()
{ {
BOOL remain = FALSE; BOOL remain = FALSE;
vertex * v = m_first; vertex* v = m_first;
do
{ do
if (v->isIntersect() && !v->isChecked()) {
remain = TRUE; // Set if an unchecked intersection is found if( v->isIntersect() && !v->isChecked() )
v = v->Next(); remain = TRUE; // Set if an unchecked intersection is found
} v = v->Next();
while (v->id() != m_first->id()); } while( v->id() != m_first->id() );
return remain;
return remain;
} }
/* /*
** Return a ref to the first unchecked intersection point in the polygon. ** Return a ref to the first unchecked intersection point in the polygon.
** If none are found then just the first vertex is returned. ** If none are found then just the first vertex is returned.
*/ */
vertex * polygon::first_unckd_intersect() vertex* polygon::first_unckd_intersect()
{ {
vertex * v = m_first; vertex* v = m_first;
do // Do-While
{ // Not yet reached end of the polygon do // Do-While
v = v->Next(); // AND the vertex if NOT an intersection { // Not yet reached end of the polygon
} // OR it IS an intersection, but has been checked already v = v->Next(); // AND the vertex if NOT an intersection
while(v->id() != m_first->id() && ( !v->isIntersect() || ( v->isIntersect() && v->isChecked() ) ) ); } // OR it IS an intersection, but has been checked already
return v; while( v->id() != m_first->id() && ( !v->isIntersect() || ( v->isIntersect() && v->isChecked() ) ) );
return v;
} }
/* /*
** Return the distance between two points ** Return the distance between two points
*/ */
double polygon::dist( double x1, double y1, double x2, double y2 ) double polygon::dist( double x1, double y1, double x2, double y2 )
{ {
return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2)); return sqrt( (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2) );
} }
/* /*
** Calculate the angle between 2 points, where Xc,Yc is the center of a circle ** Calculate the angle between 2 points, where Xc,Yc is the center of a circle
** and x,y is a point on its circumference. All angles are relative to ** and x,y is a point on its circumference. All angles are relative to
...@@ -281,46 +311,50 @@ double polygon::dist( double x1, double y1, double x2, double y2 ) ...@@ -281,46 +311,50 @@ double polygon::dist( double x1, double y1, double x2, double y2 )
*/ */
double polygon::angle( double xc, double yc, double x1, double y1 ) double polygon::angle( double xc, double yc, double x1, double y1 )
{ {
double d = dist(xc, yc, x1, y1); // calc distance between two points double d = dist( xc, yc, x1, y1 ); // calc distance between two points
double a1; double a1;
if ( asin( (y1-yc)/d ) >= 0 )
a1 = acos( (x1-xc)/d ); if( asin( (y1 - yc) / d ) >= 0 )
else a1 = acos( (x1 - xc) / d );
a1 = 2*PI - acos( (x1-xc)/d ); else
return a1; a1 = 2 * PI - acos( (x1 - xc) / d );
return a1;
} }
/* /*
** Return Alpha value for an Arc ** Return Alpha value for an Arc
** **
** X1/Y1 & X2/Y2 are the end points of the arc, Xc/Yc is the center & Xi/Yi ** X1/Y1 & X2/Y2 are the end points of the arc, Xc/Yc is the center & Xi/Yi
** the intersection point on the arc. d is the direction of the arc ** the intersection point on the arc. d is the direction of the arc
*/ */
double polygon::aAlpha( double x1, double y1, double x2, double y2, double polygon::aAlpha( double x1, double y1, double x2, double y2,
double xc, double yc, double xi, double yi, double d ) double xc, double yc, double xi, double yi, double d )
{ {
double sa = angle(xc, yc, x1, y1); // Start Angle double sa = angle( xc, yc, x1, y1 ); // Start Angle
double ea = angle(xc, yc, x2, y2); // End Angle double ea = angle( xc, yc, x2, y2 ); // End Angle
double ia = angle(xc, yc, xi, yi); // Intersection Angle double ia = angle( xc, yc, xi, yi ); // Intersection Angle
double arc, aint; double arc, aint;
if (d == 1) // Anti-Clockwise
{ if( d == 1 ) // Anti-Clockwise
arc = ea - sa; {
aint = ia - sa; arc = ea - sa;
} aint = ia - sa;
else // Clockwise }
{ else // Clockwise
arc = sa - ea; {
aint = sa - ia; arc = sa - ea;
} aint = sa - ia;
if (arc < 0) }
arc += 2*PI; if( arc < 0 )
if (aint < 0) arc += 2 * PI;
aint += 2*PI; if( aint < 0 )
double a = aint/arc; aint += 2 * PI;
return a; double a = aint / arc;
return a;
} }
/* /*
** This function handles the degenerate case where a vertex of one ** This function handles the degenerate case where a vertex of one
** polygon lies directly on an edge of the other. This case can ** polygon lies directly on an edge of the other. This case can
...@@ -328,35 +362,37 @@ double polygon::aAlpha( double x1, double y1, double x2, double y2, ...@@ -328,35 +362,37 @@ double polygon::aAlpha( double x1, double y1, double x2, double y2,
** line exactly intersects with a vertex. The function works ** line exactly intersects with a vertex. The function works
** by shortening the line by a tiny amount. ** by shortening the line by a tiny amount.
*/ */
void polygon::perturb( vertex * p1, vertex * p2, vertex * q1, vertex * q2, void polygon::perturb( vertex* p1, vertex* p2, vertex* q1, vertex* q2,
double aP, double aQ ) double aP, double aQ )
{ {
// if (aP == 0) // Move vertex p1 closer to p2 // if (aP == 0) // Move vertex p1 closer to p2
if( abs(aP) <= eps ) // Move vertex p1 closer to p2 if( abs( aP ) <= eps ) // Move vertex p1 closer to p2
{ {
p1->setX(p1->X() + (1-PT) * (p2->X() - p1->X())); p1->setX( p1->X() + (1 - PT) * ( p2->X() - p1->X() ) );
p1->setY(p1->Y() + (1-PT) * (p2->Y() - p1->Y())); p1->setY( p1->Y() + (1 - PT) * ( p2->Y() - p1->Y() ) );
} }
// else if (aP == 1) // Move vertex p2 closer to p1 // else if (aP == 1) // Move vertex p2 closer to p1
else if( abs(1-aP) <= eps ) // Move vertex p2 closer to p1 else if( abs( 1 - aP ) <= eps ) // Move vertex p2 closer to p1
{ {
p2->setX(p1->X() + PT * (p2->X() - p1->X())); p2->setX( p1->X() + PT * ( p2->X() - p1->X() ) );
p2->setY(p1->Y() + PT * (p2->Y() - p1->Y())); p2->setY( p1->Y() + PT * ( p2->Y() - p1->Y() ) );
} }
//** else if (aQ == 0) // Move vertex q1 closer to q2 //** else if (aQ == 0) // Move vertex q1 closer to q2
if( abs(aQ) <= eps ) // Move vertex q1 closer to q2 if( abs( aQ ) <= eps ) // Move vertex q1 closer to q2
{ {
q1->setX(q1->X() + (1-PT) * (q2->X() - q1->X())); q1->setX( q1->X() + (1 - PT) * ( q2->X() - q1->X() ) );
q1->setY(q1->Y() + (1-PT) * (q2->Y() - q1->Y())); q1->setY( q1->Y() + (1 - PT) * ( q2->Y() - q1->Y() ) );
} }
//** else if (aQ == 1) // Move vertex q2 closer to q1 //** else if (aQ == 1) // Move vertex q2 closer to q1
else if( abs(1-aQ) <= eps ) // Move vertex q2 closer to q1 else if( abs( 1 - aQ ) <= eps ) // Move vertex q2 closer to q1
{ {
q2->setX(q1->X() + PT * (q2->X() - q1->X())); q2->setX( q1->X() + PT * ( q2->X() - q1->X() ) );
q2->setY(q1->Y() + PT * (q2->Y() - q1->Y())); q2->setY( q1->Y() + PT * ( q2->Y() - q1->Y() ) );
} }
} }
/* /*
** Determine the intersection between two pairs of vertices p1/p2, q1/q2 ** Determine the intersection between two pairs of vertices p1/p2, q1/q2
** **
...@@ -372,270 +408,290 @@ void polygon::perturb( vertex * p1, vertex * p2, vertex * q1, vertex * q2, ...@@ -372,270 +408,290 @@ void polygon::perturb( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
** The arrays ix[], iy[], alphaP[] & alphaQ[] return the intersection points ** The arrays ix[], iy[], alphaP[] & alphaQ[] return the intersection points
** and their associated alpha values. ** and their associated alpha values.
*/ */
BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2, BOOL polygon::ints( vertex* p1, vertex* p2, vertex* q1, vertex* q2,
int * n, double ix[], double iy[], double alphaP[], double alphaQ[] ) int* n, double ix[], double iy[], double alphaP[], double alphaQ[] )
{ {
BOOL found = FALSE; BOOL found = FALSE;
*n = 0; // No intersections found yet
int pt = (int) p1->d(); *n = 0; // No intersections found yet
int qt = (int) q1->d(); // Do we have Arcs or Lines? int pt = (int) p1->d();
int qt = (int) q1->d(); // Do we have Arcs or Lines?
if (pt == 0 && qt == 0) // Is it line/Line ?
{ if( pt == 0 && qt == 0 ) // Is it line/Line ?
/* LINE/LINE {
** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/ /* LINE/LINE
*/ ** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/lineline2d/
double x1 = p1->X(); */
double y1 = p1->Y(); double x1 = p1->X();
double x2 = p2->X(); double y1 = p1->Y();
double y2 = p2->Y(); double x2 = p2->X();
double x3 = q1->X(); double y2 = p2->Y();
double y3 = q1->Y(); double x3 = q1->X();
double x4 = q2->X(); double y3 = q1->Y();
double y4 = q2->Y(); double x4 = q2->X();
double d = ((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)); double y4 = q2->Y();
if (d != 0) double d = ( (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1) );
{ // The lines intersect at a point somewhere if( d != 0 )
double ua = ((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/d; { // The lines intersect at a point somewhere
double ub = ((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/d; double ua = ( (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3) ) / d;
TRACE( " ints: ua = %.17f, ub = %.17f\n", ua, ub ); double ub = ( (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3) ) / d;
// The values of $ua and $ub tell us where the intersection occurred. // TRACE( " ints: ua = %.17f, ub = %.17f\n", ua, ub );
// A value between 0 and 1 means the intersection occurred within the
// line segment. // The values of $ua and $ub tell us where the intersection occurred.
// A value less than 0 or greater than 1 means the intersection occurred // A value between 0 and 1 means the intersection occurred within the
// outside the line segment // line segment.
// A value of exactly 0 or 1 means the intersection occurred right at the // A value less than 0 or greater than 1 means the intersection occurred
// start or end of the line segment. For our purposes we will consider this // outside the line segment
// NOT to be an intersection and we will move the vertex a tiny distance // A value of exactly 0 or 1 means the intersection occurred right at the
// away from the intersecting line. // start or end of the line segment. For our purposes we will consider this
// NOT to be an intersection and we will move the vertex a tiny distance
// away from the intersecting line.
// if( ua == 0 || ua == 1 || ub == 0 || ub == 1 ) // if( ua == 0 || ua == 1 || ub == 0 || ub == 1 )
if( abs(ua)<=eps || abs(1.0-ua)<=eps || abs(ub)<=eps || abs(1.0-ub)<=eps ) if( abs( ua )<=eps || abs( 1.0 - ua )<=eps || abs( ub )<=eps || abs( 1.0 - ub )<=eps )
{ {
// Degenerate case - vertex touches a line // Degenerate case - vertex touches a line
perturb(p1, p2, q1, q2, ua, ub); perturb( p1, p2, q1, q2, ua, ub );
//** for testing, see if we have successfully resolved the degeneracy
{ //** for testing, see if we have successfully resolved the degeneracy
double tx1 = p1->X(); {
double ty1 = p1->Y(); double tx1 = p1->X();
double tx2 = p2->X(); double ty1 = p1->Y();
double ty2 = p2->Y(); double tx2 = p2->X();
double tx3 = q1->X(); double ty2 = p2->Y();
double ty3 = q1->Y(); double tx3 = q1->X();
double tx4 = q2->X(); double ty3 = q1->Y();
double ty4 = q2->Y(); double tx4 = q2->X();
double td = ((ty4-ty3)*(tx2-tx1)-(tx4-tx3)*(ty2-ty1)); double ty4 = q2->Y();
if (td != 0) double td = ( (ty4 - ty3) * (tx2 - tx1) - (tx4 - tx3) * (ty2 - ty1) );
{ if( td != 0 )
// The lines intersect at a point somewhere {
double tua = ((tx4-tx3)*(ty1-ty3)-(ty4-ty3)*(tx1-tx3))/td; // The lines intersect at a point somewhere
double tub = ((tx2-tx1)*(ty1-ty3)-(ty2-ty1)*(tx1-tx3))/td; double tua =
if( abs(tua)<=eps || abs(1.0-tua)<=eps || abs(tub)<=eps || abs(1.0-tub)<=eps ) ( (tx4 - tx3) * (ty1 - ty3) - (ty4 - ty3) * (tx1 - tx3) ) / td;
wxASSERT(0); double tub =
else if( (tua > 0 && tua < 1) && (tub > 0 && tub < 1) ) ( (tx2 - tx1) * (ty1 - ty3) - (ty2 - ty1) * (tx1 - tx3) ) / td;
wxASSERT(0); if( abs( tua )<=eps || abs( 1.0 - tua )<=eps || abs( tub )<=eps ||
TRACE( " perturb:\n new s = (%f,%f) to (%f,%f)\n new c = (%f,%f) to (%f,%f)\n new ua = %.17f, ub = %.17f\n", abs( 1.0 - tub )<=eps )
tx1, ty1, tx2, ty2, tx3, ty3, tx4, ty4, tua, tub ); wxASSERT( 0 );
} else if( (tua > 0 && tua < 1) && (tub > 0 && tub < 1) )
} wxASSERT( 0 );
//** end test TRACE(
found = FALSE; " perturb:\n new s = (%f,%f) to (%f,%f)\n new c = (%f,%f) to (%f,%f)\n new ua = %.17f, ub = %.17f\n",
} tx1,
else if ((ua > 0 && ua < 1) && (ub > 0 && ub < 1)) ty1,
{ tx2,
// Intersection occurs on both line segments ty2,
double x = x1 + ua*(x2-x1); tx3,
double y = y1 + ua*(y2-y1); ty3,
iy[0] = y; tx4,
ix[0] = x; ty4,
alphaP[0] = ua; tua,
alphaQ[0] = ub; tub );
*n = 1; }
found = TRUE; }
}
else //** end test
{ found = FALSE;
// The lines do not intersect }
found = FALSE; else if( (ua > 0 && ua < 1) && (ub > 0 && ub < 1) )
} {
} // Intersection occurs on both line segments
else double x = x1 + ua * (x2 - x1);
{ double y = y1 + ua * (y2 - y1);
// The lines do not intersect (they are parallel) iy[0] = y;
found = FALSE; ix[0] = x;
} alphaP[0] = ua;
} // End of find Line/Line intersection alphaQ[0] = ub;
else if (pt != 0 && qt != 0) // Is it Arc/Arc? *n = 1;
{ found = TRUE;
/* ARC/ARC }
** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/2circle/ else
*/ {
double x0 = p1->Xc(); // The lines do not intersect
double y0 = p1->Yc(); // Center of first Arc found = FALSE;
double r0 = dist(x0,y0,p1->X(),p1->Y()); // Calc the radius }
double x1 = q1->Xc(); }
double y1 = q1->Yc(); // Center of second Arc else
double r1 = dist(x1,y1,q1->X(),q1->Y()); // Calc the radius {
// The lines do not intersect (they are parallel)
double dx = x1 - x0; // dx and dy are the vertical and horizontal found = FALSE;
double dy = y1 - y0; // distances between the circle centers. }
double d = sqrt((dy*dy) + (dx*dx)); // Distance between the centers. } // End of find Line/Line intersection
else if( pt != 0 && qt != 0 ) // Is it Arc/Arc?
if(d > (r0 + r1)) // Check for solvability. {
{ // no solution. circles do not intersect. /* ARC/ARC
found = FALSE; ** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/2circle/
} */
else if(d < abs(r0 - r1) ) double x0 = p1->Xc();
{ // no solution. one circle inside the other double y0 = p1->Yc(); // Center of first Arc
found = FALSE; double r0 = dist( x0, y0, p1->X(), p1->Y() ); // Calc the radius
} double x1 = q1->Xc();
else double y1 = q1->Yc(); // Center of second Arc
{ double r1 = dist( x1, y1, q1->X(), q1->Y() ); // Calc the radius
/*
** 'xy2' is the point where the line through the circle intersection double dx = x1 - x0; // dx and dy are the vertical and horizontal
** points crosses the line between the circle centers. double dy = y1 - y0; // distances between the circle centers.
*/ double d = sqrt( (dy * dy) + (dx * dx) ); // Distance between the centers.
double a = ((r0*r0)-(r1*r1)+(d*d))/(2.0*d); // Calc the distance from xy0 to xy2.
double x2 = x0 + (dx * a/d); // Determine the coordinates of xy2. if( d > (r0 + r1) ) // Check for solvability.
double y2 = y0 + (dy * a/d); { // no solution. circles do not intersect.
if (d == (r0 + r1)) // Arcs touch at xy2 exactly (unlikely) found = FALSE;
{ }
alphaP[0] = aAlpha(p1->X(), p1->Y(), p2->X(), p2->Y(), x0, y0, x2, y2, pt); else if( d < abs( r0 - r1 ) )
alphaQ[0] = aAlpha(q1->X(), q1->Y(), q2->X(), q2->Y(), x1, y1, x2, y2, qt); { // no solution. one circle inside the other
if ((alphaP[0] >0 && alphaP[0] < 1) && (alphaQ[0] >0 && alphaQ[0] < 1)) found = FALSE;
{ }
ix[0] = x2; else
iy[0] = y2; {
*n = 1; found = TRUE; /*
} ** 'xy2' is the point where the line through the circle intersection
} ** points crosses the line between the circle centers.
else // Arcs intersect at two points */
{ double a = ( (r0 * r0) - (r1 * r1) + (d * d) ) / (2.0 * d); // Calc the distance from xy0 to xy2.
double alP[2], alQ[2]; double x2 = x0 + (dx * a / d); // Determine the coordinates of xy2.
double h = sqrt((r0*r0) - (a*a)); // Calc the distance from xy2 to either double y2 = y0 + (dy * a / d);
// of the intersection points. if( d == (r0 + r1) ) // Arcs touch at xy2 exactly (unlikely)
double rx = -dy * (h/d); // Now determine the offsets of the {
double ry = dx * (h/d); alphaP[0] = aAlpha( p1->X(), p1->Y(), p2->X(), p2->Y(), x0, y0, x2, y2, pt );
// intersection points from xy2 alphaQ[0] = aAlpha( q1->X(), q1->Y(), q2->X(), q2->Y(), x1, y1, x2, y2, qt );
double x[2], y[2]; if( (alphaP[0] >0 && alphaP[0] < 1) && (alphaQ[0] >0 && alphaQ[0] < 1) )
x[0] = x2 + rx; x[1] = x2 - rx; // Calc the absolute intersection points. {
y[0] = y2 + ry; y[1] = y2 - ry; ix[0] = x2;
alP[0] = aAlpha(p1->X(), p1->Y(), p2->X(), p2->Y(), x0, y0, x[0], y[0], pt); iy[0] = y2;
alQ[0] = aAlpha(q1->X(), q1->Y(), q2->X(), q2->Y(), x1, y1, x[0], y[0], qt); *n = 1; found = TRUE;
alP[1] = aAlpha(p1->X(), p1->Y(), p2->X(), p2->Y(), x0, y0, x[1], y[1], pt); }
alQ[1] = aAlpha(q1->X(), q1->Y(), q2->X(), q2->Y(), x1, y1, x[1], y[1], qt); }
for (int i=0; i<=1; i++) else // Arcs intersect at two points
if ((alP[i] >0 && alP[i] < 1) && (alQ[i] >0 && alQ[i] < 1)) {
{ double alP[2], alQ[2];
ix[*n] = x[i]; double h = sqrt( (r0 * r0) - (a * a) ); // Calc the distance from xy2 to either
iy[*n] = y[i]; // of the intersection points.
alphaP[*n] = alP[i]; double rx = -dy * (h / d); // Now determine the offsets of the
alphaQ[*n] = alQ[i]; double ry = dx * (h / d);
*n++;
found = TRUE; // intersection points from xy2
} double x[2], y[2];
} x[0] = x2 + rx; x[1] = x2 - rx; // Calc the absolute intersection points.
} y[0] = y2 + ry; y[1] = y2 - ry;
} // End of find Arc/Arc intersection alP[0] = aAlpha( p1->X(), p1->Y(), p2->X(), p2->Y(), x0, y0, x[0], y[0], pt );
else // It must be Arc/Line alQ[0] = aAlpha( q1->X(), q1->Y(), q2->X(), q2->Y(), x1, y1, x[0], y[0], qt );
{ alP[1] = aAlpha( p1->X(), p1->Y(), p2->X(), p2->Y(), x0, y0, x[1], y[1], pt );
/* ARC/LINE alQ[1] = aAlpha( q1->X(), q1->Y(), q2->X(), q2->Y(), x1, y1, x[1], y[1], qt );
** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/sphereline/ for( int i = 0; i<=1; i++ )
*/ if( (alP[i] >0 && alP[i] < 1) && (alQ[i] >0 && alQ[i] < 1) )
double d, x1, x2, xc, xs, xe; {
double y1, y2, yc, ys, ye; ix[*n] = x[i];
if (pt == 0) // Segment p1,p2 is the line iy[*n] = y[i];
{ // Segment q1,q2 is the arc alphaP[*n] = alP[i];
x1 = p1->X(); alphaQ[*n] = alQ[i];
y1 = p1->Y(); *n++;
x2 = p2->X(); found = TRUE;
y2 = p2->Y(); }
xc = q1->Xc(); }
yc = q1->Yc(); }
xs = q1->X(); } // End of find Arc/Arc intersection
ys = q1->Y(); else // It must be Arc/Line
xe = q2->X(); {
ye = q2->Y(); /* ARC/LINE
d = qt; ** Algorithm from: http://astronomy.swin.edu.au/~pbourke/geometry/sphereline/
} */
else // Segment q1,q2 is the line double d, x1, x2, xc, xs, xe;
{ // Segment p1,p2 is the arc double y1, y2, yc, ys, ye;
x1 = q1->X(); y1 = q1->Y(); if( pt == 0 ) // Segment p1,p2 is the line
x2 = q2->X(); y2 = q2->Y(); { // Segment q1,q2 is the arc
xc = p1->Xc(); yc = p1->Yc(); x1 = p1->X();
xs = p1->X(); ys = p1->Y(); y1 = p1->Y();
xe = p2->X(); ye = p2->Y(); x2 = p2->X();
d = pt; y2 = p2->Y();
} xc = q1->Xc();
double r = dist(xc,yc,xs,ys); yc = q1->Yc();
double a = pow((x2 - x1),2)+pow((y2 - y1),2); xs = q1->X();
double b = 2* ( (x2 - x1)*(x1 - xc) ys = q1->Y();
+ (y2 - y1)*(y1 - yc) ); xe = q2->X();
double c = pow(xc,2) + pow(yc,2) + ye = q2->Y();
pow(x1,2) + pow(y1,2) - d = qt;
2* ( xc*x1 + yc*y1) - pow(r,2); }
double i = b * b - 4 * a * c; else // Segment q1,q2 is the line
if ( i < 0.0 ) // no intersection {
{ // Segment p1,p2 is the arc
found = FALSE; x1 = q1->X(); y1 = q1->Y();
} x2 = q2->X(); y2 = q2->Y();
else if ( i == 0.0 ) // one intersection xc = p1->Xc(); yc = p1->Yc();
{ xs = p1->X(); ys = p1->Y();
double mu = -b/(2*a); xe = p2->X(); ye = p2->Y();
double x = x1 + mu*(x2-x1); d = pt;
double y = y1 + mu*(y2-y1); }
double al = mu; // Line Alpha double r = dist( xc, yc, xs, ys );
double aa = this->aAlpha(xs, ys, xe, ye, xc, yc, x, y, d); // Arc Alpha double a = pow( (x2 - x1), 2 ) + pow( (y2 - y1), 2 );
if ((al >0 && al <1)&&(aa >0 && aa <1)) double b = 2 * ( (x2 - x1) * (x1 - xc)
{ + (y2 - y1) * (y1 - yc) );
ix[0] = x; iy[0] = y; double c = pow( xc, 2 ) + pow( yc, 2 ) +
*n = 1; pow( x1, 2 ) + pow( y1, 2 ) -
found = TRUE; 2 * ( xc * x1 + yc * y1) - pow( r, 2 );
if (pt == 0) double i = b * b - 4 * a * c;
{ if( i < 0.0 ) // no intersection
alphaP[0] = al; alphaQ[0] = aa; {
} found = FALSE;
else }
{ else if( i == 0.0 ) // one intersection
alphaP[0] = aa; alphaQ[0] = al; {
} double mu = -b / (2 * a);
} double x = x1 + mu * (x2 - x1);
} double y = y1 + mu * (y2 - y1);
else if ( i > 0.0 ) // two intersections double al = mu; // Line Alpha
{ double aa = this->aAlpha( xs, ys, xe, ye, xc, yc, x, y, d ); // Arc Alpha
double mu[2], x[2], y[2], al[2], aa[2]; if( (al >0 && al <1)&&(aa >0 && aa <1) )
mu[0] = (-b + sqrt( pow(b,2) - 4*a*c )) / (2*a); // first intersection {
x[0] = x1 + mu[0]*(x2-x1); ix[0] = x; iy[0] = y;
y[0] = y1 + mu[0]*(y2-y1); *n = 1;
mu[1] = (-b - sqrt(pow(b,2) - 4*a*c )) / (2*a); // second intersection found = TRUE;
x[1] = x1 + mu[1]*(x2-x1); if( pt == 0 )
y[1] = y1 + mu[1]*(y2-y1); {
al[0] = mu[0]; alphaP[0] = al; alphaQ[0] = aa;
aa[0] = aAlpha(xs, ys, xe, ye, xc, yc, x[0], y[0], d); }
al[1] = mu[1]; else
aa[1] = aAlpha(xs, ys, xe, ye, xc, yc, x[1], y[1], d); {
for (int i=0; i<=1; i++) alphaP[0] = aa; alphaQ[0] = al;
if ((al[i] >0 && al[i] < 1) && (aa[i] >0 && aa[i] < 1)) }
{ }
ix[*n] = x[i]; }
iy[*n] = y[i]; else if( i > 0.0 ) // two intersections
if (pt == 0) {
{ double mu[2], x[2], y[2], al[2], aa[2];
alphaP[*n] = al[i]; mu[0] = ( -b + sqrt( pow( b, 2 ) - 4 * a * c ) ) / (2 * a); // first intersection
alphaQ[*n] = aa[i]; x[0] = x1 + mu[0] * (x2 - x1);
} y[0] = y1 + mu[0] * (y2 - y1);
else mu[1] = ( -b - sqrt( pow( b, 2 ) - 4 * a * c ) ) / (2 * a); // second intersection
{ x[1] = x1 + mu[1] * (x2 - x1);
alphaP[*n] = aa[i]; y[1] = y1 + mu[1] * (y2 - y1);
alphaQ[*n] = al[i]; al[0] = mu[0];
} aa[0] = aAlpha( xs, ys, xe, ye, xc, yc, x[0], y[0], d );
*n++; al[1] = mu[1];
found = TRUE; aa[1] = aAlpha( xs, ys, xe, ye, xc, yc, x[1], y[1], d );
} for( int i = 0; i<=1; i++ )
} if( (al[i] >0 && al[i] < 1) && (aa[i] >0 && aa[i] < 1) )
} // End of find Arc/Line intersection {
return found; ix[*n] = x[i];
iy[*n] = y[i];
if( pt == 0 )
{
alphaP[*n] = al[i];
alphaQ[*n] = aa[i];
}
else
{
alphaP[*n] = aa[i];
alphaQ[*n] = al[i];
}
*n++;
found = TRUE;
}
}
} // End of find Arc/Line intersection
return found;
} // end of intersect function } // end of intersect function
/* /*
** Test if a vertex lies inside the polygon ** Test if a vertex lies inside the polygon
** **
...@@ -649,56 +705,60 @@ BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2, ...@@ -649,56 +705,60 @@ BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
** **
** Allan Wright 4/16/2006: I guess I have no life: I had to increase it to -1000000000 ** Allan Wright 4/16/2006: I guess I have no life: I had to increase it to -1000000000
*/ */
BOOL polygon::isInside( vertex * v ) BOOL polygon::isInside( vertex* v )
{ {
//** modified for testing //** modified for testing
if( v->isIntersect() ) if( v->isIntersect() )
wxASSERT(0); wxASSERT( 0 );
int winding_number = 0; int winding_number = 0;
int winding_number2 = 0; int winding_number2 = 0;
int winding_number3 = 0; int winding_number3 = 0;
int winding_number4 = 0; int winding_number4 = 0;
//** vertex * point_at_infinity = new vertex(-10000000,v->Y()); // Create point at infinity //** vertex * point_at_infinity = new vertex(-10000000,v->Y()); // Create point at infinity
/* vertex * point_at_infinity = new vertex(-1000000000,-50000000); // Create point at infinity /* vertex * point_at_infinity = new vertex(-1000000000,-50000000); // Create point at infinity
vertex * point_at_infinity2 = new vertex(1000000000,+50000000); // Create point at infinity * vertex * point_at_infinity2 = new vertex(1000000000,+50000000); // Create point at infinity
vertex * point_at_infinity3 = new vertex(500000000,1000000000); // Create point at infinity * vertex * point_at_infinity3 = new vertex(500000000,1000000000); // Create point at infinity
vertex * point_at_infinity4 = new vertex(-500000000,1000000000); // Create point at infinity * vertex * point_at_infinity4 = new vertex(-500000000,1000000000); // Create point at infinity
*/ */
vertex point_at_infinity(-1000000000,-50000000); // Create point at infinity vertex point_at_infinity( -1000000000, -50000000 ); // Create point at infinity
vertex point_at_infinity2(1000000000,+50000000); // Create point at infinity vertex point_at_infinity2( 1000000000, +50000000 ); // Create point at infinity
vertex point_at_infinity3(500000000,1000000000); // Create point at infinity vertex point_at_infinity3( 500000000, 1000000000 ); // Create point at infinity
vertex point_at_infinity4(-500000000,1000000000); // Create point at infinity vertex point_at_infinity4( -500000000, 1000000000 ); // Create point at infinity
vertex * q = m_first; // End vertex of a line segment in polygon vertex* q = m_first; // End vertex of a line segment in polygon
do
{ do
if (!q->isIntersect()) {
{ if( !q->isIntersect() )
int n; {
double x[2], y[2], aP[2], aQ[2]; int n;
if( ints( &point_at_infinity, v, q, nxt(q->Next()), &n, x, y, aP, aQ ) ) double x[2], y[2], aP[2], aQ[2];
winding_number += n; // Add number of intersections found if( ints( &point_at_infinity, v, q, nxt( q->Next() ), &n, x, y, aP, aQ ) )
if( ints( &point_at_infinity2, v, q, nxt(q->Next()), &n, x, y, aP, aQ ) ) winding_number += n; // Add number of intersections found
winding_number2 += n; // Add number of intersections found if( ints( &point_at_infinity2, v, q, nxt( q->Next() ), &n, x, y, aP, aQ ) )
if( ints( &point_at_infinity3, v, q, nxt(q->Next()), &n, x, y, aP, aQ ) ) winding_number2 += n; // Add number of intersections found
winding_number3 += n; // Add number of intersections found if( ints( &point_at_infinity3, v, q, nxt( q->Next() ), &n, x, y, aP, aQ ) )
if( ints( &point_at_infinity4, v, q, nxt(q->Next()), &n, x, y, aP, aQ ) ) winding_number3 += n; // Add number of intersections found
winding_number4 += n; // Add number of intersections found if( ints( &point_at_infinity4, v, q, nxt( q->Next() ), &n, x, y, aP, aQ ) )
} winding_number4 += n; // Add number of intersections found
q = q->Next(); }
} q = q->Next();
while( q->id() != m_first->id() ); } while( q->id() != m_first->id() );
// delete point_at_infinity;
// delete point_at_infinity;
// delete point_at_infinity2; // delete point_at_infinity2;
if( winding_number%2 != winding_number2%2 if( winding_number % 2 != winding_number2 % 2
|| winding_number3%2 != winding_number4%2 || winding_number3 % 2 != winding_number4 % 2
|| winding_number%2 != winding_number3%2 ) || winding_number % 2 != winding_number3 % 2 )
wxASSERT(0); wxASSERT( 0 );
if( winding_number%2 == 0 ) // Check even or odd if( winding_number % 2 == 0 ) // Check even or odd
return FALSE; // even == outside return FALSE; // even == outside
else else
return TRUE; // odd == inside return TRUE; // odd == inside
} }
/* /*
** Execute a Boolean operation on a polygon ** Execute a Boolean operation on a polygon
** **
...@@ -714,236 +774,284 @@ BOOL polygon::isInside( vertex * v ) ...@@ -714,236 +774,284 @@ BOOL polygon::isInside( vertex * v )
** **
** A is the object and B is the polygon passed to the method. ** A is the object and B is the polygon passed to the method.
*/ */
polygon * polygon::boolean( polygon * polyB, int oper ) polygon* polygon::boolean( polygon* polyB, int oper )
{ {
polygon * last = NULL; polygon* last = NULL;
vertex * s = m_first; // First vertex of the subject polygon vertex* s = m_first; // First vertex of the subject polygon
vertex * c = polyB->getFirst(); // First vertex of the "clip" polygon vertex* c = polyB->getFirst(); // First vertex of the "clip" polygon
/*
** Phase 1 of the algoritm is to find all intersection points between the two /*
** polygons. A new vertex is created for each intersection and it is added to ** Phase 1 of the algoritm is to find all intersection points between the two
** the linked lists for both polygons. The "neighbor" reference in each vertex ** polygons. A new vertex is created for each intersection and it is added to
** stores the link between the same intersection point in each polygon. ** the linked lists for both polygons. The "neighbor" reference in each vertex
*/ ** stores the link between the same intersection point in each polygon.
TRACE( "boolean...phase 1\n" ); */
do TRACE( "boolean...phase 1\n" );
{
TRACE( "s=(%f,%f) to (%f,%f) I=%d\n", do
s->m_x, s->m_y, s->m_nextV->m_x, s->m_nextV->m_y, s->m_intersect ); {
if (!s->isIntersect()) TRACE( "s=(%f,%f) to (%f,%f) I=%d\n",
{ s->m_x, s->m_y, s->m_nextV->m_x, s->m_nextV->m_y, s->m_intersect );
do if( !s->isIntersect() )
{ {
TRACE( " c=(%f,%f) to (%f,%f) I=%d\n", do
c->m_x, c->m_y, c->m_nextV->m_x, c->m_nextV->m_y, c->m_intersect ); {
if (!c->isIntersect()) TRACE( " c=(%f,%f) to (%f,%f) I=%d\n",
{ c->m_x, c->m_y, c->m_nextV->m_x, c->m_nextV->m_y, c->m_intersect );
int n; if( !c->isIntersect() )
double ix[2], iy[2], alphaS[2], alphaC[2]; {
BOOL bInt = ints(s, nxt(s->Next()),c, polyB->nxt(c->Next()), &n, ix, iy, alphaS, alphaC); int n;
if( bInt ) double ix[2], iy[2], alphaS[2], alphaC[2];
{ BOOL bInt = ints( s, nxt( s->Next() ), c, polyB->nxt(
TRACE( " int at (%f,%f) aS = %.17f, aC = %.17f\n", ix[0], iy[0], alphaS[0], alphaC[0] ); c->Next() ), &n, ix, iy, alphaS, alphaC );
for (int i=0; i<n; i++) if( bInt )
{ {
vertex * is = new vertex(ix[i], iy[i], s->Xc(), s->Yc(), s->d(), NULL, NULL, NULL, TRUE, NULL, alphaS[i], FALSE, FALSE); TRACE( " int at (%f,%f) aS = %.17f, aC = %.17f\n",
vertex * ic = new vertex(ix[i], iy[i], c->Xc(), c->Yc(), c->d(), NULL, NULL, NULL, TRUE, NULL, alphaC[i], FALSE, FALSE); ix[0],
is->setNeighbor(ic); iy[0],
ic->setNeighbor(is); alphaS[0],
insertSort(is, s, this->nxt(s->Next())); alphaC[0] );
polyB->insertSort(ic, c, polyB->nxt(c->Next())); for( int i = 0; i<n; i++ )
} {
} vertex* is = new vertex( ix[i], iy[i], s->Xc(), s->Yc(),
} // end if c is not an intersect point s->d(), NULL, NULL, NULL, TRUE, NULL, alphaS[i], FALSE, FALSE );
c = c->Next(); vertex* ic = new vertex( ix[i], iy[i], c->Xc(), c->Yc(),
} c->d(), NULL, NULL, NULL, TRUE, NULL, alphaC[i], FALSE, FALSE );
while (c->id() != polyB->m_first->id()); is->setNeighbor( ic );
} // end if s not an intersect point ic->setNeighbor( is );
s = s->Next(); insertSort( is, s, this->nxt( s->Next() ) );
} polyB->insertSort( ic, c, polyB->nxt( c->Next() ) );
while(s->id() != m_first->id()); }
}
//** for testing...check number of intersections in each poly } // end if c is not an intersect point
TRACE( "boolean...phase 1 testing\n" ); c = c->Next();
int n_ints = 0; } while( c->id() != polyB->m_first->id() );
s = m_first; } // end if s not an intersect point
do s = s->Next();
{ } while( s->id() != m_first->id() );
if( s->isIntersect() )
n_ints++; //** for testing...check number of intersections in each poly
s = s->Next(); TRACE( "boolean...phase 1 testing\n" );
} while( s->id() != m_first->id() ); int n_ints = 0;
int n_polyB_ints = 0; s = m_first;
s = polyB->m_first;
do do
{ {
if( s->isIntersect() ) if( s->isIntersect() )
n_polyB_ints++; n_ints++;
s = s->Next(); s = s->Next();
} while( s->id() != polyB->m_first->id() ); } while( s->id() != m_first->id() );
if( n_ints != n_polyB_ints )
wxASSERT(0); int n_polyB_ints = 0;
if( n_ints%2 != 0 ) s = polyB->m_first;
wxASSERT(0);
//** end test do
{
/* if( s->isIntersect() )
** Phase 2 of the algorithm is to identify every intersection point as an n_polyB_ints++;
** entry or exit point to the other polygon. This will set the entry bits s = s->Next();
** in each vertex object. } while( s->id() != polyB->m_first->id() );
**
** What is really stored in the entry record for each intersection is the if( n_ints != n_polyB_ints )
** direction the algorithm should take when it arrives at that entry point. wxASSERT( 0 );
** Depending in the operation requested (A&B, A|B, A/B, B/A) the direction is if( n_ints % 2 != 0 )
** set as follows for entry points (f=foreward, b=Back), exit points are always set wxASSERT( 0 );
** to the opposite:
** Enter Exit //** end test
** A B A B
** A|B b b f f /*
** A&B f f b b ** Phase 2 of the algorithm is to identify every intersection point as an
** A\B b f f b ** entry or exit point to the other polygon. This will set the entry bits
** B\A f b b f ** in each vertex object.
** **
** f = TRUE, b = FALSE when stored in the entry record ** What is really stored in the entry record for each intersection is the
*/ ** direction the algorithm should take when it arrives at that entry point.
BOOL A, B; ** Depending in the operation requested (A&B, A|B, A/B, B/A) the direction is
** set as follows for entry points (f=foreward, b=Back), exit points are always set
switch (oper) ** to the opposite:
{ ** Enter Exit
case A_OR_B: A = FALSE; B = FALSE; break; ** A B A B
case A_AND_B: A = TRUE; B = TRUE; break; ** A|B b b f f
case A_MINUS_B: A = FALSE; B = TRUE; break; ** A&B f f b b
case B_MINUS_A: A = TRUE; B = FALSE; break; ** A\B b f f b
default: A = TRUE; B = TRUE; break; ** B\A f b b f
} **
s = m_first; ** f = TRUE, b = FALSE when stored in the entry record
//** testing */
if( s->isIntersect() ) TRACE( "boolean...phase 2\n" );
wxASSERT(0);
//** end test BOOL A, B;
BOOL entry;
if (polyB->isInside(s)) // if we are already inside switch( oper )
entry = !A; // next intersection must be an exit {
else // otherwise case A_OR_B:
entry = A; // next intersection must be an entry A = FALSE; B = FALSE; break;
do
{ case A_AND_B:
if (s->isIntersect()) A = TRUE; B = TRUE; break;
{
s->setEntry(entry); case A_MINUS_B:
entry = !entry; A = FALSE; B = TRUE; break;
}
s = s->Next(); case B_MINUS_A:
} A = TRUE; B = FALSE; break;
while (s->id() != m_first->id());
/* default:
** Repeat for other polygon A = TRUE; B = TRUE; break;
*/ }
c = polyB->m_first;
if (this->isInside(c)) // if we are already inside s = m_first;
entry = !B; // next intersection must be an exit
else // otherwise //** testing
entry = B; // next intersection must be an entry if( s->isIntersect() )
do wxASSERT( 0 );
{
if (c->isIntersect()) //** end test
{ BOOL entry;
c->setEntry(entry); if( polyB->isInside( s ) ) // if we are already inside
entry = !entry; entry = !A; // next intersection must be an exit
} else // otherwise
c = c->Next(); entry = A; // next intersection must be an entry
}
while (c->id() != polyB->m_first->id()); do
/* {
** Phase 3 of the algorithm is to scan the linked lists of the if( s->isIntersect() )
** two input polygons an construct a linked list of result {
** polygons. We start at the first intersection then depending s->setEntry( entry );
** on whether it is an entry or exit point we continue building entry = !entry;
** our result polygon by following the source or clip polygon }
** either forwards or backwards. s = s->Next();
*/ } while( s->id() != m_first->id() );
while (this->unckd_remain()) // Loop while unchecked intersections remain
{ /*
vertex * v = first_unckd_intersect(); // Get the first unchecked intersect point ** Repeat for other polygon
polygon * r = new polygon; // Create a new instance of that class */
do c = polyB->m_first;
{ if( this->isInside( c ) ) // if we are already inside
v->setChecked(); // Set checked flag true for this intersection entry = !B; // next intersection must be an exit
if (v->isEntry()) else // otherwise
{ entry = B; // next intersection must be an entry
do
{ do
v = v->Next(); {
vertex * nv = new vertex(v->X(),v->Y(),v->Xc(),v->Yc(),v->d()); if( c->isIntersect() )
r->add(nv); {
} c->setEntry( entry );
while (!v->isIntersect()); entry = !entry;
} }
else c = c->Next();
{ } while( c->id() != polyB->m_first->id() );
do
{ /*
v = v->Prev(); ** Phase 3 of the algorithm is to scan the linked lists of the
vertex * nv = new vertex(v->X(),v->Y(),v->Xc(FALSE),v->Yc(FALSE),v->d(FALSE)); ** two input polygons an construct a linked list of result
r->add(nv); ** polygons. We start at the first intersection then depending
} ** on whether it is an entry or exit point we continue building
while (!v->isIntersect()); ** our result polygon by following the source or clip polygon
} ** either forwards or backwards.
v = v->Neighbor(); */
} TRACE( "boolean...phase 3\n" );
while (!v->isChecked()); // until polygon closed while( this->unckd_remain() ) // Loop while unchecked intersections remain
if (last) // Check in case first time thru the loop {
r->m_first->setNextPoly(last); // Save ref to the last poly in the first vertex vertex* v = first_unckd_intersect(); // Get the first unchecked intersect point
// of this poly polygon* r = new polygon; // Create a new instance of that class
last = r; // Save this polygon
} // end of while there is another intersection to check do
/* {
** Clean up the input polygons by deleting the intersection points v->setChecked(); // Set checked flag true for this intersection
*/ if( v->isEntry() )
res(); {
polyB->res(); do
/* {
** It is possible that no intersection between the polygons was found and v = v->Next();
** there is no result to return. In this case we make function fail vertex* nv = new vertex( v->X(), v->Y(), v->Xc(), v->Yc(), v->d() );
** gracefully as follows (depending on the requested operation): r->add( nv );
** } while( !v->isIntersect() );
** A|B : Return this with polyB in m_first->nextPoly }
** A&B : Return this else
** A\B : Return this {
** B\A : return polyB do
*/ {
polygon * p; v = v->Prev();
if (!last) vertex* nv =
{ new vertex( v->X(), v->Y(), v->Xc( FALSE ), v->Yc( FALSE ), v->d( FALSE ) );
switch (oper) r->add( nv );
{ } while( !v->isIntersect() );
case A_OR_B: }
last = copy_poly(); v = v->Neighbor();
p = polyB->copy_poly(); } while( !v->isChecked() ); // until polygon closed
last->m_first->setNextPoly(p);
break; if( last ) // Check in case first time thru the loop
case A_AND_B: r->m_first->setNextPoly( last ); // Save ref to the last poly in the first vertex
last = copy_poly(); // of this poly
break; last = r; // Save this polygon
case A_MINUS_B: } // end of while there is another intersection to check
last = copy_poly();
break; /*
case B_MINUS_A: ** Clean up the input polygons by deleting the intersection points
last = polyB->copy_poly(); */
break; res();
default: polyB->res();
last = copy_poly();
break; /*
} ** It is possible that no intersection between the polygons was found and
} ** there is no result to return. In this case we make function fail
else if (m_first->m_nextPoly) ** gracefully as follows (depending on the requested operation):
{ **
last->m_first->m_nextPoly = m_first->NextPoly(); ** A|B : Return this with polyB in m_first->nextPoly
} ** A&B : Return this
return last; ** A\B : Return this
** B\A : return polyB
*/
polygon* p;
if( !last )
{
TRACE( "boolean...end with no intersection\n" );
switch( oper )
{
case A_OR_B:
last = copy_poly();
p = polyB->copy_poly();
last->m_first->setNextPoly( p );
break;
case A_AND_B:
last = copy_poly();
break;
case A_MINUS_B:
last = copy_poly();
break;
case B_MINUS_A:
last = polyB->copy_poly();
break;
default:
last = copy_poly();
break;
}
}
else if( m_first->m_nextPoly )
{
TRACE( "boolean...end with nextPoly\n" );
last->m_first->m_nextPoly = m_first->NextPoly();
}
vertex * curr_vertex = last->getFirst();
for( int ii = 0; ii < last->m_cnt; ii++ )
{
int x = (int) curr_vertex->X();
int y = (int) curr_vertex->Y();
TRACE( "point %d @ %.4f %.4f\n", ii, (float)x/10000, (float)y/10000 );
curr_vertex = curr_vertex->Next();
}
return last;
} // end of boolean function } // end of boolean function
/* /*
** Test if a polygon lies entirly inside this polygon ** Test if a polygon lies entirly inside this polygon
** **
...@@ -955,155 +1063,164 @@ polygon * polygon::boolean( polygon * polyB, int oper ) ...@@ -955,155 +1063,164 @@ polygon * polygon::boolean( polygon * polyB, int oper )
*/ */
#if 0 #if 0
function polygon::isPolyInside (p) function polygon::isPolyInside( p )
{ {
inside = TRUE; inside = TRUE;
c = p->getFirst(); // Get the first vertex in polygon p c = p->getFirst(); // Get the first vertex in polygon p
do
{ do
if (!this->isInside(c)) // If vertex is NOT inside this polygon {
inside = FALSE; // then set flag to false if( !this->isInside( c ) ) // If vertex is NOT inside this polygon
c = c->Next(); // Get the next vertex in polygon p inside = FALSE; // then set flag to false
} c = c->Next(); // Get the next vertex in polygon p
while (c->id() != p->first->id()); } while( c->id() != p->first->id() );
if (inside)
{ if( inside )
c = p->getFirst(); // Get the first vertex in polygon p {
s = getFirst(); // Get the first vertex in this polygon c = p->getFirst(); // Get the first vertex in polygon p
do s = getFirst(); // Get the first vertex in this polygon
{
do do
{ {
if (this->ints(s, s->Next(),c, c->Next(), n, x, y, aS, aC)) do
inside = FALSE; {
c = c->Next(); if( this->ints( s, s->Next(), c, c->Next(), n, x, y, aS, aC ) )
} inside = FALSE;
while (c->id() != p->first->id()); c = c->Next();
s = s->Next(); } while( c->id() != p->first->id() );
}
while (s->id() != m_first->id()); s = s->Next();
} } while( s->id() != m_first->id() );
return inside; }
return inside;
} // end of isPolyInside } // end of isPolyInside
/* /*
** Move Polygon ** Move Polygon
** **
** Translates polygon by delta X and delta Y ** Translates polygon by delta X and delta Y
*/ */
function polygon::move (dx, dy) function polygon::move( dx, dy )
{ {
v = getFirst(); v = getFirst();
do
{ do
v->setX(v->X() + dx); {
v->setY(v->Y() + dy); v->setX( v->X() + dx );
if (v->d() != 0) v->setY( v->Y() + dy );
{ if( v->d() != 0 )
v->setXc(v->Xc() + dx); {
v->setYc(v->Yc() + dy); v->setXc( v->Xc() + dx );
} v->setYc( v->Yc() + dy );
v = v->Next(); }
} v = v->Next();
while(v->id() != m_first->id()); } while( v->id() != m_first->id() );
} // end of move polygon } // end of move polygon
/* /*
** Rotate Polygon ** Rotate Polygon
** **
** Rotates a polgon about point xr/yr by a radians ** Rotates a polgon about point xr/yr by a radians
*/ */
function polygon::rotate (xr, yr, a) function polygon::rotate( xr, yr, a )
{ {
this->move(-xr,-yr); // Move the polygon so that the point of this->move( -xr, -yr ); // Move the polygon so that the point of
// rotation is at the origin (0,0) // rotation is at the origin (0,0)
if (a < 0) // We might be passed a negitive angle if( a < 0 ) // We might be passed a negitive angle
a += 2*pi(); // make it positive a += 2 * pi(); // make it positive
v = m_first; v = m_first;
do
{ do
x=v->X(); y=v->Y(); {
v->setX(x*cos(a) - y*sin(a)); // x' = xCos(a)-ySin(a) x = v->X(); y = v->Y();
v->setY(x*sin(a) + y*cos(a)); // y' = xSin(a)+yCos(a) v->setX( x * cos( a ) - y * sin( a ) ); // x' = xCos(a)-ySin(a)
if (v->d() != 0) v->setY( x * sin( a ) + y * cos( a ) ); // y' = xSin(a)+yCos(a)
{ if( v->d() != 0 )
x=v->Xc(); y=v->Yc(); {
v->setXc(x*cos(a) - y*sin(a)); x = v->Xc(); y = v->Yc();
v->setYc(x*sin(a) + y*cos(a)); v->setXc( x * cos( a ) - y * sin( a ) );
} v->setYc( x * sin( a ) + y * cos( a ) );
v = v->Next(); }
} v = v->Next();
while(v->id() != m_first->id()); } while( v->id() != m_first->id() );
this->move(xr,yr); // Move the rotated polygon back
this->move( xr, yr ); // Move the rotated polygon back
} // end of rotate polygon } // end of rotate polygon
/* /*
** Return Bounding Rectangle for a Polygon ** Return Bounding Rectangle for a Polygon
** **
** returns a polygon object that represents the bounding rectangle ** returns a polygon object that represents the bounding rectangle
** for this polygon. Arc segments are correctly handled. ** for this polygon. Arc segments are correctly handled.
*/ */
function polygon::&bRect () function polygon::& bRect()
{ {
minX = INF; minY = INF; maxX = -INF; maxY = -INF; minX = INF; minY = INF; maxX = -INF; maxY = -INF;
v = m_first; v = m_first;
do
{ do
if (v->d() != 0) // Is it an arc segment {
{ if( v->d() != 0 ) // Is it an arc segment
vn = v->Next(); // end vertex of the arc segment {
v1 = new vertex(v->Xc(), -infinity); // bottom point of vertical line thru arc center vn = v->Next(); // end vertex of the arc segment
v2 = new vertex(v->Xc(), +infinity); // top point of vertical line thru arc center v1 = new vertex( v->Xc(), -infinity ); // bottom point of vertical line thru arc center
if (this->ints(v, vn, v1, v2, n, x, y, aS, aC)) // Does line intersect the arc ? v2 = new vertex( v->Xc(), +infinity ); // top point of vertical line thru arc center
{ if( this->ints( v, vn, v1, v2, n, x, y, aS, aC ) ) // Does line intersect the arc ?
for (i=0; i<n; i++) // check y portion of all intersections {
{ for( i = 0; i<n; i++ ) // check y portion of all intersections
minY = min(minY, y[i], v->Y()); {
maxY = max(maxY, y[i], v->Y()); minY = min( minY, y[i], v->Y() );
} maxY = max( maxY, y[i], v->Y() );
} }
else // There was no intersection so bounding rect is determined }
{ // by the start point only, not teh edge of the arc else // There was no intersection so bounding rect is determined
minY = min(minY, v->Y()); {
maxY = max(maxY, v->Y()); // by the start point only, not teh edge of the arc
} minY = min( minY, v->Y() );
v1 = NULL; v2 = NULL; // Free the memory used maxY = max( maxY, v->Y() );
h1 = new vertex(-infinity, v->Yc()); // left point of horozontal line thru arc center }
h2 = new vertex(+infinity, v->Yc()); // right point of horozontal line thru arc center v1 = NULL; v2 = NULL; // Free the memory used
if (this->ints(v, vn, h1, h2, n, x, y, aS, aC)) // Does line intersect the arc ? h1 = new vertex( -infinity, v->Yc() ); // left point of horozontal line thru arc center
{ h2 = new vertex( +infinity, v->Yc() ); // right point of horozontal line thru arc center
for (i=0; i<n; i++) // check x portion of all intersections if( this->ints( v, vn, h1, h2, n, x, y, aS, aC ) ) // Does line intersect the arc ?
{ {
minX = min(minX, x[i], v->X()); for( i = 0; i<n; i++ ) // check x portion of all intersections
maxX = max(maxX, x[i], v->X()); {
} minX = min( minX, x[i], v->X() );
} maxX = max( maxX, x[i], v->X() );
else }
{ }
minX = min(minX, v->X()); else
maxX = max(maxX, v->X()); {
} minX = min( minX, v->X() );
h1 = NULL; h2 = NULL; maxX = max( maxX, v->X() );
} }
else // Straight segment so just check the vertex h1 = NULL; h2 = NULL;
{ }
minX = min(minX, v->X()); else // Straight segment so just check the vertex
minY = min(minY, v->Y()); {
maxX = max(maxX, v->X()); minX = min( minX, v->X() );
maxY = max(maxY, v->Y()); minY = min( minY, v->Y() );
} maxX = max( maxX, v->X() );
v = v->Next(); maxY = max( maxY, v->Y() );
} }
while(v->id() != m_first->id()); v = v->Next();
// } while( v->id() != m_first->id() );
// Now create an return a polygon with the bounding rectangle
// //
this_class = get_class(this); // Findout the class I'm in (might be an extension of polygon) // Now create an return a polygon with the bounding rectangle
p = new this_class; // Create a new instance of that class //
p->addv(minX,minY); this_class = get_class( this ); // Findout the class I'm in (might be an extension of polygon)
p->addv(minX,maxY); p = new this_class; // Create a new instance of that class
p->addv(maxX,maxY); p->addv( minX, minY );
p->addv(maxX,minY); p->addv( minX, maxY );
return p; p->addv( maxX, maxY );
p->addv( maxX, minY );
return p;
} // end of bounding rectangle } // end of bounding rectangle
#endif #endif
// file php_polygon.h // file php_polygon.h
// See comments in php_polygon.cpp // See comments in php_polygon.cpp
#ifndef PHP_POLYGON_H #ifndef PHP_POLYGON_H
...@@ -7,55 +8,65 @@ ...@@ -7,55 +8,65 @@
class vertex; class vertex;
class segment; class segment;
#define infinity 100000000 // for places that are far far away #define infinity 100000000 // for places that are far far away
#define PI 3.14159265359 #define PI 3.14159265359
enum{ A_OR_B, A_AND_B, A_MINUS_B, B_MINUS_A }; enum {
A_OR_B,
A_AND_B,
A_MINUS_B,
B_MINUS_A
};
class polygon
{
public:
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
** This class manages a doubly linked list of vertex objects that represents ** This class manages a doubly linked list of vertex objects that represents
** a polygon. The class consists of basic methods to manage the list ** a polygon. The class consists of basic methods to manage the list
** and methods to implement boolean operations between polygon objects. ** and methods to implement boolean operations between polygon objects.
*/ */
vertex * m_first; // Reference to first vertex in the linked list
int m_cnt; // Tracks number of vertices in the polygon class polygon
{
polygon( vertex * first = NULL ); public:
~polygon(); vertex* m_first; // Reference to first vertex in the linked list
vertex * getFirst(); int m_cnt; // Tracks number of vertices in the polygon
polygon * NextPoly();
public:
void add( vertex * nv ); polygon( vertex* first = NULL );
void addv( double x, double y, ~polygon();
double xc=0, double yc=0, int d=0); vertex* getFirst();
vertex * del( vertex * v ); polygon* NextPoly();
void res();
polygon * copy_poly(); void add( vertex* nv );
void insertSort( vertex * nv, vertex * s, vertex * e ); void addv( double x, double y,
vertex * nxt( vertex * v ); double xc = 0, double yc = 0, int d = 0 );
BOOL unckd_remain(); vertex* del( vertex* v );
vertex * first_unckd_intersect(); void res();
double dist( double x1, double y1, double x2, double y2 ); polygon* copy_poly();
double angle( double xc, double yc, double x1, double y1 ); void insertSort( vertex* nv, vertex* s, vertex* e );
double aAlpha( double x1, double y1, double x2, double y2, vertex* nxt( vertex* v );
double xc, double yc, double xi, double yi, double d ); BOOL unckd_remain();
void perturb( vertex * p1, vertex * p2, vertex * q1, vertex * q2, vertex* first_unckd_intersect();
double aP, double aQ ); double dist( double x1, double y1, double x2, double y2 );
BOOL ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2, double angle( double xc, double yc, double x1, double y1 );
int * n, double ix[], double iy[], double alphaP[], double alphaQ[] ); double aAlpha( double x1, double y1, double x2, double y2,
BOOL isInside ( vertex * v ); double xc, double yc, double xi, double yi, double d );
polygon * boolean( polygon * polyB, int oper ); void perturb( vertex* p1, vertex* p2, vertex* q1, vertex* q2,
double aP, double aQ );
BOOL ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
int* n, double ix[], double iy[], double alphaP[], double alphaQ[] );
BOOL isInside( vertex* v );
polygon* boolean( polygon* polyB, int oper );
#if 0 #if 0
function isPolyInside (p); function isPolyInside( p );
function move (dx, dy); function move( dx, dy );
function rotate (xr, yr, a); function rotate( xr, yr, a );
function &bRect (); function& bRect();
#endif #endif
}; //end of class polygon }; //end of class polygon
#endif // ifndef PHP_POLYGON_H #endif // ifndef PHP_POLYGON_H
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment