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