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:
parent
88055164d5
commit
b8ea76fe63
|
@ -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 )
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue