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

B.O.M. generation still have a minor problem wih this.
This commit is contained in:
charras 2008-05-15 11:20:19 +00:00
parent 88055164d5
commit b8ea76fe63
17 changed files with 2804 additions and 2443 deletions

View File

@ -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

View File

@ -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 )

View File

@ -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,6 +467,9 @@ void SCH_COMPONENT::ClearAnnotation( DrawSheetPath* aSheet )
defRef.Append( wxT( "?" ) );
wxString multi = wxT( "1" );
if ( KeepMulti ) // We cannot remove all annotations: part selection must be kept
{
wxString NewHref;
wxString path;
if( aSheet )
@ -486,15 +487,20 @@ void SCH_COMPONENT::ClearAnnotation( DrawSheetPath* aSheet )
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];

View File

@ -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. */

View File

@ -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;

View File

@ -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,14 +791,13 @@ 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:
if( SchItem->Type() != TYPE_SCH_COMPONENT )
continue;
ItemCount++;
DrawLibItem = (SCH_COMPONENT*) DrawList;
DrawLibItem = (SCH_COMPONENT*) SchItem;
DrawLibItem->m_Parent = sheet->LastScreen();
if( List )
{
@ -825,13 +808,6 @@ int GenListeCmp( ListComponent* List )
sizeof( List->m_Ref ) );
List++;
}
break;
default:
break;
}
DrawList = DrawList->Pnext;
}
}

View File

@ -25,17 +25,22 @@ 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);
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,
@ -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] == '#' )
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,12 +163,14 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList(
memset( s_SortedComponentPinList, 0, ii );
DEntry = Entry->m_Drawings;
if( Entry->m_UnitCount <= 1 ) // One part per package
{
for( ; DEntry != NULL; DEntry = DEntry->Next() )
{
if( DEntry->Type() != COMPONENT_PIN_DRAW_TYPE )
continue;
if( DEntry->m_Unit
&& (DEntry->m_Unit != Component->m_Multi) )
&& ( DEntry->m_Unit != Component->GetUnitSelection( sheet ) ) )
continue;
if( DEntry->m_Convert
&& (DEntry->m_Convert != Component->m_Convert) )
@ -160,18 +179,15 @@ static SCH_COMPONENT* FindNextComponentAndCreatPinList(
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;
@ -218,10 +234,12 @@ 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 << 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,12 +258,11 @@ 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;
EDA_BaseStruct* SchItem;
SCH_COMPONENT* Component;
wxString netname;
int ii;
@ -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,9 +287,9 @@ 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
@ -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,7 +384,7 @@ static void WriteNetListPspice( WinEDA_SchematicFrame* frame, FILE* f,
* sinon les nodes sont identifies par le netnumber
*
* tous les textes graphiques commen<EFBFBD>ant par [.-+]pspice ou [.-+]gnucap
* sont consid<EFBFBD>r<EFBFBD>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
*/
@ -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
@ -547,7 +547,7 @@ static void WriteNetListPCBNEW( WinEDA_SchematicFrame* frame, FILE* f, bool with
/* 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 );
@ -566,7 +566,8 @@ 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 );
}
@ -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++){
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;
@ -739,56 +745,40 @@ 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;
if( SchItem->Type() != TYPE_SCH_COMPONENT )
continue;
Component2 = (SCH_COMPONENT*) SchItem;
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( str.CmpNoCase( Reference ) != 0 )
continue;
Entry = FindLibPart( Component2->m_ChipName.GetData(), wxEmptyString, FIND_ROOT );
if( Entry == NULL )
break;
if( str[0] == '#' )
break;
if( Entry->m_Drawings != NULL )
if( Entry && Entry->m_Drawings != NULL )
{
DEntry = Entry->m_Drawings;
for( ; DEntry != NULL; DEntry = DEntry->Next() )
@ -796,26 +786,16 @@ static void FindOthersUnits( SCH_COMPONENT* Component_in, DrawSheetPath* Sheet_i
if( DEntry->Type() != COMPONENT_PIN_DRAW_TYPE )
continue;
if( DEntry->m_Unit
&& (DEntry->m_Unit != Component2->m_Multi) )
&& ( 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;
}
}
}
@ -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 << wxT("_") <<
// g_TabObjNet[jj].m_SheetList.PathHumanReadable();
}
@ -971,7 +953,7 @@ 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() )
@ -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 << wxT("_") <<
// g_TabObjNet[jj].m_SheetList.PathHumanReadable();
}

View File

@ -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;
}
}

View File

@ -97,11 +97,13 @@ typedef struct ListLabel
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.
//have to store it here since the object references will be duplicated.
DrawSheetPath m_SheetList; //composed of UIDs
} ListComponent;

View File

@ -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 )

View File

@ -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);

View File

@ -212,20 +212,20 @@
#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"

View File

@ -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
*/

View File

@ -1,4 +1,5 @@
// PolyLine.cpp ... implementation of CPolyLine class from FreePCB.
//
// implementation for kicad
//
@ -16,29 +17,43 @@ using namespace std;
#define pi 3.14159265359
#define DENOM 10 // to use mils for php clipping
//#define DENOM 1 // to use internal units for php clipping
CPolyLine::CPolyLine()
{
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();
#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
@ -76,6 +91,7 @@ int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, bool bRetainArcs
else
AppendCorner( x, y, STRAIGHT, FALSE );
}
Close();
n_ext_cont++;
}
@ -93,13 +109,13 @@ int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, bool bRetainArcs
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++ )
{
@ -142,9 +158,11 @@ int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, bool bRetainArcs
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();
@ -152,21 +170,24 @@ int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, bool bRetainArcs
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 );
}
m_php_poly->addv( GetX( iv ), GetY( iv ) );
m_php_poly->getFirst()->m_id = 1;
return 0;
}
void CPolyLine::FreePhpPoly()
{
// delete all vertices
@ -175,11 +196,13 @@ void CPolyLine::FreePhpPoly()
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 )
@ -196,33 +219,76 @@ void CPolyLine::ClipPhpPolygon( int php_op, CPolyLine * poly )
// 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 );
Start( m_layer, to_int( v->X() ), to_int( v->Y() ), m_HatchStyle );
do
{
vertex* n = v->Next();
AppendCorner( to_int(v->X()*DENOM), to_int((v->Y()*DENOM )) );
AppendCorner( to_int( v->X() ), to_int( (v->Y()) ) );
v = n;
}
while( v->id() != p->getFirst()->id() );
} while( v->id() != p->getFirst()->id() );
Close();
// p = p->NextPoly();
delete p;
p = NULL;
}
while( p );
} 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 )
@ -286,6 +352,7 @@ int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array )
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 );
@ -389,6 +456,7 @@ int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array )
theta2 = 3.0 * pi / 2.0;
}
}
// now write steps for arc
if( arc_array )
{
@ -418,10 +486,13 @@ int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array )
}
}
}
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 )
@ -437,10 +508,12 @@ int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array )
free( g_v_list->vertex );
free( g_v_list );
}
return 0;
}
int CPolyLine::FreeGpcPoly()
void CPolyLine::FreeGpcPoly()
{
if( m_gpc_poly->num_contours )
{
@ -449,10 +522,11 @@ int CPolyLine::FreeGpcPoly()
delete m_gpc_poly->hole;
}
m_gpc_poly->num_contours = 0;
return 0;
}
#endif
// Restore arcs to a polygon where they were replaced with steps
// If pa != NULL, also use polygons in pa array
//
@ -460,6 +534,7 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine
{
// get poly info
int n_polys = 1;
if( pa )
n_polys += pa->size();
CPolyLine* poly;
@ -474,6 +549,7 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine
poly->Undraw();
for( int ic = 0; ic<poly->GetNumCorners(); ic++ )
poly->SetUtility( ic, 0 ); // clear utility flag
}
// find arcs and replace them
@ -489,6 +565,7 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine
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++ )
{
@ -544,6 +621,7 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine
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; )
{
@ -555,6 +633,7 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine
else
i++;
}
break;
}
}
@ -566,6 +645,7 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine
break;
}
}
if( bFound )
(*arc_array)[iarc].bFound = TRUE;
}
@ -583,9 +663,11 @@ int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine
poly->DeleteCorner( ic, FALSE );
}
}
return 0;
}
// initialize new polyline
// set layer, width, selection box size, starting point, id and pointer
//
@ -614,6 +696,7 @@ void CPolyLine::Start( int layer, int x, int y, int hatch )
side_style.push_back( 0 );
}
// add a corner to unclosed polyline
//
void CPolyLine::AppendCorner( int x, int y, int style, bool bDraw )
@ -640,6 +723,7 @@ void CPolyLine::AppendCorner( int x, int y, int style, bool bDraw )
Draw();
}
// close last polyline contour
//
void CPolyLine::Close( int style, bool bDraw )
@ -653,6 +737,7 @@ void CPolyLine::Close( int style, bool bDraw )
Draw();
}
// move corner of polyline
//
void CPolyLine::MoveCorner( int ic, int x, int y )
@ -663,6 +748,7 @@ void CPolyLine::MoveCorner( int ic, int x, int y )
Draw();
}
// delete corner and adjust arrays
//
void CPolyLine::DeleteCorner( int ic, bool bDraw )
@ -698,9 +784,11 @@ void CPolyLine::DeleteCorner( int ic, bool bDraw )
Draw();
}
/******************************************/
void CPolyLine::RemoveContour( int icont )
/******************************************/
/**
* Function RemoveContour
* @param icont = contour number to remove
@ -738,6 +826,7 @@ void CPolyLine::RemoveContour( int icont )
/******************************************/
void CPolyLine::RemoveAllContours( void )
/******************************************/
/**
* function RemoveAllContours
* removes all corners from the lists.
@ -779,6 +868,7 @@ void CPolyLine::InsertCorner( int ic, int x, int y )
Draw();
}
// undraw polyline by removing all graphic elements from display list
//
void CPolyLine::Undraw()
@ -787,13 +877,13 @@ void CPolyLine::Undraw()
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()
{
// first, undraw if necessary
if( bDrawn )
Undraw();
@ -808,19 +898,23 @@ int CPolyLine::GetX( int ic )
return corner[ic].x;
}
int CPolyLine::GetY( int ic )
{
return corner[ic].y;
}
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;
@ -828,9 +922,11 @@ CRect CPolyLine::GetBounds()
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++ )
@ -840,12 +936,15 @@ CRect CPolyLine::GetCornerBounds()
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 );
@ -857,14 +956,17 @@ CRect CPolyLine::GetCornerBounds( int icont )
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::GetNumSides()
{
if( GetClosed() )
@ -873,31 +975,38 @@ int CPolyLine::GetNumSides()
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 CPolyLine::GetContour( int ic )
{
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 )
@ -913,10 +1022,12 @@ int CPolyLine::GetContourStart( int icont )
return i + 1;
}
}
wxASSERT( 0 );
return 0;
}
int CPolyLine::GetContourEnd( int icont )
{
if( icont < 0 )
@ -935,10 +1046,12 @@ int CPolyLine::GetContourEnd( int icont )
ncont++;
}
}
wxASSERT( 0 );
return 0;
}
int CPolyLine::GetContourSize( int icont )
{
return GetContourEnd( icont ) - GetContourStart( icont ) + 1;
@ -970,6 +1083,7 @@ void CPolyLine::SetSideStyle( int is, int style )
Draw();
}
int CPolyLine::GetSideStyle( int is )
{
return side_style[is];
@ -984,6 +1098,7 @@ int CPolyLine::GetClosed()
return corner[corner.size() - 1].end_contour;
}
// draw hatch lines
//
void CPolyLine::Hatch()
@ -1019,6 +1134,7 @@ void CPolyLine::Hatch()
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;
@ -1038,18 +1154,21 @@ void CPolyLine::Hatch()
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
{
@ -1091,13 +1210,14 @@ void CPolyLine::Hatch()
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
* my work done:
* wxASSERT( npts%2==0 ); // odd number of intersection points, error
*/
// sort points in order of descending x (if more than 2)
@ -1115,6 +1235,7 @@ void CPolyLine::Hatch()
imax = i;
}
}
int temp = xx[istart];
xx[istart] = xx[imax];
xx[imax] = temp;
@ -1145,18 +1266,23 @@ void CPolyLine::Hatch()
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)) );
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 };
enum {
MAXPTS = 100
};
if( !GetClosed() )
wxASSERT( 0 );
@ -1167,6 +1293,7 @@ bool CPolyLine::TestPointInside( int x, int y )
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
{
@ -1208,9 +1335,11 @@ bool CPolyLine::TestPointInside( int x, int y )
}
}
}
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
@ -1222,12 +1351,14 @@ bool CPolyLine::TestPointInside( int x, int y )
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 )
@ -1235,7 +1366,9 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
if( icont >= GetNumContours() )
return FALSE;
enum { MAXPTS = 100 };
enum {
MAXPTS = 100
};
if( !GetClosed() )
wxASSERT( 0 );
@ -1246,6 +1379,7 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
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
{
@ -1284,9 +1418,11 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
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
@ -1298,6 +1434,7 @@ bool CPolyLine::TestPointInsideContour( int icont, int x, int y )
else if( xx[ip] > x )
ncount++;
}
if( ncount % 2 )
return TRUE;
else
@ -1314,27 +1451,35 @@ void CPolyLine::Copy( CPolyLine * src )
// 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;
}
void CPolyLine::MoveOrigin( int x_off, int y_off )
{
Undraw();
@ -1343,6 +1488,7 @@ void CPolyLine::MoveOrigin( int x_off, int y_off )
SetX( ic, GetX( ic ) + x_off );
SetY( ic, GetY( ic ) + y_off );
}
Draw();
}
@ -1351,14 +1497,24 @@ 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;
}
// Create CPolyLine for a pad
//
CPolyLine* CPolyLine::MakePolylineForPad( int type, int x, int y, int w, int l, int r, int angle )
@ -1366,6 +1522,7 @@ CPolyLine * CPolyLine::MakePolylineForPad( int type, int x, int y, int w, int l,
CPolyLine* poly = new CPolyLine;
int dx = l / 2;
int dy = w / 2;
if( angle % 180 == 90 )
{
dx = w / 2;
@ -1382,16 +1539,27 @@ CPolyLine * CPolyLine::MakePolylineForPad( int type, int x, int y, int w, int l,
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;
@ -1463,8 +1631,10 @@ void CPolyLine::AddContourForPadClearance( int type, int x, int y, int w,
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 );
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 );
}
}
@ -1509,15 +1679,18 @@ void CPolyLine::AddContourForPadClearance( int type, int x, int y, int w,
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++ )
{
@ -1526,16 +1699,6 @@ void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int n
AppendCorner( x, y, STRAIGHT, 0 );
theta += th_d;
}
Close( STRAIGHT );
}
void CPolyLine::ClipGpcPolygon( gpc_op op, CPolyLine * clip_poly )
{
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;
}

View File

@ -16,6 +16,9 @@
#include <vector>
#define USE_GPC_POLY_LIB
//#define USE_GPL_POLY_LIB
#include "defs-macros.h"
#include "GenericPolygonClipperLibrary.h"
@ -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,
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

View File

@ -1,4 +1,5 @@
// 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,6 +59,7 @@
#include "php_polygon.h"
const double PT = 0.99999;
//const double eps = (1.0 - PT)/10.0;
const double eps = 0.0;
@ -66,6 +69,7 @@ polygon::polygon( vertex * first )
m_cnt = 0;
}
polygon::~polygon()
{
while( m_cnt > 1 )
@ -73,22 +77,26 @@ polygon::~polygon()
vertex* v = getFirst();
del( v->m_nextV );
}
if( m_first )
{
delete m_first;
}
}
vertex* polygon::getFirst()
{
return m_first;
}
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
@ -123,6 +131,7 @@ void polygon::add( vertex * nv )
m_cnt++; // Increment the count of vertices
}
/*
** Create a vertex and then add it to the polygon
*/
@ -130,9 +139,11 @@ void polygon::addv ( double x, double y,
double xc, double yc, int d )
{
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
@ -144,6 +155,7 @@ vertex * polygon::del( vertex * v )
// 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
@ -159,6 +171,7 @@ vertex * polygon::del( vertex * v )
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
@ -167,14 +180,15 @@ 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() );
}
while (v->id() != m_first->id());
}
/*
** Copy Polygon - Returns a reference to a new copy of the poly object
@ -184,15 +198,17 @@ 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());
} while( v->id() != m_first->id() );
return n;
}
/*
** Insert and Sort a vertex between a specified pair of vertices (start and end)
**
@ -205,11 +221,13 @@ polygon * polygon::copy_poly()
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
@ -224,17 +242,21 @@ void polygon::insertSort( vertex * nv, vertex * s, vertex * e )
m_cnt++; // Just added a new vertex
}
/*
** return the next non intersecting vertex after the one specified
*/
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
}
/*
** Check if any unchecked intersections remain in the polygon. The boolean
** method is complete when all intersections have been checked.
@ -243,16 +265,18 @@ 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());
} 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.
@ -260,13 +284,17 @@ BOOL polygon::unckd_remain()
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;
}
/*
** Return the distance between two points
*/
@ -274,6 +302,8 @@ double polygon::dist( double x1, double y1, double x2, double 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
@ -283,6 +313,7 @@ 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
@ -290,6 +321,7 @@ double polygon::angle( double xc, double yc, double x1, double y1 )
return a1;
}
/*
** Return Alpha value for an Arc
**
@ -303,6 +335,7 @@ double polygon::aAlpha( double x1, double y1, double x2, double y2,
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;
@ -321,6 +354,7 @@ double polygon::aAlpha( double x1, double y1, double x2, double y2,
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
@ -343,6 +377,7 @@ void polygon::perturb( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
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
{
@ -357,6 +392,7 @@ void polygon::perturb( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
}
}
/*
** Determine the intersection between two pairs of vertices p1/p2, q1/q2
**
@ -376,6 +412,7 @@ 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?
@ -398,7 +435,8 @@ BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
{ // 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 );
// 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.
@ -413,6 +451,7 @@ BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
{
// 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();
@ -427,16 +466,30 @@ BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
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 )
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 );
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;
}
@ -515,6 +568,7 @@ BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
// 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.
@ -558,7 +612,8 @@ BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
d = qt;
}
else // Segment q1,q2 is the line
{ // Segment p1,p2 is the arc
{
// Segment p1,p2 is the arc
x1 = q1->X(); y1 = q1->Y();
x2 = q2->X(); y2 = q2->Y();
xc = p1->Xc(); yc = p1->Yc();
@ -636,6 +691,7 @@ BOOL polygon::ints( vertex * p1, vertex * p2, vertex * q1, vertex * q2,
return found;
} // end of intersect function
/*
** Test if a vertex lies inside the polygon
**
@ -658,17 +714,20 @@ BOOL polygon::isInside( vertex * v )
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_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() )
@ -685,8 +744,8 @@ BOOL polygon::isInside( vertex * v )
winding_number4 += n; // Add number of intersections found
}
q = q->Next();
}
while( q->id() != m_first->id() );
} while( q->id() != m_first->id() );
// delete point_at_infinity;
// delete point_at_infinity2;
if( winding_number % 2 != winding_number2 % 2
@ -699,6 +758,7 @@ BOOL polygon::isInside( vertex * v )
return TRUE; // odd == inside
}
/*
** Execute a Boolean operation on a polygon
**
@ -720,6 +780,7 @@ polygon * polygon::boolean( polygon * polyB, int oper )
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
@ -727,6 +788,7 @@ polygon * polygon::boolean( polygon * polyB, int oper )
** 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",
@ -741,14 +803,21 @@ polygon * polygon::boolean( polygon * polyB, int oper )
{
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);
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] );
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);
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() ) );
@ -757,35 +826,38 @@ polygon * polygon::boolean( polygon * polyB, int oper )
}
} // end if c is not an intersect point
c = c->Next();
}
while (c->id() != polyB->m_first->id());
} while( c->id() != polyB->m_first->id() );
} // end if s not an intersect point
s = s->Next();
}
while(s->id() != m_first->id());
} 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
/*
@ -807,26 +879,41 @@ polygon * polygon::boolean( polygon * polyB, int oper )
**
** 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;
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() )
@ -835,8 +922,8 @@ polygon * polygon::boolean( polygon * polyB, int oper )
entry = !entry;
}
s = s->Next();
}
while (s->id() != m_first->id());
} while( s->id() != m_first->id() );
/*
** Repeat for other polygon
*/
@ -845,6 +932,7 @@ polygon * polygon::boolean( polygon * polyB, int oper )
entry = !B; // next intersection must be an exit
else // otherwise
entry = B; // next intersection must be an entry
do
{
if( c->isIntersect() )
@ -853,8 +941,8 @@ polygon * polygon::boolean( polygon * polyB, int oper )
entry = !entry;
}
c = c->Next();
}
while (c->id() != polyB->m_first->id());
} 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
@ -863,10 +951,12 @@ polygon * polygon::boolean( polygon * polyB, int oper )
** 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
@ -877,32 +967,33 @@ polygon * polygon::boolean( polygon * polyB, int oper )
v = v->Next();
vertex* nv = new vertex( v->X(), v->Y(), v->Xc(), v->Yc(), v->d() );
r->add( nv );
}
while (!v->isIntersect());
} 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));
vertex* nv =
new vertex( v->X(), v->Y(), v->Xc( FALSE ), v->Yc( FALSE ), v->d( FALSE ) );
r->add( nv );
}
while (!v->isIntersect());
} while( !v->isIntersect() );
}
v = v->Neighbor();
}
while (!v->isChecked()); // until polygon closed
} 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
@ -916,6 +1007,7 @@ polygon * polygon::boolean( polygon * polyB, int oper )
polygon* p;
if( !last )
{
TRACE( "boolean...end with no intersection\n" );
switch( oper )
{
case A_OR_B:
@ -923,15 +1015,19 @@ polygon * polygon::boolean( polygon * polyB, int oper )
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;
@ -939,11 +1035,23 @@ polygon * polygon::boolean( polygon * polyB, int oper )
}
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
**
@ -959,17 +1067,19 @@ 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());
} 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
@ -977,15 +1087,15 @@ function polygon::isPolyInside (p)
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());
} while( c->id() != p->first->id() );
s = s->Next();
}
while (s->id() != m_first->id());
} while( s->id() != m_first->id() );
}
return inside;
} // end of isPolyInside
/*
** Move Polygon
**
@ -994,6 +1104,7 @@ function polygon::isPolyInside (p)
function polygon::move( dx, dy )
{
v = getFirst();
do
{
v->setX( v->X() + dx );
@ -1004,10 +1115,10 @@ function polygon::move (dx, dy)
v->setYc( v->Yc() + dy );
}
v = v->Next();
}
while(v->id() != m_first->id());
} while( v->id() != m_first->id() );
} // end of move polygon
/*
** Rotate Polygon
**
@ -1020,6 +1131,7 @@ function polygon::rotate (xr, yr, a)
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();
@ -1032,11 +1144,12 @@ function polygon::rotate (xr, yr, a)
v->setYc( x * sin( a ) + y * cos( a ) );
}
v = v->Next();
}
while(v->id() != m_first->id());
} 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
**
@ -1047,6 +1160,7 @@ function polygon::&bRect ()
{
minX = INF; minY = INF; maxX = -INF; maxY = -INF;
v = m_first;
do
{
if( v->d() != 0 ) // Is it an arc segment
@ -1063,7 +1177,8 @@ function polygon::&bRect ()
}
}
else // There was no intersection so bounding rect is determined
{ // by the start point only, not teh edge of the arc
{
// by the start point only, not teh edge of the arc
minY = min( minY, v->Y() );
maxY = max( maxY, v->Y() );
}
@ -1093,8 +1208,8 @@ function polygon::&bRect ()
maxY = max( maxY, v->Y() );
}
v = v->Next();
}
while(v->id() != m_first->id());
} while( v->id() != m_first->id() );
//
// Now create an return a polygon with the bounding rectangle
//
@ -1106,4 +1221,6 @@ function polygon::&bRect ()
p->addv( maxX, minY );
return p;
} // end of bounding rectangle
#endif

View File

@ -1,4 +1,5 @@
// file php_polygon.h
// See comments in php_polygon.cpp
#ifndef PHP_POLYGON_H
@ -10,20 +11,27 @@ class segment;
#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.
*/
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();
@ -45,15 +53,18 @@ public:
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();
#endif
}; //end of class polygon