Commit 5eda8a52 authored by CHARRAS's avatar CHARRAS

First draft (and first code..) about new zone handling

parent ee3d9844
ADD_DEFINITIONS(-DPCBNEW)
INCLUDE_DIRECTORIES(../pcbnew)
INCLUDE_DIRECTORIES(../pcbnew ../polygon)
SET(3D-VIEWER_SRCS
3d_aux.cpp
......
EXTRALIBS =
EXTRACPPFLAGS= -I./ -I../include -I../common -I../pcbnew
EXTRACPPFLAGS= -I./ -I../include -I../common -I../polygon -I../pcbnew
CPPFLAGS += $(EXTRACPPFLAGS)
......
......@@ -4,6 +4,14 @@ Started 2007-June-11
Please add newer entries at the top, list the date and your name with
email address.
2007-Dec-29 UPDATE Jean-Pierre Charras <jean-pierre.charras@inpg.fr>
================================================================================
+pcbnew:
First draft (and code..) about new zone handling, using polygons to define an outline.
Now currently not useable because the fill function (and many other important functions) is not implemented.
Many functions are not yet implemented: merging zones, cutout, DRC ...
Nevertheless, one can create, modify edit and save zone outlines
2007-Dec-23 UPDATE Dick Hollenbeck <dick@softplc.com>
================================================================================
......
......@@ -4,6 +4,7 @@ INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}
bitmaps
../3d-viewer
../polygon
../pcbnew)
SET(CVPCB_SRCS
......@@ -35,6 +36,7 @@ SET(CVPCB_SRCS
SET(CVPCB_EXTRA_SRCS
../pcbnew/basepcbframe.cpp
../pcbnew/class_board.cpp
../pcbnew/class_zone.cpp
../pcbnew/class_cotation.cpp
../pcbnew/class_edge_mod.cpp
../pcbnew/class_equipot.cpp
......
# makefile pour cvpcb (mingw)
OBJSUFF = o
EXTRACPPFLAGS += -DCVPCB -fno-strict-aliasing -I./ -I../cvpcb -I../include -Ibitmaps -I../pcbnew -I../3d-viewer
EXTRALIBS = ../common/common.a
EXTRACPPFLAGS += -DCVPCB -fno-strict-aliasing\
-I./ -I../cvpcb -I../include -Ibitmaps\
-I../pcbnew -I../3d-viewer\
-I../polygon
EXTRALIBS = ../common/common.a ../polygon/lib_polygon.a
LIBVIEWER3D = ../3d-viewer/3d-viewer.a
......@@ -10,6 +14,7 @@ LIBVIEWER3D = ../3d-viewer/3d-viewer.a
OBJECTS = $(TARGET).o \
class_cvpcb.o\
class_zone.o\
memoire.o \
cvframe.o\
listboxes.o\
......@@ -69,6 +74,9 @@ classpcb.o: ../pcbnew/classpcb.cpp $(DEPEND)
class_mire.o: ../pcbnew/class_mire.cpp ../pcbnew/class_mire.h $(COMMON)
$(CXX) -c $(EDACPPFLAGS) -o $@ ../pcbnew/$*.cpp
class_zone.o: ../pcbnew/class_zone.cpp ../pcbnew/class_zone.h $(COMMON)
$(CXX) -c $(EDACPPFLAGS) -o $@ ../pcbnew/$*.cpp
class_cotation.o: ../pcbnew/class_cotation.cpp ../pcbnew/class_cotation.h $(COMMON)
$(CXX) -c $(EDACPPFLAGS) -o $@ ../pcbnew/$*.cpp
......
......@@ -4,7 +4,8 @@ INCLUDE_DIRECTORIES(
${CMAKE_CURRENT_SOURCE_DIR}
../3d-viewer
../cvpcb
../pcbnew)
../pcbnew
../polygon)
SET(GERBVIEW_SRCS
affiche.cpp
......@@ -41,6 +42,7 @@ SET(GERBVIEW_SRCS
SET(GERBVIEW_EXTRA_SRCS
../pcbnew/basepcbframe.cpp
../pcbnew/class_board.cpp
../pcbnew/class_zone.cpp
../pcbnew/class_drc_item.cpp
../pcbnew/class_marker.cpp
../pcbnew/class_pcb_text.cpp
......@@ -74,6 +76,6 @@ ENDIF(APPLE)
ADD_EXECUTABLE(gerbview WIN32 MACOSX_BUNDLE ${GERBVIEW_SRCS} ${GERBVIEW_EXTRA_SRCS} ${GERBVIEW_RESOURCES})
TARGET_LINK_LIBRARIES(gerbview common 3d-viewer ${wxWidgets_LIBRARIES})
TARGET_LINK_LIBRARIES(gerbview common 3d-viewer lib_polygon ${wxWidgets_LIBRARIES})
INSTALL(TARGETS gerbview RUNTIME DESTINATION ${KICAD_BIN})
EXTRALIBS = ../common/common.a
EXTRACPPFLAGS= -DGERBVIEW -DPCBNEW -fno-strict-aliasing -I./ -I../gerbview -I../include\
-I../share -I../pcbnew -I../3d-viewer
EXTRALIBS = ../common/common.a ../polygon/lib_polygon.a
EXTRACPPFLAGS= -DGERBVIEW -DPCBNEW -fno-strict-aliasing\
-I./ -I../gerbview -I../include\
-I../share -I../pcbnew -I../3d-viewer\
-I../polygon
#COMMON = pcbnew.h struct.h
OBJECTS= \
$(TARGET).o\
classpcb.o\
class_zone.o\
select_layers_to_pcb.o\
sel_layer.o\
lay2plot.o\
......@@ -69,6 +74,9 @@ files.o: files.cpp $(COMMON)
class_marker.o: ../pcbnew/class_marker.cpp ../pcbnew/class_marker.h $(COMMON)
$(CXX) -c $(EDACPPFLAGS) -o $@ ../pcbnew/$*.cpp
class_zone.o: ../pcbnew/class_zone.cpp ../pcbnew/class_zone.h $(COMMON)
$(CXX) -c $(EDACPPFLAGS) -o $@ ../pcbnew/$*.cpp
class_drc_item.o: ../pcbnew/class_drc_item.cpp $(COMMON)
$(CXX) -c $(EDACPPFLAGS) -o $@ ../pcbnew/$*.cpp
......
......@@ -41,7 +41,7 @@ enum KICAD_T {
TYPESCREEN,
TYPEBLOCK,
TYPEEDGEZONE,
TYPEZONE_POLYEDGE,
TYPEZONE_EDGE_CORNER,
TYPEZONE_CONTAINER,
// Draw Items in schematic
......
......@@ -5,7 +5,7 @@
COMMON_GLOBL wxString g_BuildVersion
#ifdef EDA_BASE
(wxT("(2007-12-17)"))
(wxT("(2007-12-22)"))
#endif
;
......
......@@ -546,8 +546,21 @@ enum main_id {
ID_POPUP_PCB_DELETE_TRACK,
ID_POPUP_PCB_DELETE_TRACKNET,
ID_POPUP_PCB_DELETE_TRACK_MNU,
ID_POPUP_PCB_EDIT_ZONE,
ID_POPUP_PCB_EDIT_ZONE_PARAMS,
ID_POPUP_PCB_DELETE_ZONE,
ID_POPUP_PCB_MOVE_ZONE_CORNER,
ID_POPUP_PCB_ADD_ZONE_CORNER,
ID_POPUP_PCB_DELETE_ZONE_CORNER,
ID_POPUP_PCB_STOP_CURRENT_EDGE_ZONE,
ID_POPUP_PCB_DELETE_EDGE_ZONE,
ID_POPUP_PCB_DELETE_ZONE_LIMIT,
ID_POPUP_PCB_FILL_ZONE,
ID_POPUP_PCB_DELETE_ZONE_CONTAINER,
ID_POPUP_PCB_PLACE_ZONE_CORNER,
ID_POPUP_ZONE_UNUSED2,
ID_POPUP_ZONE_UNUSED3,
ID_POPUP_ZONE_UNUSED4,
ID_POPUP_PCB_DELETE_MARKER,
ID_POPUP_PCB_DELETE_COTATION,
......@@ -565,12 +578,6 @@ enum main_id {
ID_POPUP_PCB_IMPORT_PAD_SETTINGS,
ID_POPUP_PCB_EXPORT_PAD_SETTINGS,
ID_POPUP_PCB_STOP_CURRENT_EDGE_ZONE,
ID_POPUP_PCB_DELETE_EDGE_ZONE,
ID_POPUP_PCB_DELETE_ZONE_LIMIT,
ID_POPUP_PCB_FILL_ZONE,
ID_POPUP_PCB_SELECT_NET_ZONE,
ID_POPUP_PCB_SELECT_WIDTH,
ID_POPUP_PCB_SELECT_WIDTH1,
ID_POPUP_PCB_SELECT_WIDTH2,
......
......@@ -102,6 +102,7 @@ class Ki_HotkeyInfo;
class GENERAL_COLLECTOR;
class GENERAL_COLLECTORS_GUIDE;
class DRC;
class ZONE_CONTAINER;
enum id_librarytype {
......@@ -728,10 +729,8 @@ public:
TRACK* Delete_Segment( wxDC* DC, TRACK* Track );
void Delete_Track( wxDC* DC, TRACK* Track );
void Delete_net( wxDC* DC, TRACK* Track );
void Delete_Zone( wxDC* DC, SEGZONE* Track );
void Supprime_Une_Piste( wxDC* DC, TRACK* pt_segm );
bool Resize_Pistes_Vias( wxDC* DC, bool Track, bool Via );
void Edit_Zone_Width( wxDC* DC, SEGZONE* pt_ref );
void Edit_Net_Width( wxDC* DC, int Netcode );
void Edit_Track_Width( wxDC* DC, TRACK* Track );
int Edit_TrackSegm_Width( wxDC* DC, TRACK* segm );
......@@ -749,8 +748,13 @@ public:
bool Genere_Pad_Connexion( wxDC* DC, int layer );
// zone handling
void Delete_Zone( wxDC* DC, SEGZONE* Track );
EDGE_ZONE* Del_SegmEdgeZone( wxDC* DC, EDGE_ZONE* edge_zone );
void CaptureNetName( wxDC* DC );
/**
* Function Begin_Zone
* initiates a zone edge creation process,
* or terminates the current zone edge and creates a new zone edge stub
*/
EDGE_ZONE* Begin_Zone( wxDC* DC );
/**
......@@ -761,14 +765,30 @@ public:
/**
* Function Fill_Zone
* creates a number zone segments by using a flood fill algorithm. The
* "high-lighted" net is used to determine the netcode of all the zone
* segments and what can be connected to and what must be avoided on the
* current layer as the flooding occurs.
* Fills an outline.
*/
void Fill_Zone( wxDC* DC );
// Target handling
void Fill_Zone( wxDC* DC, ZONE_CONTAINER * zone_container );
/**
* Function Edit_Zone_Params
* Edit params (layer, clearance, ...) for a zone outline
*/
void Edit_Zone_Params( wxDC* DC , ZONE_CONTAINER * zone_container );
/**
* Function Start_Move_Zone_Corner
* Prepares a move corner in a zone outline,
* called from a move corner command (IsNewCorner = false),
* or a create new cornet command (IsNewCorner = true )
*/
void Start_Move_Zone_Corner( wxDC* DC , ZONE_CONTAINER * zone_container, int corner_id, bool IsNewCorner );
/**
* Function End_Move_Zone_Corner
* Terminates a move corner in a zone outline
*/
void End_Move_Zone_Corner( wxDC* DC , ZONE_CONTAINER * zone_container );
// Target handling
MIREPCB* Create_Mire( wxDC* DC );
void Delete_Mire( MIREPCB* MirePcb, wxDC* DC );
void StartMove_Mire( MIREPCB* MirePcb, wxDC* DC );
......
KICAD_SUBDIRS = common 3d-viewer eeschema eeschema/plugins pcbnew kicad cvpcb gerbview
KICAD_SUBDIRS = common 3d-viewer polygon eeschema eeschema/plugins pcbnew kicad cvpcb gerbview
KICAD_SUBDIRS_BIN = eeschema eeschema/plugins pcbnew cvpcb kicad gerbview
# How to invoke make:
MAKE = make -k -f makefile.g95
......
MAKEGTK = $(MAKE) -f makefile.gtk
KICAD_SUBDIRS = common 3d-viewer pcbnew eeschema eeschema/plugins cvpcb kicad gerbview
KICAD_SUBDIRS = common 3d-viewer polygon pcbnew eeschema eeschema/plugins cvpcb kicad gerbview
KICAD_SUBDIRS_BIN = eeschema eeschema/plugins pcbnew cvpcb kicad gerbview
KICAD_SUBDIRS_RES = internat modules template library
KICAD_SUBDIRS_HELP = help
......
KICAD_SUBDIRS = common 3d-viewer eeschema pcbnew cvpcb kicad gerbview
KICAD_SUBDIRS = common 3d-viewer polygon eeschema pcbnew cvpcb kicad gerbview
KICAD_SUBDIRS_BIN = eeschema pcbnew cvpcb kicad gerbview
# How to invoke make:
MAKE = make -f makefile.macosx
......
......@@ -6,8 +6,6 @@
#include "pcbnew.h"
//#include "bitmaps.h"
/*****************/
/* Class BOARD: */
......@@ -76,6 +74,7 @@ BOARD::~BOARD()
m_LocalRatsnest = 0;
DeleteMARKERs();
DeleteZONEOutlines();
}
......@@ -128,11 +127,11 @@ void BOARD::Add( BOARD_ITEM* aBoardItem, int aControl )
void BOARD::Delete( BOARD_ITEM* aBoardItem )
{
if ( aBoardItem == NULL ) return;
switch( aBoardItem->Type() )
{
// this one uses a vector
case TYPEMARKER:
case TYPEMARKER: // this one uses a vector
// find the item in the vector, then delete then erase it.
for( unsigned i=0; i<m_markers.size(); ++i )
{
......@@ -143,6 +142,19 @@ void BOARD::Delete( BOARD_ITEM* aBoardItem )
}
}
break;
case TYPEZONE_CONTAINER: // this one uses a vector
// find the item in the vector, then delete then erase it.
for( unsigned i=0; i<m_ZoneDescriptorList.size(); ++i )
{
if( m_ZoneDescriptorList[i] == (ZONE_CONTAINER*) aBoardItem )
{
delete m_ZoneDescriptorList[i];
m_ZoneDescriptorList.erase(m_ZoneDescriptorList.begin() + i);
break;
}
}
break;
// other types may use linked list
default:
......@@ -170,6 +182,15 @@ void BOARD::DeleteMARKERs()
m_markers.clear();
}
void BOARD::DeleteZONEOutlines()
{
// the vector does not know how to delete the ZONE Outlines, it holds pointers
for( unsigned i=0; i<m_ZoneDescriptorList.size(); ++i )
delete m_ZoneDescriptorList[i];
m_ZoneDescriptorList.clear();
}
/* Calculate the track segment count */
int BOARD::GetNumSegmTrack()
......@@ -522,6 +543,17 @@ SEARCH_RESULT BOARD::Visit( INSPECTOR* inspector, const void* testData,
++p;
break;
case TYPEZONE_CONTAINER:
// TYPEZONE_CONTAINER are in the m_ZoneDescriptorList std::vector
for( unsigned i=0; i< m_ZoneDescriptorList.size(); ++i )
{
result = m_ZoneDescriptorList[i]->Visit( inspector, testData, p );
if( result == SEARCH_QUIT )
break;
}
++p;
break;
case PCB_EQUIPOT_STRUCT_TYPE:
result = IterateForward( m_Equipots, inspector, testData, p );
++p;
......@@ -782,16 +814,12 @@ bool BOARD::Save( FILE* aFile ) const
fprintf( aFile, "$EndZONE\n" );
// save the zone edges
/*
if( m_CurrentLimitZone )
{
fprintf( aFile, "$ZONE_EDGE\n" );
for( item = m_CurrentLimitZone; item; item=item->Next() )
if( !item->Save( aFile ) )
goto out;
fprintf( aFile, "$EndZONE_EDGE\n" );
}
*/
for( unsigned ii = 0; ii < m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_ZoneDescriptorList[ii];
edge_zone->Save( aFile );
}
if( fprintf( aFile, "$EndBOARD\n" ) != sizeof("$EndBOARD\n")-1 )
goto out;
......
......@@ -20,7 +20,6 @@ class BOARD : public BOARD_ITEM
private:
std::vector<MARKER*> m_markers; ///< MARKERs for clearance problems, owned by pointer
// std::vector<MARKER*> m_markersUnconnected; ///< MARKERs for unconnected problems, owned by pointer
std::vector<ZONE_CONTAINER*> m_ZoneDescriptorList; ///< edge zone descriptors, owned by pointer
......@@ -86,6 +85,12 @@ public:
*/
void DeleteMARKERs();
/**
* Function DeleteZONEOutlines
* deletes ALL zone outlines from the board.
*/
void DeleteZONEOutlines();
/**
* Function DeleteMARKER
......
......@@ -149,8 +149,25 @@ wxString BOARD_ITEM::MenuText( const BOARD* aPcb ) const
}
break;
case TYPEZONE:
text << _( "Zone" ) << wxT( " " );
case TYPEZONE_CONTAINER:
text = _( "Zone Outline" );
text << wxT( " " );
{
wxString TimeStampText;
TimeStampText.Printf( wxT( "(%8.8X)" ), item->m_TimeStamp );
text << TimeStampText;
}
net = aPcb->FindNet( ( (ZONE_CONTAINER*) item )->GetNet() );
if( net )
{
text << wxT( " [" ) << net->m_Netname << wxT( "]" );
}
text << _( " on " ) << ReturnPcbLayerName( item->GetLayer() ).Trim();
break;
case TYPEZONE:
text = _( "Zone" );
text << wxT( " " );
{
wxString TimeStampText;
TimeStampText.Printf( wxT( "(%8.8X)" ), item->m_TimeStamp );
......@@ -268,6 +285,7 @@ const char** BOARD_ITEM::MenuIcon() const
xpm = showtrack_xpm;
break;
case TYPEZONE_CONTAINER:
case TYPEZONE:
xpm = add_zone_xpm;
break;
......
......@@ -44,6 +44,7 @@ EQUIPOT::~EQUIPOT()
}
wxPoint& EQUIPOT::GetPosition()
{
static wxPoint dummy;
......@@ -172,3 +173,5 @@ void EQUIPOT::Show( int nestLevel, std::ostream& os )
" netcode=\"" << GetNet() << "\"/>\n";
}
#endif
......@@ -61,7 +61,7 @@ public:
*/
int GetNet() const { return m_NetCode; }
void SetNet( int aNetCode ) { m_NetCode = aNetCode; }
/**
* Function GetClass
......@@ -86,3 +86,4 @@ public:
#endif
};
......@@ -93,27 +93,9 @@ bool MIREPCB::ReadMirePcbDescr( FILE* File, int* LineNum )
return FALSE;
}
#if 0 // replaced by Save()
/************************************************/
bool MIREPCB::WriteMirePcbDescr( FILE* File )
/************************************************/
{
if( GetState( DELETED ) )
return FALSE;
fprintf( File, "$MIREPCB\n" );
fprintf( File, "Po %X %d %d %d %d %d %8.8lX\n",
m_Shape, m_Layer,
m_Pos.x, m_Pos.y,
m_Size, m_Width, m_TimeStamp );
fprintf( File, "$EndMIREPCB\n" );
return TRUE;
}
#endif
/**************************************/
bool MIREPCB::Save( FILE* aFile ) const
/**************************************/
{
if( GetState( DELETED ) )
return true;
......
......@@ -14,10 +14,13 @@
/* class ZONE_CONTAINER */
/************************/
ZONE_CONTAINER::ZONE_CONTAINER (BOARD * parent):
BOARD_ITEM (parent, TYPEZONE_CONTAINER)
ZONE_CONTAINER::ZONE_CONTAINER( BOARD* parent ) :
BOARD_ITEM( parent, TYPEZONE_CONTAINER )
, CPolyLine( NULL )
{
m_NetCode = -1; // Net number for fast comparisons
m_CornerSelection = -1;
}
......@@ -25,11 +28,6 @@ ZONE_CONTAINER::~ZONE_CONTAINER()
{
}
bool ZONE_CONTAINER::Save( FILE* aFile ) const
{
return true;
}
/**********************/
/* Class EDGE_ZONE */
......@@ -49,19 +47,367 @@ EDGE_ZONE:: ~EDGE_ZONE()
}
/****************************************/
bool EDGE_ZONE::Save( FILE* aFile ) const
/****************************************/
{
return true;
}
/********************************************/
bool ZONE_CONTAINER::Save( FILE* aFile ) const
/********************************************/
{
if( GetState( DELETED ) )
return true;
int ret = fprintf( aFile, "ZE %d %d %d %d %d %lX %X\n",
m_Start.x, m_Start.y,
m_End.x, m_End.y,
m_Angle,
m_TimeStamp,
ReturnStatus()
);
return (ret > 14 );
unsigned item_pos;
int ret;
unsigned corners_count = corner.size();
int outline_hatch;
fprintf( aFile, "$CZONE_OUTLINE\n");
// Save the outline main info
ret = fprintf( aFile, "ZInfo %8.8lX %d \"%s\"\n",
m_TimeStamp, m_NetCode,
CONV_TO_UTF8(m_Netname) );
if ( ret < 3 ) return false;
// Save the ouline layer info
ret = fprintf( aFile, "ZLayer %d\n", m_Layer );
if ( ret < 1 ) return false;
// Save the ouline aux info
switch ( m_HatchStyle )
{
default:
case NO_HATCH:
outline_hatch = 'N';
break;
case DIAGONAL_EDGE:
outline_hatch = 'E';
break;
case DIAGONAL_FULL:
outline_hatch = 'F';
break;
}
ret = fprintf( aFile, "ZAux %d %c\n", corners_count, outline_hatch );
if ( ret < 2 ) return false;
// Save the corner list
for ( item_pos = 0; item_pos < corners_count; item_pos++ )
{
ret = fprintf( aFile, "ZCorner %d %d %d \n",
corner[item_pos].x, corner[item_pos].y,
corner[item_pos].end_contour );
if ( ret < 3 ) return false;
}
fprintf( aFile, "$endCZONE_OUTLINE\n");
return true;
}
/**********************************************************/
int ZONE_CONTAINER::ReadDescr( FILE* aFile, int* aLineNum )
/**********************************************************/
/** Function ReadDescr
* @param aFile = opened file
* @param aLineNum = pointer on a line number counter (can be NULL or missing)
* @return 0 if ok or NULL
*/
{
char Line[1024], * text;
char netname_buffer[1024];
int ret;
int n_corner_item = 0;
int outline_hatch = NO_HATCH;
bool error = false, has_corner = false;
netname_buffer[0] = 0;
while( GetLine( aFile, Line, aLineNum, sizeof(Line) - 1 ) != NULL )
{
if( strnicmp(Line, "ZCorner", 7 ) == 0 ) // new corner found
{
int x = 0, y = 0, flag = 0;
text = Line + 7;
ret = sscanf( text, "%d %d %d", &x, &y, &flag);
if (ret < 3 ) error = true;
else
{
if ( ! has_corner )
Start( m_Layer, 0, 0,
x, y,
outline_hatch );
else
AppendCorner( x, y );
has_corner = true;
if ( flag ) Close();
}
}
if( strnicmp(Line, "ZInfo", 5 ) == 0 ) // general info found
{
int ts = 0, netcode = 0;
text = Line + 5;
ret = sscanf( text, "%X %d %s", &ts, &netcode, netname_buffer);
if (ret < 3 ) error = true;
else
{
m_TimeStamp = ts;
m_NetCode = netcode;
ReadDelimitedText( netname_buffer, netname_buffer, 1024 );
m_Netname = CONV_FROM_UTF8(netname_buffer);
}
}
if( strnicmp(Line, "ZLayer", 6 ) == 0 ) // layer found
{
int x = 0;
text = Line + 6;
ret = sscanf( text, "%d", &x);
if (ret < 1 ) error = true;
else m_Layer = x;
}
if( strnicmp(Line, "ZAux", 4 ) == 0 ) // aux info found
{
int x = 0;
char hopt[10];
text = Line + 4;
ret = sscanf( text, "%d %c", &x, hopt );
if (ret < 2 ) error = true;
else
{
n_corner_item = x;
switch ( hopt[0] )
{
case 'n':
case 'N':
outline_hatch = NO_HATCH;
break;
case 'e':
case 'E':
outline_hatch = DIAGONAL_EDGE;
break;
case 'f':
case 'F':
outline_hatch = DIAGONAL_FULL;
break;
}
}
}
if( strnicmp(Line, "$end", 4 ) == 0 ) // end of description
{
break;
}
}
return error ? 0 : 1;
}
/****************************************************************************************************/
void ZONE_CONTAINER::Draw( WinEDA_DrawPanel* panel, wxDC* DC, const wxPoint& offset, int draw_mode )
/****************************************************************************************************/
/** Function Draw
* @param panel = current Draw Panel
* @param DC = current Device Context
* @param offset = Draw offset (usually wxPoint(0,0))
* @param draw_mode = draw mode: OR, XOR ..
*/
{
int curr_layer = ( (PCB_SCREEN*) panel->GetScreen() )->m_Active_Layer;
int color = g_DesignSettings.m_LayerColor[m_Layer];
if( ( color & (ITEM_NOT_SHOW | HIGHT_LIGHT_FLAG) ) == ITEM_NOT_SHOW )
return;
GRSetDrawMode( DC, draw_mode );
if( DisplayOpt.ContrastModeDisplay )
{
if( !IsOnLayer( curr_layer ) )
{
color &= ~MASKCOLOR;
color |= DARKDARKGRAY;
}
}
if( draw_mode & GR_SURBRILL )
{
if( draw_mode & GR_AND )
color &= ~HIGHT_LIGHT_FLAG;
else
color |= HIGHT_LIGHT_FLAG;
}
if( color & HIGHT_LIGHT_FLAG )
color = ColorRefs[color & MASKCOLOR].m_LightColor;
// draw the lines
int i_start_contour = 0;
for( unsigned ic = 0; ic < corner.size(); ic++ )
{
int xi = corner[ic].x + offset.x;
int yi = corner[ic].y + offset.y;
int xf, yf;
if( corner[ic].end_contour == FALSE && ic < corner.size() - 1 )
{
xf = corner[ic + 1].x + offset.x;
yf = corner[ic + 1].y + offset.y;
}
else
{
xf = corner[i_start_contour].x + offset.x;
yf = corner[i_start_contour].y + offset.y;
i_start_contour = ic + 1;
}
GRLine( &panel->m_ClipBox, DC, xi, yi, xf, yf, 0, color );
}
// draw hatches
for( unsigned ic = 0; ic < m_HatchLines.size(); ic++ )
{
int xi = m_HatchLines[ic].xi + offset.x;
int yi = m_HatchLines[ic].yi + offset.y;
int xf = m_HatchLines[ic].xf + offset.x;
int yf =m_HatchLines[ic].yf + offset.y;
GRLine( &panel->m_ClipBox, DC, xi, yi, xf, yf, 0, color );
}
}
/**
* Function HitTest
* tests if the given wxPoint is within the bounds of this object.
* @param refPos A wxPoint to test
* @return bool - true if a hit, else false
* return true if refPos is near a corner or an edge
*/
bool ZONE_CONTAINER::HitTest( const wxPoint& refPos )
{
if( HitTestForCorner( refPos ) >= 0 )
return true;
if( HitTestForEdge( refPos ) >= 0 )
return true;
return false;
}
/**
* Function HitTestForCorner
* tests if the given wxPoint near a corner, or near the segment define by 2 corners.
* "near" means MIN_DIST_IN_PIXELS pixels
* @return -1 if none, corner index in .corner <vector>
* @param refPos : A wxPoint to test
*/
int ZONE_CONTAINER::HitTestForCorner( const wxPoint& refPos )
{
#define MIN_DIST_IN_PIXELS 5
int dist;
unsigned item_pos, lim;
lim = corner.size();
// Min distance to hit = MIN_DIST_IN_PIXELS pixels :
WinEDA_BasePcbFrame* frame = ((BOARD*)GetParent())->m_PcbFrame;
int min_dist = frame ? frame->GetZoom() * MIN_DIST_IN_PIXELS : 3;
for ( item_pos = 0; item_pos < lim; item_pos++ )
{
dist = abs( corner[item_pos].x - refPos.x ) + abs( corner[item_pos].y - refPos.y );
if( dist <= min_dist )
return item_pos;
}
return -1;
}
/**
* Function HitTestForEdge
* tests if the given wxPoint near a corner, or near the segment define by 2 corners.
* "near" means MIN_DIST_IN_PIXELS pixels
* @return -1 if none, or index of the starting corner in .corner <vector>
* @param refPos : A wxPoint to test
*/
int ZONE_CONTAINER::HitTestForEdge( const wxPoint& refPos )
{
#define MIN_DIST_IN_PIXELS 5
int dist;
unsigned item_pos, lim;
lim = corner.size();
// Min distance to hit = MIN_DIST_IN_PIXELS pixels :
WinEDA_BasePcbFrame* frame = ((BOARD*)GetParent())->m_PcbFrame;
int min_dist = frame ? frame->GetZoom() * MIN_DIST_IN_PIXELS : 3;
/* Test for an entire segment */
unsigned first_corner_pos = 0, end_segm;
for ( item_pos = 0; item_pos < lim; item_pos++ )
{
end_segm = item_pos+1;
/* the last corner of the current outline is tested
* the last segment of the current outline starts at current corner, and ends
* at the first corner of the outline
*/
if( corner[item_pos].end_contour || end_segm >= lim)
{
unsigned tmp = first_corner_pos;
first_corner_pos = end_segm; // first_corner_pos is now the beginning of the next outline
end_segm = tmp; // end_segm is the beginning of the current outline
}
/* test the dist between segment and ref point */
dist = (int) GetPointToLineSegmentDistance( refPos.x,
refPos.y,
corner[item_pos].x,
corner[item_pos].y,
corner[end_segm].x,
corner[end_segm].y );
if( dist <= min_dist )
return item_pos;
}
return -1;
}
/************************************************************/
void ZONE_CONTAINER::Display_Infos( WinEDA_DrawFrame* frame )
/************************************************************/
{
wxString msg;
int text_pos;
frame->MsgPanel->EraseMsgBox();
msg = _( "Zone Outline" );
text_pos = 1;
Affiche_1_Parametre( frame, text_pos, _( "Type" ), msg, DARKCYAN );
text_pos += 15;
EQUIPOT* equipot = ( (WinEDA_PcbFrame*) frame )->m_Pcb->FindNet( GetNet() );
if( equipot )
msg = equipot->m_Netname;
else
msg = wxT( "<noname>" );
Affiche_1_Parametre( frame, text_pos, _( "NetName" ), msg, RED );
/* Display net code : (usefull in test or debug) */
text_pos += 18;
msg.Printf( wxT( "%d" ), GetNet());
Affiche_1_Parametre( frame, text_pos, _( "NetCode" ), msg, RED );
text_pos += 8;
msg = ReturnPcbLayerName( m_Layer );
Affiche_1_Parametre( frame, text_pos, _( "Layer" ), msg, BROWN );
text_pos += 8;
msg.Printf( wxT( "%d" ), corner.size() );
Affiche_1_Parametre( frame, text_pos, _( "Corners" ), msg, BLUE );
text_pos += 8;
msg.Printf( wxT( "%d" ), m_HatchLines.size() );
Affiche_1_Parametre( frame, text_pos, _( "Hatch lines" ), msg, BLUE );
}
......@@ -5,6 +5,8 @@
#ifndef CLASS_ZONE_H
#define CLASS_ZONE_H
#include "PolyLine.h"
/************************/
/* class ZONE_CONTAINER */
/************************/
......@@ -13,10 +15,11 @@
* others polygons inside this main polygon are holes.
*/
class ZONE_CONTAINER : public BOARD_ITEM // Not sure BOARD_ITEM is better than EDA_BaseStruct
class ZONE_CONTAINER : public BOARD_ITEM, public CPolyLine
{
public:
wxString m_Netname; /* Net Name */
int m_CornerSelection; // For corner moving, corner index to drag, or -1 if no selection
private:
int m_NetCode; // Net number for fast comparisons
......@@ -26,7 +29,47 @@ public:
~ZONE_CONTAINER();
bool Save( FILE* aFile ) const;
int ReadDescr( FILE* aFile, int* aLineNum = NULL );
wxPoint & GetPosition( ) { static wxPoint pos ;return pos; }
void UnLink(void) {};
void Display_Infos( WinEDA_DrawFrame* frame );
/** Function Draw
* Draws the zone outline.
* @param panel = current Draw Panel
* @param DC = current Device Context
* @param offset = Draw offset (usually wxPoint(0,0))
* @param draw_mode = draw mode: OR, XOR ..
*/
void Draw( WinEDA_DrawPanel* panel, wxDC* DC,
const wxPoint& offset, int draw_mode );
int GetNet( void ) { return m_NetCode; }
void SetNet( int anet_code ) { m_NetCode = anet_code; }
/**
* Function HitTest
* tests if the given wxPoint is within the bounds of this object.
* @param refPos A wxPoint to test
* @return bool - true if a hit, else false
*/
bool HitTest( const wxPoint& refPos );
/**
* Function HitTestForCorner
* tests if the given wxPoint near a corner, or near the segment define by 2 corners.
* @return -1 if none, corner index in .corner <vector>
* @param refPos : A wxPoint to test
*/
int HitTestForCorner( const wxPoint& refPos );
/**
* Function HitTestForEdge
* tests if the given wxPoint near a corner, or near the segment define by 2 corners.
* @return -1 if none, or index of the starting corner in .corner <vector>
* @param refPos : A wxPoint to test
*/
int HitTestForEdge( const wxPoint& refPos );
};
/*******************/
......
......@@ -47,6 +47,7 @@ const KICAD_T GENERAL_COLLECTOR::AllBoardItems[] = {
TYPETEXTEMODULE,
TYPEMODULE,
TYPEZONE,
TYPEZONE_CONTAINER,
EOT
};
......@@ -212,6 +213,8 @@ SEARCH_RESULT GENERAL_COLLECTOR::Inspect( EDA_BaseStruct* testItem, const void*
break;
case TYPEZONE:
break;
case TYPEZONE_CONTAINER:
break;
case TYPETEXTE:
break;
case TYPEDRAWSEGMENT:
......
......@@ -68,6 +68,7 @@ WinEDA_ZoneFrame::WinEDA_ZoneFrame()
WinEDA_ZoneFrame::WinEDA_ZoneFrame( WinEDA_PcbFrame* parent,
ZONE_CONTAINER * zone_container,
wxWindowID id,
const wxString& caption,
const wxPoint& pos,
......@@ -75,6 +76,7 @@ WinEDA_ZoneFrame::WinEDA_ZoneFrame( WinEDA_PcbFrame* parent,
long style )
{
m_Parent = parent;
m_Zone_Container = zone_container;
if( m_Parent->m_Parent->m_EDA_Config )
{
......@@ -98,7 +100,6 @@ bool WinEDA_ZoneFrame::Create( wxWindow* parent,
long style )
{
////@begin WinEDA_ZoneFrame member initialisation
m_OutlinesOpt = 0;
m_GridCtrl = NULL;
m_ClearanceValueTitle = NULL;
m_ZoneClearanceCtrl = NULL;
......@@ -135,7 +136,7 @@ void WinEDA_ZoneFrame::CreateControls()
SetFont( *g_DialogFont );
////@begin WinEDA_ZoneFrame content construction
// Generated by DialogBlocks, 20/12/2007 15:46:22 (unregistered)
// Generated by DialogBlocks, 29/12/2007 14:29:53 (unregistered)
WinEDA_ZoneFrame* itemDialog1 = this;
......@@ -231,10 +232,11 @@ void WinEDA_ZoneFrame::CreateControls()
itemBoxSizer20->Add(m_LayerSelectionCtrl, 0, wxGROW|wxALL, 5);
// Set validators
m_OutlineAppearanceCtrl->SetValidator( wxGenericValidator(& m_OutlinesOpt) );
m_NetSortingOption->SetValidator( wxGenericValidator(& m_NetSorting) );
////@end WinEDA_ZoneFrame content construction
wxString title = _( "Zone clearance value:" ) + ReturnUnitSymbol( g_UnitMetric );
// Initialise options
wxString title = _( "Zone clearance value:" ) + ReturnUnitSymbol( g_UnitMetric );
m_ClearanceValueTitle->SetLabel( title );
title = _( "Grid :" ) + ReturnUnitSymbol( g_UnitMetric );;
......@@ -250,7 +252,7 @@ void WinEDA_ZoneFrame::CreateControls()
if( Zone_45_Only )
m_OrientEdgesOpt->SetSelection( 1 );
static const int GridList[4] = { 50, 100, 250 };
static const int GridList[3] = { 50, 100, 250 };
int selection = 0;
for( unsigned ii = 0; ii < (unsigned) m_GridCtrl->GetCount(); ii++ )
......@@ -263,7 +265,6 @@ void WinEDA_ZoneFrame::CreateControls()
selection = ii;
}
// Initialise options
m_GridCtrl->SetSelection( selection );
if( Zone_Exclude_Pads )
......@@ -274,6 +275,21 @@ void WinEDA_ZoneFrame::CreateControls()
m_FillOpt->SetSelection( 2 );
}
switch( s_Zone_Hatching )
{
case CPolyLine::NO_HATCH:
m_OutlineAppearanceCtrl->SetSelection(0);
break;
case CPolyLine::DIAGONAL_EDGE:
m_OutlineAppearanceCtrl->SetSelection(1);
break;
case CPolyLine::DIAGONAL_FULL:
m_OutlineAppearanceCtrl->SetSelection(2);
break;
}
m_NetSortingOption->SetSelection(m_NetSorting == 0 ? 0 : 1 );
int layer_cnt = g_DesignSettings.m_CopperLayerCount;
......@@ -288,8 +304,12 @@ void WinEDA_ZoneFrame::CreateControls()
m_LayerId[ii] = layer_number;
msg = ReturnPcbLayerName( layer_number ).Trim();
m_LayerSelectionCtrl->InsertItems( 1, &msg, ii );
if( m_Parent->GetScreen()->m_Active_Layer == layer_number )
m_LayerSelectionCtrl->SetSelection( ii );
if ( m_Zone_Container )
if( m_Zone_Container->GetLayer() == layer_number )
m_LayerSelectionCtrl->SetSelection( ii );
else
if( m_Parent->GetScreen()->m_Active_Layer == layer_number )
m_LayerSelectionCtrl->SetSelection( ii );
}
wxArrayString ListNetName;
......@@ -298,9 +318,12 @@ void WinEDA_ZoneFrame::CreateControls()
m_ListNetNameSelection->InsertItems( ListNetName, 0 );
// Select net:
if( g_HightLigth_NetCode > 0 )
int net_select = g_HightLigth_NetCode;
if ( m_Zone_Container )
net_select = m_Zone_Container->GetNet();
if( net_select > 0 )
{
EQUIPOT* equipot = m_Parent->m_Pcb->FindNet( g_HightLigth_NetCode );
EQUIPOT* equipot = m_Parent->m_Pcb->FindNet( net_select );
if( equipot ) // Search net in list and select it
{
for( unsigned ii = 0; ii < ListNetName.GetCount(); ii++ )
......@@ -389,6 +412,21 @@ bool WinEDA_ZoneFrame::AcceptOptions(bool aPromptForErrors)
break;
}
switch( m_OutlineAppearanceCtrl->GetSelection() )
{
case 0:
s_Zone_Hatching = CPolyLine::NO_HATCH;
break;
case 1:
s_Zone_Hatching = CPolyLine::DIAGONAL_EDGE;
break;
case 2:
s_Zone_Hatching = CPolyLine::DIAGONAL_FULL;
break;
}
switch( m_GridCtrl->GetSelection() )
{
case 0:
......
......@@ -75,7 +75,13 @@ class WinEDA_ZoneFrame: public wxDialog
public:
/// Constructors
WinEDA_ZoneFrame( );
WinEDA_ZoneFrame( WinEDA_PcbFrame* parent, wxWindowID id = SYMBOL_WINEDA_ZONEFRAME_IDNAME, const wxString& caption = SYMBOL_WINEDA_ZONEFRAME_TITLE, const wxPoint& pos = SYMBOL_WINEDA_ZONEFRAME_POSITION, const wxSize& size = SYMBOL_WINEDA_ZONEFRAME_SIZE, long style = SYMBOL_WINEDA_ZONEFRAME_STYLE );
WinEDA_ZoneFrame( WinEDA_PcbFrame* parent,
ZONE_CONTAINER * zone_container = NULL,
wxWindowID id = SYMBOL_WINEDA_ZONEFRAME_IDNAME,
const wxString& caption = SYMBOL_WINEDA_ZONEFRAME_TITLE,
const wxPoint& pos = SYMBOL_WINEDA_ZONEFRAME_POSITION,
const wxSize& size = SYMBOL_WINEDA_ZONEFRAME_SIZE,
long style = SYMBOL_WINEDA_ZONEFRAME_STYLE );
/// Creation
bool Create( wxWindow* parent, wxWindowID id = SYMBOL_WINEDA_ZONEFRAME_IDNAME, const wxString& caption = SYMBOL_WINEDA_ZONEFRAME_TITLE, const wxPoint& pos = SYMBOL_WINEDA_ZONEFRAME_POSITION, const wxSize& size = SYMBOL_WINEDA_ZONEFRAME_SIZE, long style = SYMBOL_WINEDA_ZONEFRAME_STYLE );
......@@ -98,9 +104,6 @@ public:
////@begin WinEDA_ZoneFrame member function declarations
int GetOutlinesOpt() const { return m_OutlinesOpt ; }
void SetOutlinesOpt(int value) { m_OutlinesOpt = value ; }
/// Retrieves bitmap resources
wxBitmap GetBitmapResource( const wxString& name );
......@@ -125,13 +128,13 @@ public:
wxRadioBox* m_NetSortingOption;
wxListBox* m_ListNetNameSelection;
wxListBox* m_LayerSelectionCtrl;
int m_OutlinesOpt;
////@end WinEDA_ZoneFrame member variables
WinEDA_PcbFrame * m_Parent;
int m_NetSorting;
int m_LayerId[LAYER_COUNT]; // Handle the real layer number from layer name position in m_LayerSelectionCtrl
ZONE_CONTAINER * m_Zone_Container;
};
#endif // DIALOG_ZONES_H_
......
......@@ -218,7 +218,6 @@
<string name="id-suffix">""</string>
<long name="use-xrc">0</long>
<long name="working-mode">0</long>
<string name="variable-0">"m_OutlinesOpt|int|OutlinesOpt|0|0|0|"</string>
<string name="proxy-Id name">"ID_DIALOG"</string>
<long name="proxy-Id value">10000</long>
<string name="proxy-Class">"WinEDA_ZoneFrame"</string>
......@@ -595,8 +594,8 @@
<bool name="proxy-Hidden">0</bool>
<bool name="proxy-Enabled">1</bool>
<string name="proxy-Platform">"&lt;Any platform&gt;"</string>
<string name="proxy-Data variable">"m_OutlinesOpt"</string>
<string name="proxy-Data validator">"wxGenericValidator(&amp; %VARIABLE%)"</string>
<string name="proxy-Data variable">""</string>
<string name="proxy-Data validator">""</string>
<string name="proxy-Data source">""</string>
<string name="proxy-Data class name">""</string>
<string name="proxy-Data class implementation filename">""</string>
......
......@@ -67,13 +67,13 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event )
case ID_POPUP_PCB_STOP_CURRENT_EDGE_ZONE:
case ID_POPUP_PCB_DELETE_EDGE_ZONE:
case ID_POPUP_PCB_DELETE_ZONE_LIMIT:
case ID_POPUP_PCB_EDIT_ZONE:
case ID_POPUP_PCB_PLACE_ZONE_CORNER:
case ID_POPUP_PCB_EDIT_ZONE_PARAMS:
case ID_POPUP_PCB_DELETE_ZONE:
case ID_POPUP_PCB_DELETE_TRACKSEG:
case ID_POPUP_PCB_DELETE_TRACK:
case ID_POPUP_PCB_DELETE_TRACKNET:
case ID_POPUP_PCB_FILL_ZONE:
case ID_POPUP_PCB_SELECT_NET_ZONE:
case ID_POPUP_PCB_SELECT_LAYER:
case ID_POPUP_PCB_SELECT_CU_LAYER:
case ID_POPUP_PCB_SELECT_LAYER_PAIR:
......@@ -445,18 +445,71 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event )
SetCurItem( NULL );
break;
case ID_POPUP_PCB_EDIT_ZONE:
case ID_POPUP_PCB_EDIT_ZONE_PARAMS:
Edit_Zone_Params( &dc, (ZONE_CONTAINER*) GetCurItem() );
break;
case ID_POPUP_PCB_DELETE_ZONE_CONTAINER:
DrawPanel->MouseToCursorSchema();
if( GetCurItem() == NULL )
break;
Edit_Zone_Width( &dc, (SEGZONE*) GetCurItem() );
((ZONE_CONTAINER*)GetCurItem())->Draw(DrawPanel,&dc, wxPoint(0,0), GR_XOR);
m_Pcb->Delete( GetCurItem() );
SetCurItem( NULL );
break;
case ID_POPUP_PCB_DELETE_ZONE_CORNER:
{
DrawPanel->MouseToCursorSchema();
ZONE_CONTAINER * zone_cont = (ZONE_CONTAINER*)GetCurItem();
zone_cont->Draw(DrawPanel,&dc, wxPoint(0,0), GR_XOR);
zone_cont->DeleteCorner(zone_cont->m_CornerSelection);
zone_cont->Draw(DrawPanel,&dc, wxPoint(0,0), GR_XOR);
SetCurItem( NULL );
break;
}
case ID_POPUP_PCB_MOVE_ZONE_CORNER:
{
DrawPanel->MouseToCursorSchema();
ZONE_CONTAINER * zone_cont = (ZONE_CONTAINER*)GetCurItem();
Start_Move_Zone_Corner(&dc, zone_cont, zone_cont->m_CornerSelection, false);
break;
}
case ID_POPUP_PCB_ADD_ZONE_CORNER:
{
DrawPanel->MouseToCursorSchema();
ZONE_CONTAINER * zone_cont = (ZONE_CONTAINER*)GetCurItem();
wxPoint pos = GetScreen()->m_Curseur;
/* add corner between zone_cont->m_CornerSelection
* and zone_cont->m_CornerSelection+1
* and start move the new corner
*/
zone_cont->Draw(DrawPanel, &dc, wxPoint(0,0), GR_XOR);
zone_cont->InsertCorner( zone_cont->m_CornerSelection, pos.x, pos.y );
zone_cont->m_CornerSelection++;
zone_cont->Draw(DrawPanel, &dc, wxPoint(0,0), GR_XOR);
Start_Move_Zone_Corner(&dc, zone_cont, zone_cont->m_CornerSelection, true);
break;
}
case ID_POPUP_PCB_PLACE_ZONE_CORNER:
{
DrawPanel->MouseToCursorSchema();
ZONE_CONTAINER * zone_cont = (ZONE_CONTAINER*)GetCurItem();
End_Move_Zone_Corner(&dc, zone_cont);
break;
}
case ID_POPUP_PCB_DELETE_ZONE_LIMIT:
DrawPanel->MouseToCursorSchema();
DelLimitesZone( &dc, TRUE );
break;
case ID_POPUP_PCB_FILL_ZONE:
DrawPanel->MouseToCursorSchema();
Fill_Zone( &dc, (ZONE_CONTAINER*)GetCurItem() );
break;
case ID_PCB_DELETE_ITEM_BUTT:
SetToolID( id, wxCURSOR_BULLSEYE, _( "Delete item" ) );
break;
......@@ -745,16 +798,6 @@ void WinEDA_PcbFrame::Process_Special_Functions( wxCommandEvent& event )
}
break;
case ID_POPUP_PCB_FILL_ZONE:
DrawPanel->MouseToCursorSchema();
Fill_Zone( &dc );
break;
case ID_POPUP_PCB_SELECT_NET_ZONE:
DrawPanel->MouseToCursorSchema();
CaptureNetName( &dc );
break;
case ID_POPUP_PCB_SELECT_WIDTH:
break;
......
/**********************************************/
/* PCBNEW : Routines d'initialisation globale */
/******* Fichier INITPCB.C ********************/
/**********************************************/
/*********************************************/
/******* file initpcb.cpp ********************/
/*********************************************/
#include "fctsys.h"
......@@ -148,6 +147,9 @@ bool WinEDA_BasePcbFrame::Clear_Pcb( bool query )
DelLimitesZone( NULL, FALSE );
m_Pcb->DeleteMARKERs();
m_Pcb->DeleteZONEOutlines();
for( ; g_UnDeleteStackPtr != 0; )
{
g_UnDeleteStackPtr--;
......@@ -221,6 +223,7 @@ void WinEDA_PcbFrame::Erase_Zones( bool query )
}
DelLimitesZone( NULL, FALSE );
m_Pcb->DeleteZONEOutlines();
GetScreen()->SetModify();
}
......
......@@ -815,6 +815,13 @@ int WinEDA_PcbFrame::ReadPcbFile( wxDC* DC, FILE* File, bool Append )
continue;
}
if( strnicmp( Line, "$CZONE_OUTLINE", 7 ) == 0 )
{
ZONE_CONTAINER * zone_descr = new ZONE_CONTAINER(m_Pcb);
zone_descr->ReadDescr( File, &LineNum );
m_Pcb->m_ZoneDescriptorList.push_back(zone_descr);
}
if( strnicmp( Line, "$MODULE", 7 ) == 0 )
{
Module = new MODULE( m_Pcb );
......
EXTRALIBS = ../common/common.a
EXTRALIBS = ../common/common.a ../polygon/lib_polygon.a
EXTRACPPFLAGS += -DPCBNEW -fno-strict-aliasing -I./ -Ibitmaps -I../include -I../share\
-I../pcbnew -I../3d-viewer -I../polygon
......
......@@ -38,6 +38,11 @@ void WinEDA_PcbFrame::OnLeftClick( wxDC* DC, const wxPoint& MousePos )
switch( DrawStruct->Type() )
{
case TYPEZONE_CONTAINER:
End_Move_Zone_Corner( DC, (ZONE_CONTAINER *) DrawStruct );
exit = true;
break;
case TYPETRACK:
case TYPEVIA:
if( DrawStruct->m_Flags & IS_DRAGGED )
......
......@@ -275,6 +275,41 @@ bool WinEDA_PcbFrame::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu )
_( "Delete edge zone" ), delete_xpm );
break;
case TYPEZONE_CONTAINER:
{
ZONE_CONTAINER * edge_zone = (ZONE_CONTAINER *) item;
if ( edge_zone->m_Flags )
{
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_PLACE_ZONE_CORNER,
_( "Place Corner" ), apply_xpm );
}
else
{
edge_zone->m_CornerSelection = -1;
int index;
if ( (index = edge_zone->HitTestForCorner( GetScreen()->m_Curseur )) >= 0 )
{
edge_zone->m_CornerSelection = index;
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_MOVE_ZONE_CORNER,
_( "Move Corner" ), move_xpm );
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_DELETE_ZONE_CORNER,
_( "Delete Corner" ), delete_xpm );
}
else if ( (index = edge_zone->HitTestForEdge( GetScreen()->m_Curseur )) >= 0 )
{
edge_zone->m_CornerSelection = index;
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_ADD_ZONE_CORNER,
_( "Create Corner" ), move_xpm );
}
aPopMenu->AppendSeparator();
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_EDIT_ZONE_PARAMS,
_( "Edit Zone Params" ), edit_xpm );
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_DELETE_ZONE_CONTAINER,
_( "Delete Zone Outline" ), delete_xpm );
}
}
break;
case TYPETEXTE:
createPopUpMenuForTexts( (TEXTE_PCB*) item, aPopMenu );
break;
......@@ -286,8 +321,6 @@ bool WinEDA_PcbFrame::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu )
break;
case TYPEZONE:
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_EDIT_ZONE,
_( "Edit Zone" ), edit_xpm );
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_DELETE_ZONE,
_( "Delete Zone" ), delete_xpm );
break;
......@@ -358,14 +391,6 @@ bool WinEDA_PcbFrame::OnRightClick( const wxPoint& aMousePos, wxMenu* aPopMenu )
ADD_MENUITEM( aPopMenu, ID_POPUP_PCB_FILL_ZONE,
_( "Fill zone" ), fill_zone_xpm );
if( item
&& ( (item->Type() == TYPEPAD)
|| (item->Type() == TYPETRACK)
|| (item->Type() == TYPEVIA) ) )
{
add_separator = TRUE;
aPopMenu->Append( ID_POPUP_PCB_SELECT_NET_ZONE, _( "Select Net" ) );
}
if( m_Pcb->m_CurrentLimitZone )
{
add_separator = TRUE;
......
......@@ -8,6 +8,8 @@
* Routines d'affichage grille, Boite de coordonnees, Curseurs, marqueurs ...
*/
#include <vector.h>
#include "fctsys.h"
#include "gr_basic.h"
......@@ -18,9 +20,7 @@
#include "protos.h"
/* Routines Locales : */
/* Variables Locales */
using namespace std;
/**********************************************************************/
......@@ -185,6 +185,12 @@ void WinEDA_PcbFrame::Trace_Pcb( wxDC* DC, int mode )
Trace_DrawSegmentPcb( DrawPanel, DC, segment, mode );
}
for( unsigned ii = 0; ii < m_Pcb->m_ZoneDescriptorList.size(); ii++ )
{
ZONE_CONTAINER* edge_zone = m_Pcb->m_ZoneDescriptorList[ii];
edge_zone->Draw( DrawPanel, DC, wxPoint(0,0), mode);
}
DrawGeneralRatsnest( DC );
m_CurrentScreen->ClrRefreshReq();
......
/////////////////////////////////////////////////////////////////////////////
// Name: zones_by_polygon.cpp
// Purpose:
// Author: jean-pierre Charras
// Modified by:
// Created: 25/01/2006 11:35:19
// RCS-ID:
// Copyright: GNU License
// Licence: GNU License
/////////////////////////////////////////////////////////////////////////////
// Generated by DialogBlocks (unregistered), 25/01/2006 11:35:19
#if defined (__GNUG__) && !defined (NO_GCC_PRAGMA)
#pragma implementation "dialog_zones_by_polygon.h"
#endif
#include "fctsys.h"
#include "gr_basic.h"
#include "common.h"
#include "pcbnew.h"
#include "autorout.h"
#include "cell.h"
#include "trigo.h"
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
#include "protos.h"
// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"
......@@ -35,33 +20,43 @@
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
using namespace std;
////@begin includes
////@end includes
#include "fctsys.h"
#include "gr_basic.h"
#include "common.h"
#include "pcbnew.h"
////@begin XPM images
////@end XPM images
#include "autorout.h"
#include "cell.h"
#include "trigo.h"
#include "protos.h"
/* Imported functions */
void Build_Zone( WinEDA_PcbFrame* frame, wxDC* DC, int net_code,
bool Zone_Exclude_Pads, bool Zone_Create_Thermal_Relief );
/* Local functions */
static void Display_Zone_Netname( WinEDA_PcbFrame* frame );
static void Exit_Zones( WinEDA_DrawPanel* Panel, wxDC* DC );
static void Show_Zone_Edge_While_MoveMouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase );
// Outile creation:
static void Abort_Zone_Create_Outline( WinEDA_DrawPanel* Panel, wxDC* DC );
static void Show_New_Zone_Edge_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase );
// Corner moving
static void Abort_Zone_Move_Corner( WinEDA_DrawPanel* Panel, wxDC* DC );
static void Show_Zone_Corner_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase );
/* Local variables */
static bool Zone_45_Only = FALSE;
static bool Zone_Exclude_Pads = TRUE;
static bool s_Zone_Create_Thermal_Relief = TRUE;
static int s_Zone_Layer; // Layer used to put the current zone
static int s_NetcodeSelection; // Net code selection for the current zone
static int s_Zone_Layer; // Layer used to create the current zone
static int s_Zone_Hatching; // Option to show the zone area (outlines only, short hatches or full hatches
static int s_NetcodeSelection; // Net code selection for the current zone
static wxPoint s_CornerInitialPosition; // Used to abort a move corner command
static bool s_CornerIsNew; // Used to abort a move corner command (if it is a new corner, it must be deleted)
// key used to store net sort option in config file :
#define ZONE_NET_SORT_OPTION_KEY wxT("Zone_NetSort_Opt")
enum zone_cmd {
......@@ -72,55 +67,6 @@ enum zone_cmd {
#include "dialog_zones_by_polygon.cpp"
/**************************************************************/
void WinEDA_PcbFrame::Edit_Zone_Width( wxDC* DC, SEGZONE* aZone )
/**************************************************************/
/* Edite (change la largeur des segments) la zone Zone.
* La zone est constituee des segments zones de meme TimeStamp
*/
{
bool modify = FALSE;
double f_new_width;
int w_tmp;
wxString Line;
wxString Msg( _( "New zone segment width: " ) );
if( aZone == NULL )
return;
f_new_width = To_User_Unit( g_UnitMetric, aZone->m_Width, GetScreen()->GetInternalUnits() );
Line.Printf( wxT( "%.4f" ), f_new_width );
Msg += g_UnitMetric ? wxT( "(mm)" ) : wxT( "(\")" );
if( Get_Message( Msg, Line, this ) != 0 )
return;
w_tmp = g_DesignSettings.m_CurrentTrackWidth;
Line.ToDouble( &f_new_width );
g_DesignSettings.m_CurrentTrackWidth = From_User_Unit( g_UnitMetric,
f_new_width, GetScreen(
)->GetInternalUnits() );
for( SEGZONE* zone = m_Pcb->m_Zone; zone; zone = zone->Next() )
{
if( zone->m_TimeStamp == aZone->m_TimeStamp )
{
modify = TRUE;
Edit_TrackSegm_Width( DC, zone );
}
}
g_DesignSettings.m_CurrentTrackWidth = w_tmp;
if( modify )
{
GetScreen()->SetModify();
DrawPanel->Refresh();
}
}
/**********************************************************/
void WinEDA_PcbFrame::Delete_Zone( wxDC* DC, SEGZONE* aZone )
......@@ -199,103 +145,12 @@ EDGE_ZONE* WinEDA_PcbFrame::Del_SegmEdgeZone( wxDC* DC, EDGE_ZONE* edge_zone )
}
/*********************************************/
void WinEDA_PcbFrame::CaptureNetName( wxDC* DC )
/*********************************************/
/* routine permettant de capturer le nom net net (netcode) d'un pad
* ou d'une piste pour l'utiliser comme netcode de zone
*/
{
D_PAD* pt_pad = 0;
TRACK* adrpiste;
MODULE* Module;
int masquelayer = g_TabOneLayerMask[GetScreen()->m_Active_Layer];
int netcode;
netcode = -1;
MsgPanel->EraseMsgBox();
adrpiste = Locate_Pistes( m_Pcb->m_Track, masquelayer, CURSEUR_OFF_GRILLE );
if( adrpiste == NULL )
{
pt_pad = Locate_Any_Pad( m_Pcb, CURSEUR_OFF_GRILLE );
if( pt_pad ) /* Verif qu'il est bien sur la couche active */
{
Module = (MODULE*) pt_pad->m_Parent;
pt_pad = Locate_Pads( Module, g_TabOneLayerMask[GetScreen()->m_Active_Layer],
CURSEUR_OFF_GRILLE );
}
if( pt_pad )
{
pt_pad->Display_Infos( this );
netcode = pt_pad->GetNet();
}
}
else
{
adrpiste->Display_Infos( this );
netcode = adrpiste->GetNet();
}
// Mise en surbrillance du net
if( g_HightLigt_Status )
Hight_Light( DC );
g_HightLigth_NetCode = netcode;
if( g_HightLigth_NetCode >= 0 )
{
Hight_Light( DC );
}
/* Affichage du net selectionne pour la zone a tracer */
Display_Zone_Netname( this );
}
/*******************************************************/
static void Display_Zone_Netname( WinEDA_PcbFrame* frame )
/*******************************************************/
/*
* Affiche le net_code et le nom de net couramment selectionne
*/
{
EQUIPOT* pt_equipot;
wxString line;
pt_equipot = frame->m_Pcb->m_Equipots;
if( g_HightLigth_NetCode > 0 )
{
for( ; pt_equipot != NULL; pt_equipot = (EQUIPOT*) pt_equipot->Pnext )
{
if( pt_equipot->GetNet() == g_HightLigth_NetCode )
break;
}
if( pt_equipot )
{
line.Printf( wxT( "Zone: Net[%d] <%s>" ), g_HightLigth_NetCode,
pt_equipot->m_Netname.GetData() );
}
else
line.Printf( wxT( "Zone: NetCode[%d], Equipot not found" ),
g_HightLigth_NetCode );
}
line = _( "Zone: No net selected" );
frame->Affiche_Message( line );
}
/********************************************************/
static void Exit_Zones( WinEDA_DrawPanel* Panel, wxDC* DC )
/********************************************************/
/*************************************************************************/
static void Abort_Zone_Create_Outline( WinEDA_DrawPanel* Panel, wxDC* DC )
/*************************************************************************/
/**
* Function Exit_Zones
* Function Abort_Zone_Create_Outline
* cancels the Begin_Zone state if at least one EDGE_ZONE has been created.
*/
{
......@@ -326,9 +181,6 @@ void WinEDA_BasePcbFrame::DelLimitesZone( wxDC* DC, bool Redraw )
if( m_Pcb->m_CurrentLimitZone == NULL )
return;
if( !IsOK( this, _( "Delete Current Zone Edges" ) ) )
return;
// erase the old zone border, one segment at a time
for( segment = m_Pcb->m_CurrentLimitZone; segment; segment = next )
{
......@@ -345,13 +197,109 @@ void WinEDA_BasePcbFrame::DelLimitesZone( wxDC* DC, bool Redraw )
SetCurItem( NULL );
}
/*******************************************************************************************************/
void WinEDA_PcbFrame::Start_Move_Zone_Corner( wxDC* DC , ZONE_CONTAINER * zone_container,
int corner_id, bool IsNewCorner )
/*******************************************************************************************************/
/**
* Function Start_Move_Zone_Corner
* Initialise parametres to move an existing corner of a zone.
* if IsNewCorner is true, the Abort_Zone_Move_Corner will remove this corner, if called
*/
{
/* Show the Net */
if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) )
{
Hight_Light( DC ); // Remove old hightlight selection
}
g_HightLigth_NetCode = s_NetcodeSelection;
if ( ! g_HightLigt_Status )
Hight_Light( DC );
zone_container->m_Flags = IN_EDIT;
DrawPanel->ManageCurseur = Show_Zone_Corner_While_Move_Mouse;
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Move_Corner;
s_CornerInitialPosition.x = zone_container->GetX(corner_id);
s_CornerInitialPosition.y = zone_container->GetY(corner_id);
s_CornerIsNew = IsNewCorner;
}
/***************************************************************************************/
void WinEDA_PcbFrame::End_Move_Zone_Corner( wxDC* DC , ZONE_CONTAINER * zone_container )
/****************************************************************************************/
/**
* Function End_Move_Zone_Corner
* Terminates a move corner in a zone outline
*/
{
zone_container->m_Flags = 0;
DrawPanel->ManageCurseur = NULL;
DrawPanel->ForceCloseManageCurseur = NULL;
zone_container->Draw(DrawPanel, DC, wxPoint(0,0), GR_OR);
}
/**************************************************************/
void Abort_Zone_Move_Corner( WinEDA_DrawPanel* Panel, wxDC* DC )
/**************************************************************/
/**
* Function Abort_Zone_Move_Corner
* cancels the Begin_Zone state if at least one EDGE_ZONE has been created.
*/
{
WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) Panel->m_Parent;
ZONE_CONTAINER* zone_container = (ZONE_CONTAINER*) pcbframe->GetCurItem();
zone_container->Draw(Panel, DC, wxPoint(0,0), GR_XOR);
if ( s_CornerIsNew )
{
zone_container->DeleteCorner( zone_container->m_CornerSelection );
}
else
{
wxPoint pos = s_CornerInitialPosition;
zone_container->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y );
}
zone_container->Draw(Panel, DC, wxPoint(0,0), GR_XOR);
Panel->ManageCurseur = NULL;
Panel->ForceCloseManageCurseur = NULL;
pcbframe->SetCurItem( NULL );
zone_container->m_Flags = 0;
}
/**************************************************************************************/
void Show_Zone_Corner_While_Move_Mouse( WinEDA_DrawPanel* Panel, wxDC* DC, bool erase )
/**************************************************************************************/
/* Redraws the zone outline when moving a corner according to the cursor position
*/
{
WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) Panel->m_Parent;
ZONE_CONTAINER* zone_container = (ZONE_CONTAINER*) pcbframe->GetCurItem();
// if( erase ) /* Undraw edge in old position*/
{
zone_container->Draw(Panel, DC, wxPoint(0,0), GR_XOR);
}
wxPoint pos = pcbframe->GetScreen()->m_Curseur;
zone_container->MoveCorner( zone_container->m_CornerSelection, pos.x, pos.y );
zone_container->Draw(Panel, DC, wxPoint(0,0), GR_XOR);
}
/*************************************************/
EDGE_ZONE* WinEDA_PcbFrame::Begin_Zone( wxDC* DC )
/*************************************************/
/**
* Function Begin_Zone
* either initializes the first segment of a new zone, or adds an
* intermediate segment.
*/
EDGE_ZONE* WinEDA_PcbFrame::Begin_Zone( wxDC* DC )
{
EDGE_ZONE* oldedge;
EDGE_ZONE* newedge = NULL;
......@@ -401,13 +349,12 @@ EDGE_ZONE* WinEDA_PcbFrame::Begin_Zone( wxDC* DC )
m_Pcb->m_CurrentLimitZone = newedge;
DrawPanel->ManageCurseur = Show_Zone_Edge_While_MoveMouse;
DrawPanel->ForceCloseManageCurseur = Exit_Zones;
DrawPanel->ManageCurseur = Show_New_Zone_Edge_While_Move_Mouse;
DrawPanel->ForceCloseManageCurseur = Abort_Zone_Create_Outline;
}
// edge in progress:
else /* piste en cours : les coord du point d'arrivee ont ete mises
* a jour par la routine Show_Zone_Edge_While_MoveMouse*/
{
else
{ /* edge in progress : the ending point coordinate was set by Show_New_Zone_Edge_While_Move_Mouse */
if( oldedge->m_Start != oldedge->m_End )
{
oldedge->m_Flags &= ~(IS_NEW | IS_MOVED);
......@@ -433,7 +380,9 @@ void WinEDA_PcbFrame::End_Zone( wxDC* DC )
/*********************************************/
/*
* Routine de fin de trace d'une zone (succession de segments)
* Terminates an edge zone creation
* Close the current edge zone considered as a polygon
* put it in the main list m_Pcb->m_ZoneDescriptorList (a vector<ZONE_CONTAINER*>)
*/
{
EDGE_ZONE* edge;
......@@ -442,8 +391,9 @@ void WinEDA_PcbFrame::End_Zone( wxDC* DC )
{
Begin_Zone( DC );
/* le dernier point genere est de longueur tj nulle donc inutile. */
/* il sera raccorde au point de depart */
/* The last segment is a stub: its lenght is 0.
* Use it to close the polygon by setting its ending point coordinate = start point of first segment
*/
edge = m_Pcb->m_CurrentLimitZone;
edge->m_Flags &= ~(IS_NEW | IS_MOVED);
......@@ -466,14 +416,46 @@ void WinEDA_PcbFrame::End_Zone( wxDC* DC )
DrawPanel->ManageCurseur = NULL;
DrawPanel->ForceCloseManageCurseur = NULL;
/* Put edges in list */
ZONE_CONTAINER * polygon = new ZONE_CONTAINER( m_Pcb );
polygon->SetLayer( GetScreen()->m_Active_Layer );
polygon->SetNet( g_HightLigth_NetCode );
polygon->m_TimeStamp = GetTimeStamp();
EQUIPOT* net = m_Pcb->FindNet( g_HightLigth_NetCode );
if ( net ) polygon->m_Netname = net->m_Netname;
edge = m_Pcb->m_CurrentLimitZone;
polygon->Start( GetScreen()->m_Active_Layer, 0, NULL,
edge->m_Start.x, edge->m_Start.y,
s_Zone_Hatching );
edge = edge->Next();
while( edge )
{
polygon->AppendCorner( edge->m_Start.x, edge->m_Start.y );
edge = edge->Next();
}
polygon->Close(); // Close the current corner list
polygon->Hatch();
m_Pcb->m_ZoneDescriptorList.push_back(polygon);
/* Remove the current temporary list */
DelLimitesZone( DC, TRUE );
/* Redraw the real edge zone */
polygon->CPolyLine::Draw( ); // Build the line list
polygon->Draw( DrawPanel, DC, wxPoint(0,0), GR_OR );
GetScreen()->SetModify();
}
/******************************************************************************************/
static void Show_Zone_Edge_While_MoveMouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
static void Show_New_Zone_Edge_While_Move_Mouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase )
/******************************************************************************************/
/* redessin du contour de la piste lors des deplacements de la souris
/* Redraws the edge zone when moving mouse
*/
{
EDGE_ZONE* edge;
......@@ -483,8 +465,7 @@ static void Show_Zone_Edge_While_MoveMouse( WinEDA_DrawPanel* panel, wxDC* DC, b
if( pcbframe->m_Pcb->m_CurrentLimitZone == NULL )
return;
/* efface ancienne position si elle a ete deja dessinee */
if( erase )
if( erase ) /* Undraw edge in old position*/
{
edge = pcbframe->m_Pcb->m_CurrentLimitZone;
......@@ -494,23 +475,22 @@ static void Show_Zone_Edge_While_MoveMouse( WinEDA_DrawPanel* panel, wxDC* DC, b
}
}
/* mise a jour de la couche */
/* Reinit layer (which can be changed) */
for( edge = pcbframe->m_Pcb->m_CurrentLimitZone; edge; edge = edge->Next() )
{
edge->SetLayer( pcbframe->GetScreen()->m_Active_Layer );
}
/* dessin de la nouvelle piste : mise a jour du point d'arrivee */
/* Redraw the curent edge in its new position */
currentEdge = pcbframe->m_Pcb->m_CurrentLimitZone;
if( Zone_45_Only )
{
// Calcul de l'extremite de la piste pour orientations permises:
// horiz,vertical ou 45 degre
// calculate the new position as allowed
currentEdge->m_End = pcbframe->GetScreen()->m_Curseur;
Calcule_Coord_Extremite_45( currentEdge->m_Start.x, currentEdge->m_Start.y,
&currentEdge->m_End.x, &currentEdge->m_End.y );
}
else /* ici l'angle d'inclinaison est quelconque */
else /* all orientations are allowed */
{
currentEdge->m_End = pcbframe->GetScreen()->m_Curseur;
}
......@@ -522,58 +502,58 @@ static void Show_Zone_Edge_While_MoveMouse( WinEDA_DrawPanel* panel, wxDC* DC, b
}
/**********************************************/
void WinEDA_PcbFrame::Fill_Zone( wxDC* DC )
/**********************************************/
/** Function Fill_Zone()
* Init the zone filling
* If a zone edge is found, it is used.
* Otherwise the whole board is filled by the zone
* The zone edge is a frontier, and can be complex. So non filled zones can be achieved
* The zone is put on the active layer
* If a net is hightlighted, the zone will be attached to this net
* The filling start from a starting point.
* If a net is selected, all tracks attached to this net are also starting points
/***********************************************************************************/
void WinEDA_PcbFrame::Edit_Zone_Params( wxDC* DC , ZONE_CONTAINER * zone_container )
/***********************************************************************************/
/**
* Function Edit_Zone_Params
* Edit params (layer, clearance, ...) for a zone outline
*/
{
EQUIPOT* pt_equipot;
wxPoint ZoneStartFill;
wxString msg;
MsgPanel->EraseMsgBox();
if( m_Pcb->ComputeBoundaryBox() == FALSE )
{
DisplayError( this, wxT( "Board is empty!" ), 10 );
return;
}
DrawPanel->m_IgnoreMouseEvents = TRUE;
WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this );
WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this, zone_container );
int diag = frame->ShowModal();
frame->Destroy();
DrawPanel->MouseToCursorSchema();
DrawPanel->m_IgnoreMouseEvents = FALSE;
if( diag == ZONE_ABORT )
if( diag == ZONE_ABORT )
return;
// set all the EDGE_ZONEs to the currently active layer and redraw them
// on that layer.
GetScreen()->m_Active_Layer = s_Zone_Layer;
EDGE_ZONE* PtLim = m_Pcb->m_CurrentLimitZone;
for( ; PtLim != NULL; PtLim = PtLim->Next() )
zone_container->Draw( DrawPanel, DC, wxPoint(0,0), GR_XOR );
zone_container->SetLayer( s_Zone_Layer );
zone_container->SetNet( s_NetcodeSelection );
EQUIPOT* net = m_Pcb->FindNet( s_NetcodeSelection );
if ( net ) zone_container->m_Netname = net->m_Netname;
zone_container->SetHatch(s_Zone_Hatching);
zone_container->Draw( DrawPanel, DC, wxPoint(0,0), GR_OR );
}
/***************************************************************************/
void WinEDA_PcbFrame::Fill_Zone( wxDC* DC, ZONE_CONTAINER * zone_container )
/***************************************************************************/
/** Function Fill_Zone()
* Fillst the zone defined in zone_container
*/
{
wxPoint ZoneStartFill;
wxString msg;
MsgPanel->EraseMsgBox();
if( m_Pcb->ComputeBoundaryBox() == FALSE )
{
Trace_DrawSegmentPcb( DrawPanel, DC, PtLim, GR_XOR );
PtLim->SetLayer( s_Zone_Layer );
Trace_DrawSegmentPcb( DrawPanel, DC, PtLim, GR_XOR );
DisplayError( this, wxT( "Board is empty!" ), 10 );
return;
}
/* Show the Net */
if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) )
{
Hight_Light( DC ); // Remoive old hightlight selection
Hight_Light( DC ); // Remove old hightlight selection
}
g_HightLigth_NetCode = s_NetcodeSelection;
......@@ -582,14 +562,17 @@ void WinEDA_PcbFrame::Fill_Zone( wxDC* DC )
if( g_HightLigth_NetCode > 0 )
{
pt_equipot = m_Pcb->FindNet( g_HightLigth_NetCode );
if( pt_equipot == NULL )
EQUIPOT* net = m_Pcb->FindNet( g_HightLigth_NetCode );
if( net == NULL )
{
if( g_HightLigth_NetCode > 0 )
{
DisplayError( this, wxT( "Unable to find Net name" ) );
return;
}
}
else
msg = pt_equipot->m_Netname;
msg = net->m_Netname;
}
else
msg = _( "No Net" );
......
// PolyLine.cpp ... implementation of CPolyLine class
// from FreePCB.
// Adaptation for kicad
//
using namespace std;
#include <math.h>
#include <vector>
#include "PolyLine.h"
#define to_int(x) (int)round((x))
/* Stuff to compile PolyLine.cpp, used in std::vector as CArray. does not work. must be redesigned, only for test */
#define SetSize reserve
#define pi 3.14159265359
#define DENOM 10 // to use mils for php clipping
//#define DENOM 1 // to use internal units for php clipping
// dl is a pointer to CDisplayList for drawing graphic elements
// if dl = NULL, doesn't draw anything but can still hold data
//
CPolyLine::CPolyLine( CDisplayList * dl )
{
m_dlist = dl;
m_HatchStyle = 0;
m_sel_box = 0;
m_gpc_poly = new gpc_polygon;
m_gpc_poly->num_contours = 0;
m_php_poly = new polygon;
}
CPolyLine::CPolyLine()
{
m_dlist = NULL;
m_HatchStyle = 0;
m_sel_box = 0;
m_gpc_poly = new gpc_polygon;
m_gpc_poly->num_contours = 0;
m_php_poly = new polygon;
}
// destructor, removes display elements
//
CPolyLine::~CPolyLine()
{
Undraw();
FreeGpcPoly();
delete m_gpc_poly;
delete m_php_poly;
}
// 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
// Returns number of external contours, or -1 if error
//
int CPolyLine::NormalizeWithGpc( std::vector<CPolyLine*> * pa, BOOL bRetainArcs )
{
std::vector<CArc> arc_array;
if( bRetainArcs )
MakeGpcPoly( -1, &arc_array );
else
MakeGpcPoly( -1, NULL );
Undraw();
// now, recreate poly
// first, find outside contours and create new CPolyLines if necessary
int n_ext_cont = 0;
for( int ic=0; ic<m_gpc_poly->num_contours; ic++ )
{
if( !(m_gpc_poly->hole)[ic] )
{
if( n_ext_cont == 0 )
{
// first external contour, replace this poly
corner.clear();
side_style.clear();
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x);
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y);
if( i==0 )
Start( m_layer, m_Width, m_sel_box, x, y, m_HatchStyle );
else
AppendCorner( x, y, STRAIGHT, FALSE );
}
Close();
n_ext_cont++;
}
else if( pa )
{
// next external contour, create new poly
CPolyLine * poly = new CPolyLine;
pa->SetSize(n_ext_cont); // put in array
(*pa)[n_ext_cont-1] = poly;
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x);
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y);
if( i==0 )
poly->Start( m_layer, m_Width, m_sel_box, x, y, m_HatchStyle );
else
poly->AppendCorner( x, y, STRAIGHT, FALSE );
}
poly->Close( STRAIGHT, FALSE );
n_ext_cont++;
}
}
}
// now add cutouts to the CPolyLine(s)
for( int ic=0; ic<m_gpc_poly->num_contours; ic++ )
{
if( (m_gpc_poly->hole)[ic] )
{
CPolyLine * ext_poly = NULL;
if( n_ext_cont == 1 )
{
ext_poly = this;
}
else
{
// find the polygon that contains this hole
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x);
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y);
if( TestPointInside( x, y ) )
ext_poly = this;
else
{
for( int ext_ic=0; ext_ic<n_ext_cont-1; ext_ic++ )
{
if( (*pa)[ext_ic]->TestPointInside( x, y ) )
{
ext_poly = (*pa)[ext_ic];
break;
}
}
}
if( ext_poly )
break;
}
}
if( !ext_poly )
ASSERT(0);
for( int i=0; i<m_gpc_poly->contour[ic].num_vertices; i++ )
{
int x = to_int(((m_gpc_poly->contour)[ic].vertex)[i].x);
int y = to_int(((m_gpc_poly->contour)[ic].vertex)[i].y);
ext_poly->AppendCorner( x, y, STRAIGHT, FALSE );
}
ext_poly->Close( STRAIGHT, FALSE );
}
}
if( bRetainArcs )
RestoreArcs( &arc_array, pa );
FreeGpcPoly();
return n_ext_cont;
}
// make a php_polygon from first contour
int CPolyLine::MakePhpPoly()
{
FreePhpPoly();
polygon test_poly;
int nv = GetContourEnd(0);
for( int iv=0; iv<=nv; iv++ )
{
int x = GetX(iv)/DENOM;
int y = GetY(iv)/DENOM;
m_php_poly->addv( x, y );
}
return 0;
}
void CPolyLine::FreePhpPoly()
{
// delete all vertices
while( m_php_poly->m_cnt > 1 )
{
vertex * fv = m_php_poly->getFirst();
m_php_poly->del( fv->m_nextV );
}
delete m_php_poly->m_first;
m_php_poly->m_first = NULL;
m_php_poly->m_cnt = 0;
}
// Use the php clipping lib to clip this poly against poly
//
void CPolyLine::ClipPhpPolygon( int php_op, CPolyLine * poly )
{
Undraw();
poly->MakePhpPoly();
MakePhpPoly();
polygon * p = m_php_poly->boolean( poly->m_php_poly, php_op );
poly->FreePhpPoly();
FreePhpPoly();
if( p )
{
// now screw with the PolyLine
corner.clear();
side_style.clear();
do
{
vertex * v = p->getFirst();
Start( m_layer, m_Width, m_sel_box,
to_int(v->X()*DENOM),
to_int(v->Y()*DENOM),
m_HatchStyle );
do
{
vertex * n = v->Next();
AppendCorner( to_int(v->X()*DENOM), to_int((v->Y()*DENOM )) );
v = n;
}
while( v->id() != p->getFirst()->id() );
Close();
// p = p->NextPoly();
delete p;
p = NULL;
}
while( p );
}
Draw();
}
// make a gpc_polygon for a closed polyline contour
// approximates arcs with multiple straight-line segments
// if icontour = -1, make polygon with all contours,
// combining intersecting contours if possible
// returns data on arcs in arc_array
//
int CPolyLine::MakeGpcPoly( int icontour, std::vector<CArc> * arc_array )
{
if( m_gpc_poly->num_contours )
FreeGpcPoly();
if( !GetClosed() && (icontour == (GetNumContours()-1) || icontour == -1))
return 1; // error
// initialize m_gpc_poly
m_gpc_poly->num_contours = 0;
m_gpc_poly->hole = NULL;
m_gpc_poly->contour = NULL;
int n_arcs = 0;
int first_contour = icontour;
int last_contour = icontour;
if( icontour == -1 )
{
first_contour = 0;
last_contour = GetNumContours() - 1;
}
if( arc_array )
arc_array->SetSize(0);
int iarc = 0;
for( int icont=first_contour; icont<=last_contour; icont++ )
{
// make gpc_polygon for this contour
gpc_polygon * gpc = new gpc_polygon;
gpc->num_contours = 0;
gpc->hole = NULL;
gpc->contour = NULL;
// first, calculate number of vertices in contour
int n_vertices = 0;
int ic_st = GetContourStart(icont);
int ic_end = GetContourEnd(icont);
for( int ic=ic_st; ic<=ic_end; ic++ )
{
int style = side_style[ic];
int x1 = corner[ic].x;
int y1 = corner[ic].y;
int x2, y2;
if( ic < ic_end )
{
x2 = corner[ic+1].x;
y2 = corner[ic+1].y;
}
else
{
x2 = corner[ic_st].x;
y2 = corner[ic_st].y;
}
if( style == STRAIGHT )
n_vertices++;
else
{
// style is ARC_CW or ARC_CCW
int n; // number of steps for arcs
n = (abs(x2-x1)+abs(y2-y1))/(CArc::MAX_STEP);
n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc
n_vertices += n;
n_arcs++;
}
}
// now create gcp_vertex_list for this contour
gpc_vertex_list * g_v_list = new gpc_vertex_list;
g_v_list->vertex = (gpc_vertex*)calloc( sizeof(gpc_vertex), n_vertices );
g_v_list->num_vertices = n_vertices;
int ivtx = 0;
for( int ic=ic_st; ic<=ic_end; ic++ )
{
int style = side_style[ic];
int x1 = corner[ic].x;
int y1 = corner[ic].y;
int x2, y2;
if( ic < ic_end )
{
x2 = corner[ic+1].x;
y2 = corner[ic+1].y;
}
else
{
x2 = corner[ic_st].x;
y2 = corner[ic_st].y;
}
if( style == STRAIGHT )
{
g_v_list->vertex[ivtx].x = x1;
g_v_list->vertex[ivtx].y = y1;
ivtx++;
}
else
{
// style is arc_cw or arc_ccw
int n; // number of steps for arcs
n = (abs(x2-x1)+abs(y2-y1))/(CArc::MAX_STEP);
n = max( n, CArc::MIN_STEPS ); // or at most 5 degrees of arc
double xo, yo, theta1, theta2, a, b;
a = fabs( (double)(x1 - x2) );
b = fabs( (double)(y1 - y2) );
if( style == CPolyLine::ARC_CW )
{
// clockwise arc (ie.quadrant of ellipse)
if( x2 > x1 && y2 > y1 )
{
// first quadrant, draw second quadrant of ellipse
xo = x2;
yo = y1;
theta1 = pi;
theta2 = pi/2.0;
}
else if( x2 < x1 && y2 > y1 )
{
// second quadrant, draw third quadrant of ellipse
xo = x1;
yo = y2;
theta1 = 3.0*pi/2.0;
theta2 = pi;
}
else if( x2 < x1 && y2 < y1 )
{
// third quadrant, draw fourth quadrant of ellipse
xo = x2;
yo = y1;
theta1 = 2.0*pi;
theta2 = 3.0*pi/2.0;
}
else
{
xo = x1; // fourth quadrant, draw first quadrant of ellipse
yo = y2;
theta1 = pi/2.0;
theta2 = 0.0;
}
}
else
{
// counter-clockwise arc
if( x2 > x1 && y2 > y1 )
{
xo = x1; // first quadrant, draw fourth quadrant of ellipse
yo = y2;
theta1 = 3.0*pi/2.0;
theta2 = 2.0*pi;
}
else if( x2 < x1 && y2 > y1 )
{
xo = x2; // second quadrant
yo = y1;
theta1 = 0.0;
theta2 = pi/2.0;
}
else if( x2 < x1 && y2 < y1 )
{
xo = x1; // third quadrant
yo = y2;
theta1 = pi/2.0;
theta2 = pi;
}
else
{
xo = x2; // fourth quadrant
yo = y1;
theta1 = pi;
theta2 = 3.0*pi/2.0;
}
}
// now write steps for arc
if( arc_array )
{
arc_array->SetSize(iarc+1);
(*arc_array)[iarc].style = style;
(*arc_array)[iarc].n_steps = n;
(*arc_array)[iarc].xi = x1;
(*arc_array)[iarc].yi = y1;
(*arc_array)[iarc].xf = x2;
(*arc_array)[iarc].yf = y2;
iarc++;
}
for( int is=0; is<n; is++ )
{
double theta = theta1 + ((theta2-theta1)*(double)is)/n;
double x = xo + a*cos(theta);
double y = yo + b*sin(theta);
if( is == 0 )
{
x = x1;
y = y1;
}
g_v_list->vertex[ivtx].x = x;
g_v_list->vertex[ivtx].y = y;
ivtx++;
}
}
}
if( n_vertices != ivtx )
ASSERT(0);
// add vertex_list to gpc
gpc_add_contour( gpc, g_v_list, 0 );
// now clip m_gpc_poly with gpc, put new poly into result
gpc_polygon * result = new gpc_polygon;
if( icontour == -1 && icont != 0 )
gpc_polygon_clip( GPC_DIFF, m_gpc_poly, gpc, result ); // hole
else
gpc_polygon_clip( GPC_UNION, m_gpc_poly, gpc, result ); // outside
// now copy result to m_gpc_poly
gpc_free_polygon( m_gpc_poly );
delete m_gpc_poly;
m_gpc_poly = result;
gpc_free_polygon( gpc );
delete gpc;
free( g_v_list->vertex );
free( g_v_list );
}
return 0;
}
int CPolyLine::FreeGpcPoly()
{
if( m_gpc_poly->num_contours )
{
delete m_gpc_poly->contour->vertex;
delete m_gpc_poly->contour;
delete m_gpc_poly->hole;
}
m_gpc_poly->num_contours = 0;
return 0;
}
// Restore arcs to a polygon where they were replaced with steps
// If pa != NULL, also use polygons in pa array
//
int CPolyLine::RestoreArcs( std::vector<CArc> * arc_array, std::vector<CPolyLine*> * pa )
{
// get poly info
int n_polys = 1;
if( pa )
n_polys += pa->size();
CPolyLine * poly;
// undraw polys and clear utility flag for all corners
for( int ip=0; ip<n_polys; ip++ )
{
if( ip == 0 )
poly = this;
else
poly = (*pa)[ip-1];
poly->Undraw();
for( int ic=0; ic<poly->GetNumCorners(); ic++ )
poly->SetUtility( ic, 0 ); // clear utility flag
}
// find arcs and replace them
BOOL bFound;
int arc_start;
int arc_end;
for( unsigned iarc=0; iarc<arc_array->size(); iarc++ )
{
int arc_xi = (*arc_array)[iarc].xi;
int arc_yi = (*arc_array)[iarc].yi;
int arc_xf = (*arc_array)[iarc].xf;
int arc_yf = (*arc_array)[iarc].yf;
int n_steps = (*arc_array)[iarc].n_steps;
int style = (*arc_array)[iarc].style;
bFound = FALSE;
// loop through polys
for( int ip=0; ip<n_polys; ip++ )
{
if( ip == 0 )
poly = this;
else
poly = (*pa)[ip-1];
for( int icont=0; icont<poly->GetNumContours(); icont++ )
{
int ic_start = poly->GetContourStart(icont);
int ic_end = poly->GetContourEnd(icont);
if( (ic_end-ic_start) > n_steps )
{
for( int ic=ic_start; ic<=ic_end; ic++ )
{
int ic_next = ic+1;
if( ic_next > ic_end )
ic_next = ic_start;
int xi = poly->GetX(ic);
int yi = poly->GetY(ic);
if( xi == arc_xi && yi == arc_yi )
{
// test for forward arc
int ic2 = ic + n_steps;
if( ic2 > ic_end )
ic2 = ic2 - ic_end + ic_start - 1;
int xf = poly->GetX(ic2);
int yf = poly->GetY(ic2);
if( xf == arc_xf && yf == arc_yf )
{
// arc from ic to ic2
bFound = TRUE;
arc_start = ic;
arc_end = ic2;
}
else
{
// try reverse arc
ic2 = ic - n_steps;
if( ic2 < ic_start )
ic2 = ic2 - ic_start + ic_end + 1;
xf = poly->GetX(ic2);
yf = poly->GetY(ic2);
if( xf == arc_xf && yf == arc_yf )
{
// arc from ic2 to ic
bFound = TRUE;
arc_start = ic2;
arc_end = ic;
style = 3 - style;
}
}
if( bFound )
{
poly->side_style[arc_start] = style;
// mark corners for deletion from arc_start+1 to arc_end-1
for( int i=arc_start+1; i!=arc_end; )
{
if( i > ic_end )
i = ic_start;
poly->SetUtility( i, 1 );
if( i == ic_end )
i = ic_start;
else
i++;
}
break;
}
}
if( bFound )
break;
}
}
if( bFound )
break;
}
}
if( bFound )
(*arc_array)[iarc].bFound = TRUE;
}
// now delete all marked corners
for( int ip=0; ip<n_polys; ip++ )
{
if( ip == 0 )
poly = this;
else
poly = (*pa)[ip-1];
for( int ic=poly->GetNumCorners()-1; ic>=0; ic-- )
{
if( poly->GetUtility(ic) )
poly->DeleteCorner( ic, FALSE );
}
}
return 0;
}
// initialize new polyline
// set layer, width, selection box size, starting point, id and pointer
//
// if sel_box = 0, don't create selection elements at all
//
// if polyline is board outline, enter with:
// id.type = ID_BOARD
// id.st = ID_BOARD_OUTLINE
// id.i = 0
// ptr = NULL
//
// if polyline is copper area, enter with:
// id.type = ID_NET;
// id.st = ID_AREA
// id.i = index to area
// ptr = pointer to net
//
void CPolyLine::Start( int layer, int w, int sel_box, int x, int y,
int hatch )
{
m_layer = layer;
m_Width = w;
m_sel_box = sel_box;
m_HatchStyle = hatch;
CPolyPt poly_pt( x, y );
poly_pt.end_contour = FALSE;
corner.push_back(poly_pt);
side_style.push_back(0);
}
// add a corner to unclosed polyline
//
void CPolyLine::AppendCorner( int x, int y, int style, BOOL bDraw )
{
Undraw();
CPolyPt poly_pt( x, y );
poly_pt.end_contour = FALSE;
// add entries for new corner and side
corner.push_back(poly_pt);
side_style.push_back(style);
if( corner.size() > 0 && !corner[corner.size()-1].end_contour )
side_style[corner.size()-1] = style;
int dl_type;
if( style == CPolyLine::STRAIGHT )
dl_type = DL_LINE;
else if( style == CPolyLine::ARC_CW )
dl_type = DL_ARC_CW;
else if( style == CPolyLine::ARC_CCW )
dl_type = DL_ARC_CCW;
else
ASSERT(0);
if( bDraw )
Draw();
}
// close last polyline contour
//
void CPolyLine::Close( int style, BOOL bDraw )
{
if( GetClosed() )
ASSERT(0);
Undraw();
side_style[corner.size()-1] = style;
corner[corner.size()-1].end_contour = TRUE;
if( bDraw )
Draw();
}
// move corner of polyline
//
void CPolyLine::MoveCorner( int ic, int x, int y )
{
Undraw();
corner[ic].x = x;
corner[ic].y = y;
Draw();
}
// delete corner and adjust arrays
//
void CPolyLine::DeleteCorner( int ic, BOOL bDraw )
{
Undraw();
int icont = GetContour( ic );
int istart = GetContourStart( icont );
int iend = GetContourEnd( icont );
BOOL bClosed = icont < GetNumContours()-1 || GetClosed();
if( !bClosed )
{
// open contour, must be last contour
corner.erase( corner.begin() + ic );
if( ic != istart )
side_style.erase( side_style.begin() + ic-1 );
}
else
{
// closed contour
corner.erase( corner.begin() + ic );
side_style.erase( side_style.begin() + ic );
if( ic == iend )
corner[ic-1].end_contour = TRUE;
}
if( bClosed && GetContourSize(icont) < 3 )
{
// delete the entire contour
RemoveContour( icont );
}
if( bDraw )
Draw();
}
void CPolyLine::RemoveContour( int icont )
{
Undraw();
int istart = GetContourStart( icont );
int iend = GetContourEnd( icont );
if( icont == 0 && GetNumContours() == 1 )
{
// remove the only contour
ASSERT(0);
}
else if( icont == GetNumContours()-1 )
{
// remove last contour
corner.erase( corner.begin() + icont, corner.end() );
side_style.erase( side_style.begin() + icont, side_style.end() );
}
else
{
// remove closed contour
for( int ic=iend; ic>=istart; ic-- )
{
corner.erase( corner.begin() + ic );
side_style.erase( side_style.begin() + ic );
}
}
Draw();
}
/** Function InsertCorner
* insert a new corner between two existing corners
* @param ic = index for the insertion point: the corner is inserted AFTER ic
* @param x, y = coordinates corner to insert
*/
void CPolyLine::InsertCorner( int ic, int x, int y )
{
Undraw();
if ( (unsigned)(ic) >= corner.size() )
{
corner.push_back( CPolyPt(x,y) );
side_style.push_back( STRAIGHT );
}
else
{
corner.insert( corner.begin() + ic + 1, CPolyPt(x,y) );
side_style.insert( side_style.begin() + ic + 1, STRAIGHT );
}
if( (unsigned)(ic+1) < corner.size() )
{
if( corner[ic].end_contour )
{
corner[ic+1].end_contour = TRUE;
corner[ic].end_contour = FALSE;
}
}
Draw();
}
// undraw polyline by removing all graphic elements from display list
//
void CPolyLine::Undraw()
{
if( m_dlist && bDrawn )
{
// remove display elements, if present
for( unsigned i=0; i<dl_side.size(); i++ )
m_dlist->Remove( dl_side[i] );
for( unsigned i=0; i<dl_side_sel.size(); i++ )
m_dlist->Remove( dl_side_sel[i] );
for( unsigned i=0; i<dl_corner_sel.size(); i++ )
m_dlist->Remove( dl_corner_sel[i] );
// remove pointers
dl_side.clear();
dl_side_sel.clear();
dl_corner_sel.clear();
}
m_HatchLines.clear();
bDrawn = FALSE;
}
// draw polyline by adding all graphics to display list
// if side style is ARC_CW or ARC_CCW but endpoints are not angled,
// convert to STRAIGHT
//
void CPolyLine::Draw( CDisplayList * dl )
{
// first, undraw if necessary
if( bDrawn )
Undraw();
// use new display list if provided
if( dl )
m_dlist = dl;
#if 0
int i_start_contour = 0;
if( m_dlist )
{
// set up std::vectors
dl_side.SetSize( corner.size() );
if( m_sel_box )
{
dl_side_sel.SetSize( corner.size() );
dl_corner_sel.SetSize( corner.size() );
}
else
{
dl_side_sel.clear();
dl_corner_sel.clear();
}
// now draw elements
for( int ic=0; ic<corner.size(); ic++ )
{
m_id.ii = ic;
int xi = corner[ic].x;
int yi = corner[ic].y;
int xf, yf;
if( corner[ic].end_contour == FALSE && ic < corner.size()-1 )
{
xf = corner[ic+1].x;
yf = corner[ic+1].y;
}
else
{
xf = corner[i_start_contour].x;
yf = corner[i_start_contour].y;
i_start_contour = ic+1;
}
// draw
if( m_sel_box )
{
m_id.sst = ID_SEL_CORNER;
dl_corner_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, DL_HOLLOW_RECT,
1, 0, 0, xi-m_sel_box, yi-m_sel_box,
xi+m_sel_box, yi+m_sel_box, 0, 0 );
}
if( ic<(corner.size()-1) || corner[ic].end_contour )
{
// draw side
if( xi == xf || yi == yf )
{
// if endpoints not angled, make side STRAIGHT
side_style[ic] = STRAIGHT;
}
int g_type = DL_LINE;
if( side_style[ic] == STRAIGHT )
g_type = DL_LINE;
else if( side_style[ic] == ARC_CW )
g_type = DL_ARC_CW;
else if( side_style[ic] == ARC_CCW )
g_type = DL_ARC_CCW;
m_id.sst = ID_SIDE;
dl_side[ic] = m_dlist->Add( m_id, m_ptr, m_layer, g_type,
1, m_w, 0, xi, yi, xf, yf, 0, 0 );
if( m_sel_box )
{
m_id.sst = ID_SEL_SIDE;
dl_side_sel[ic] = m_dlist->AddSelector( m_id, m_ptr, m_layer, g_type,
1, m_w, 0, xi, yi, xf, yf, 0, 0 );
}
}
}
// if( m_HatchStyle )
// Hatch();
}
#endif
Hatch();
bDrawn = TRUE;
}
// start dragging new corner to be inserted into side, make side and hatching invisible
//
void CPolyLine::StartDraggingToInsertCorner( CDC * pDC, int ic, int x, int y )
{
if( !m_dlist )
ASSERT(0);
int icont = GetContour( ic );
int istart = GetContourStart( icont );
int iend = GetContourEnd( icont );
int post_c;
if( ic == iend )
post_c = istart;
else
post_c = ic + 1;
int xi = corner[ic].x;
int yi = corner[ic].y;
int xf = corner[post_c].x;
int yf = corner[post_c].y;
m_dlist->StartDraggingLineVertex( pDC, x, y, xi, yi, xf, yf,
LAY_SELECTION, LAY_SELECTION, 1, 1, DSS_STRAIGHT, DSS_STRAIGHT,
0, 0, 0, 0, 1 );
m_dlist->CancelHighLight();
m_dlist->Set_visible( dl_side[ic], 0 );
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/
}
// cancel dragging inserted corner, make side and hatching visible again
//
void CPolyLine::CancelDraggingToInsertCorner( int ic )
{
if( !m_dlist )
ASSERT(0);
int post_c;
if( ic == (int)(corner.size()-1) )
post_c = 0;
else
post_c = ic + 1;
m_dlist->StopDragging();
/* m_dlist->Set_visible( dl_side[ic], 1 );
for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 1 );
*/
}
// start dragging corner to new position, make adjacent sides and hatching invisible
//
void CPolyLine::StartDraggingToMoveCorner( CDC * pDC, int ic, int x, int y )
{
if( !m_dlist )
ASSERT(0);
// see if corner is the first or last corner of an open contour
int icont = GetContour( ic );
int istart = GetContourStart( icont );
int iend = GetContourEnd( icont );
if( !GetClosed()
&& icont == GetNumContours() - 1
&& (ic == istart || ic == iend) )
{
// yes
int style, xi, yi, iside;
if( ic == istart )
{
// first corner
iside = ic;
xi = GetX( ic+1 );
yi = GetY( ic+1 );
style = GetSideStyle( iside );
// reverse arc since we are drawing from corner 1 to 0
if( style == CPolyLine::ARC_CW )
style = CPolyLine::ARC_CCW;
else if( style == CPolyLine::ARC_CCW )
style = CPolyLine::ARC_CW;
}
else
{
// last corner
iside = ic - 1;
xi = GetX( ic-1 );
yi = GetY( ic-1);
style = GetSideStyle( iside );
}
m_dlist->StartDraggingArc( pDC, style, GetX(ic), GetY(ic), xi, yi, LAY_SELECTION, 1, 1 );
m_dlist->CancelHighLight();
m_dlist->Set_visible( dl_side[iside], 0 );
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/
}
else
{
// no
// get indexes for preceding and following corners
int pre_c, post_c;
int poly_side_style1, poly_side_style2;
int style1, style2;
if( ic == istart )
{
pre_c = iend;
post_c = istart+1;
poly_side_style1 = side_style[iend];
poly_side_style2 = side_style[istart];
}
else if( ic == iend )
{
// last side
pre_c = ic-1;
post_c = istart;
poly_side_style1 = side_style[ic-1];
poly_side_style2 = side_style[ic];
}
else
{
pre_c = ic-1;
post_c = ic+1;
poly_side_style1 = side_style[ic-1];
poly_side_style2 = side_style[ic];
}
if( poly_side_style1 == STRAIGHT )
style1 = DSS_STRAIGHT;
else if( poly_side_style1 == ARC_CW )
style1 = DSS_ARC_CW;
else if( poly_side_style1 == ARC_CCW )
style1 = DSS_ARC_CCW;
if( poly_side_style2 == STRAIGHT )
style2 = DSS_STRAIGHT;
else if( poly_side_style2 == ARC_CW )
style2 = DSS_ARC_CW;
else if( poly_side_style2 == ARC_CCW )
style2 = DSS_ARC_CCW;
int xi = corner[pre_c].x;
int yi = corner[pre_c].y;
int xf = corner[post_c].x;
int yf = corner[post_c].y;
m_dlist->StartDraggingLineVertex( pDC, x, y, xi, yi, xf, yf,
LAY_SELECTION, LAY_SELECTION, 1, 1, style1, style2,
0, 0, 0, 0, 1 );
m_dlist->CancelHighLight();
m_dlist->Set_visible( dl_side[pre_c], 0 );
m_dlist->Set_visible( dl_side[ic], 0 );
/* for( int ih=0; ih<m_nhatch; ih++ )
m_dlist->Set_visible( dl_hatch[ih], 0 );
*/ }
}
// cancel dragging corner to new position, make sides and hatching visible again
//
// highlight side by drawing line over it
//
void CPolyLine::HighlightSide( int is )
{
if( !m_dlist )
ASSERT(0);
if( GetClosed() && is >= (int)corner.size() )
return;
if( !GetClosed() && is >= (int)(corner.size()-1) )
return;
int style;
if( side_style[is] == CPolyLine::STRAIGHT )
style = DL_LINE;
else if( side_style[is] == CPolyLine::ARC_CW )
style = DL_ARC_CW;
else if( side_style[is] == CPolyLine::ARC_CCW )
style = DL_ARC_CCW;
m_dlist->HighLight( style,
m_dlist->Get_x( dl_side_sel[is] ),
m_dlist->Get_y( dl_side_sel[is] ),
m_dlist->Get_xf( dl_side_sel[is] ),
m_dlist->Get_yf( dl_side_sel[is] ),
m_dlist->Get_w( dl_side_sel[is]) );
}
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;
r.top += m_Width/2;
return r;
}
CRect CPolyLine::GetCornerBounds()
{
CRect r;
r.left = r.bottom = INT_MAX;
r.right = r.top = INT_MIN;
for( unsigned i=0; i<corner.size(); i++ )
{
r.left = min( r.left, corner[i].x );
r.right = max( r.right, corner[i].x );
r.bottom = min( r.bottom, corner[i].y );
r.top = max( r.top, corner[i].y );
}
return r;
}
CRect CPolyLine::GetCornerBounds( int icont )
{
CRect r;
r.left = r.bottom = INT_MAX;
r.right = r.top = INT_MIN;
int istart = GetContourStart( icont );
int iend = GetContourEnd( icont );
for( int i=istart; i<=iend; i++ )
{
r.left = min( r.left, corner[i].x );
r.right = max( r.right, corner[i].x );
r.bottom = min( r.bottom, corner[i].y );
r.top = max( r.top, corner[i].y );
}
return r;
}
int CPolyLine::GetNumCorners()
{
return corner.size();
}
int CPolyLine::GetNumSides()
{
if( GetClosed() )
return corner.size();
else
return corner.size()-1;
}
int CPolyLine::GetW()
{
return m_Width;
}
int CPolyLine::GetSelBoxSize()
{
return m_sel_box;
}
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 )
return 0;
int ncont = 0;
for( unsigned i=0; i<corner.size(); i++ )
{
if( corner[i].end_contour )
{
ncont++;
if( ncont == icont )
return i+1;
}
}
ASSERT(0);
return 0;
}
int CPolyLine::GetContourEnd( int icont )
{
if( icont < 0 )
return 0;
if( icont == GetNumContours()-1 )
return corner.size()-1;
int ncont = 0;
for( unsigned i=0; i<corner.size(); i++ )
{
if( corner[i].end_contour )
{
if( ncont == icont )
return i;
ncont++;
}
}
ASSERT(0);
return 0;
}
int CPolyLine::GetContourSize( int icont )
{
return GetContourEnd(icont) - GetContourStart(icont) + 1;
}
void CPolyLine::SetSideStyle( int is, int style )
{
Undraw();
CPoint p1, p2;
if( is == (int)(corner.size()-1) )
{
p1.x = corner[corner.size()-1].x;
p1.y = corner[corner.size()-1].y;
p2.x = corner[0].x;
p2.y = corner[0].y;
}
else
{
p1.x = corner[is].x;
p1.y = corner[is].y;
p2.x = corner[is+1].x;
p2.y = corner[is+1].y;
}
if( p1.x == p2.x || p1.y == p2.y )
side_style[is] = STRAIGHT;
else
side_style[is] = style;
Draw();
}
int CPolyLine::GetSideStyle( int is )
{
return side_style[is];
}
int CPolyLine::GetClosed()
{
if( corner.size() == 0 )
return 0;
else
return corner[corner.size()-1].end_contour;
}
// draw hatch lines
//
void CPolyLine::Hatch()
{
m_HatchLines.clear();
if( m_HatchStyle == NO_HATCH )
{
return;
}
int layer = m_layer;
// if( /*m_dlist && */GetClosed() )
{
enum {
MAXPTS = 100,
MAXLINES = 1000
};
int xx[MAXPTS], yy[MAXPTS];
// define range for hatch lines
int min_x = corner[0].x;
int max_x = corner[0].x;
int min_y = corner[0].y;
int max_y = corner[0].y;
for( unsigned ic = 1; ic < corner.size(); ic++ )
{
if( corner[ic].x < min_x )
min_x = corner[ic].x;
if( corner[ic].x > max_x )
max_x = corner[ic].x;
if( corner[ic].y < min_y )
min_y = corner[ic].y;
if( corner[ic].y > max_y )
max_y = corner[ic].y;
}
int slope_flag = (layer & 1) ? 1 : -1; // 1 or -1
double slope = 0.707106*slope_flag;
int spacing;
if( m_HatchStyle == DIAGONAL_EDGE )
spacing = 10*PCBU_PER_MIL;
else
spacing = 50*PCBU_PER_MIL;
int max_a, min_a;
if( slope_flag == 1 )
{
max_a = (int)(max_y - slope*min_x);
min_a = (int)(min_y - slope*max_x);
}
else
{
max_a = (int)(max_y - slope*max_x);
min_a = (int)(min_y - slope*min_x);
}
min_a = (min_a/spacing)*spacing;
int offset;
if( layer < (LAY_TOP_COPPER+2) )
offset = 0;
else if( layer < (LAY_TOP_COPPER+4) )
offset = spacing/2;
else if( layer < (LAY_TOP_COPPER+6) )
offset = spacing/4;
else if( layer < (LAY_TOP_COPPER+8) )
offset = 3*spacing/4;
else if( layer < (LAY_TOP_COPPER+10) )
offset = 1*spacing/8;
else if( layer < (LAY_TOP_COPPER+12) )
offset = 3*spacing/8;
else if( layer < (LAY_TOP_COPPER+14) )
offset = 5*spacing/8;
else if( layer < (LAY_TOP_COPPER+16) )
offset = 7*spacing/8;
else
ASSERT(0);
min_a += offset;
// now calculate and draw hatch lines
int nc = corner.size();
// loop through hatch lines
for( int a=min_a; a<max_a; a+=spacing )
{
// get intersection points for this hatch line
int nloops = 0;
int npts;
// make this a loop in case my homebrew hatching algorithm screws up
do
{
npts = 0;
int i_start_contour = 0;
for( int ic=0; ic<nc; ic++ )
{
double x, y, x2, y2;
int ok;
if( corner[ic].end_contour )
{
ok = FindLineSegmentIntersection( a, slope,
corner[ic].x, corner[ic].y,
corner[i_start_contour].x, corner[i_start_contour].y,
side_style[ic],
&x, &y, &x2, &y2 );
i_start_contour = ic + 1;
}
else
{
ok = FindLineSegmentIntersection( a, slope,
corner[ic].x, corner[ic].y,
corner[ic+1].x, corner[ic+1].y,
side_style[ic],
&x, &y, &x2, &y2 );
}
if( ok )
{
xx[npts] = (int)x;
yy[npts] = (int)y;
npts++;
ASSERT( npts<MAXPTS ); // overflow
}
if( ok == 2 )
{
xx[npts] = (int)x2;
yy[npts] = (int)y2;
npts++;
ASSERT( npts<MAXPTS ); // overflow
}
}
nloops++;
a += PCBU_PER_MIL/100;
} while( npts%2 != 0 && nloops < 3 );
ASSERT( npts%2==0 ); // odd number of intersection points, error
// sort points in order of descending x (if more than 2)
if( npts>2 )
{
for( int istart=0; istart<(npts-1); istart++ )
{
int max_x = INT_MIN;
int imax;
for( int i=istart; i<npts; i++ )
{
if( xx[i] > max_x )
{
max_x = xx[i];
imax = i;
}
}
int temp = xx[istart];
xx[istart] = xx[imax];
xx[imax] = temp;
temp = yy[istart];
yy[istart] = yy[imax];
yy[imax] = temp;
}
}
// draw lines
for( int ip=0; ip<npts; ip+=2 )
{
double dx = xx[ip+1] - xx[ip];
if( m_HatchStyle == DIAGONAL_FULL || fabs(dx) < 40*NM_PER_MIL )
{
m_HatchLines.push_back(CSegment(xx[ip], yy[ip], xx[ip+1], yy[ip+1]) );
}
else
{
double dy = yy[ip+1] - yy[ip];
double slope = dy/dx;
if( dx > 0 )
dx = 20*NM_PER_MIL;
else
dx = -20*NM_PER_MIL;
double x1 = xx[ip] + dx;
double x2 = xx[ip+1] - dx;
double y1 = yy[ip] + dx*slope;
double y2 = yy[ip+1] - dx*slope;
m_HatchLines.push_back(CSegment(xx[ip], yy[ip], to_int(x1), to_int(y1)) );
m_HatchLines.push_back(CSegment(xx[ip+1], yy[ip+1], to_int(x2), to_int(y2)) );
}
}
} // end for
}
}
// test to see if a point is inside polyline
//
BOOL CPolyLine::TestPointInside( int x, int y )
{
enum { MAXPTS = 100 };
if( !GetClosed() )
ASSERT(0);
// define line passing through (x,y), with slope = 2/3;
// get intersection points
double xx[MAXPTS], yy[MAXPTS];
double slope = (double)2.0/3.0;
double a = y - slope*x;
int nloops = 0;
int npts;
// make this a loop so if my homebrew algorithm screws up, we try it again
do
{
// now find all intersection points of line with polyline sides
npts = 0;
for( int icont=0; icont<GetNumContours(); icont++ )
{
int istart = GetContourStart( icont );
int iend = GetContourEnd( icont );
for( int ic=istart; ic<=iend; ic++ )
{
double x, y, x2, y2;
int ok;
if( ic == istart )
ok = FindLineSegmentIntersection( a, slope,
corner[iend].x, corner[iend].y,
corner[istart].x, corner[istart].y,
side_style[corner.size()-1],
&x, &y, &x2, &y2 );
else
ok = FindLineSegmentIntersection( a, slope,
corner[ic-1].x, corner[ic-1].y,
corner[ic].x, corner[ic].y,
side_style[ic-1],
&x, &y, &x2, &y2 );
if( ok )
{
xx[npts] = (int)x;
yy[npts] = (int)y;
npts++;
ASSERT( npts<MAXPTS ); // overflow
}
if( ok == 2 )
{
xx[npts] = (int)x2;
yy[npts] = (int)y2;
npts++;
ASSERT( npts<MAXPTS ); // overflow
}
}
}
nloops++;
a += PCBU_PER_MIL/100;
} while( npts%2 != 0 && nloops < 3 );
ASSERT( npts%2==0 ); // odd number of intersection points, error
// count intersection points to right of (x,y), if odd (x,y) is inside polyline
int ncount = 0;
for( int ip=0; ip<npts; ip++ )
{
if( xx[ip] == x && yy[ip] == y )
return FALSE; // (x,y) is on a side, call it outside
else if( xx[ip] > x )
ncount++;
}
if( ncount%2 )
return TRUE;
else
return FALSE;
}
// test to see if a point is inside polyline contour
//
BOOL CPolyLine::TestPointInsideContour( int icont, int x, int y )
{
if( icont >= GetNumContours() )
return FALSE;
enum { MAXPTS = 100 };
if( !GetClosed() )
ASSERT(0);
// define line passing through (x,y), with slope = 2/3;
// get intersection points
double xx[MAXPTS], yy[MAXPTS];
double slope = (double)2.0/3.0;
double a = y - slope*x;
int nloops = 0;
int npts;
// make this a loop so if my homebrew algorithm screws up, we try it again
do
{
// now find all intersection points of line with polyline sides
npts = 0;
int istart = GetContourStart( icont );
int iend = GetContourEnd( icont );
for( int ic=istart; ic<=iend; ic++ )
{
double x, y, x2, y2;
int ok;
if( ic == istart )
ok = FindLineSegmentIntersection( a, slope,
corner[iend].x, corner[iend].y,
corner[istart].x, corner[istart].y,
side_style[corner.size()-1],
&x, &y, &x2, &y2 );
else
ok = FindLineSegmentIntersection( a, slope,
corner[ic-1].x, corner[ic-1].y,
corner[ic].x, corner[ic].y,
side_style[ic-1],
&x, &y, &x2, &y2 );
if( ok )
{
xx[npts] = (int)x;
yy[npts] = (int)y;
npts++;
ASSERT( npts<MAXPTS ); // overflow
}
if( ok == 2 )
{
xx[npts] = (int)x2;
yy[npts] = (int)y2;
npts++;
ASSERT( npts<MAXPTS ); // overflow
}
}
nloops++;
a += PCBU_PER_MIL/100;
} while( npts%2 != 0 && nloops < 3 );
ASSERT( npts%2==0 ); // odd number of intersection points, error
// count intersection points to right of (x,y), if odd (x,y) is inside polyline
int ncount = 0;
for( int ip=0; ip<npts; ip++ )
{
if( xx[ip] == x && yy[ip] == y )
return FALSE; // (x,y) is on a side, call it outside
else if( xx[ip] > x )
ncount++;
}
if( ncount%2 )
return TRUE;
else
return FALSE;
}
// Test for intersection of sides
//
int CPolyLine::TestIntersection( CPolyLine * poly )
{
if( !GetClosed() )
ASSERT(0);
if( !poly->GetClosed() )
ASSERT(0);
for( int ic=0; ic<GetNumContours(); ic++ )
{
int istart = GetContourStart(ic);
int iend = GetContourEnd(ic);
for( int is=istart; is<=iend; is++ )
{
int xf, yf;
if( is < GetContourEnd(ic) )
{
xf = GetX(is+1);
yf = GetY(is+1);
}
else
{
xf = GetX(istart);
yf = GetY(istart);
}
for( int ic2=0; ic2<poly->GetNumContours(); ic2++ )
{
int istart2 = poly->GetContourStart(ic2);
int iend2 = poly->GetContourEnd(ic2);
for( int is2=istart2; is2<=iend2; is2++ )
{
int xf2, yf2;
if( is2 < poly->GetContourEnd(ic2) )
{
xf2 = poly->GetX(is2+1);
yf2 = poly->GetY(is2+1);
}
else
{
xf2 = poly->GetX(istart2);
yf2 = poly->GetY(istart2);
}
// test for intersection between side and side2
}
}
}
}
return 0;
}
// set selection box size
//
void CPolyLine::SetSelBoxSize( int sel_box )
{
// Undraw();
m_sel_box = sel_box;
// Draw();
}
// set pointer to display list, and draw into display list
//
void CPolyLine::SetDisplayList( CDisplayList * dl )
{
if( m_dlist )
Undraw();
m_dlist = dl;
if( m_dlist )
Draw();
}
// copy data from another poly, but don't draw it
//
void CPolyLine::Copy( CPolyLine * src )
{
Undraw();
m_dlist = src->m_dlist;
m_sel_box = src->m_sel_box;
// copy corners
for( unsigned i=0; i< src->corner.size(); i++ )
corner.push_back(src->corner[i]);
// copy side styles
int nsides = src->GetNumSides();
side_style.SetSize(nsides);
for( int i=0; i<nsides; i++ )
side_style[i] = src->side_style[i];
// don't copy the Gpc_poly, just clear the old one
FreeGpcPoly();
}
void CPolyLine::MoveOrigin( int x_off, int y_off )
{
Undraw();
for( int ic=0; ic < GetNumCorners(); ic++ )
{
SetX( ic, GetX(ic) + x_off );
SetY( ic, GetY(ic) + y_off );
}
Draw();
}
// Set various parameters:
// 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::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 )
{
CPolyLine * poly = new CPolyLine;
int dx = l/2;
int dy = w/2;
if( angle%180 == 90 )
{
dx = w/2;
dy = l/2;
}
if( type == PAD_ROUND )
{
poly->Start( 0, 0, 0, x-dx, y, 0 );
poly->AppendCorner( x, y+dy, ARC_CW, 0 );
poly->AppendCorner( x+dx, y, ARC_CW, 0 );
poly->AppendCorner( x, y-dy, ARC_CW, 0 );
poly->Close( ARC_CW );
}
return poly;
}
// Add cutout for a pad
// Convert arcs to multiple straight lines
// Do NOT draw or undraw
//
void CPolyLine::AddContourForPadClearance( int type, int x, int y, int w,
int l, int r, int angle, int fill_clearance,
int hole_w, int hole_clearance, BOOL bThermal, int spoke_w )
{
int dx = l/2;
int dy = w/2;
if( angle%180 == 90 )
{
dx = w/2;
dy = l/2;
}
int x_clearance = max( fill_clearance, hole_clearance+hole_w/2-dx);
int y_clearance = max( fill_clearance, hole_clearance+hole_w/2-dy);
dx += x_clearance;
dy += y_clearance;
if( !bThermal )
{
// normal clearance
if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) )
{
AppendCorner( x-dx, y, ARC_CW, 0 );
AppendCorner( x, y+dy, ARC_CW, 0 );
AppendCorner( x+dx, y, ARC_CW, 0 );
AppendCorner( x, y-dy, ARC_CW, 0 );
Close( ARC_CW );
}
else if( type == PAD_SQUARE || type == PAD_RECT
|| type == PAD_RRECT || type == PAD_OVAL )
{
AppendCorner( x-dx, y-dy, STRAIGHT, 0 );
AppendCorner( x+dx, y-dy, STRAIGHT, 0 );
AppendCorner( x+dx, y+dy, STRAIGHT, 0 );
AppendCorner( x-dx, y+dy, STRAIGHT, 0 );
Close( STRAIGHT );
}
}
else
{
// thermal relief
if( type == PAD_ROUND || (type == PAD_NONE && hole_w > 0) )
{
// draw 4 "wedges"
double r = max(w/2 + fill_clearance, hole_w/2 + hole_clearance);
double start_angle = asin( spoke_w/(2.0*r) );
double th1, th2, corner_x, corner_y;
for( int i=0; i<4; i++ )
{
if( i == 0 )
{
corner_x = spoke_w/2;
corner_y = spoke_w/2;
th1 = start_angle;
th2 = pi/2.0 - start_angle;
}
else if( i == 1 )
{
corner_x = -spoke_w/2;
corner_y = spoke_w/2;
th1 = pi/2.0 + start_angle;
th2 = pi - start_angle;
}
else if( i == 2 )
{
corner_x = -spoke_w/2;
corner_y = -spoke_w/2;
th1 = -pi + start_angle;
th2 = -pi/2.0 - start_angle;
}
else if( i == 3 )
{
corner_x = spoke_w/2;
corner_y = -spoke_w/2;
th1 = -pi/2.0 + start_angle;
th2 = -start_angle;
}
AppendCorner( to_int(x+corner_x), to_int(y+corner_y), STRAIGHT, 0 );
AppendCorner( to_int(x+r*cos(th1)), to_int(y+r*sin(th1)), STRAIGHT, 0 );
AppendCorner( to_int(x+r*cos(th2)), to_int(y+r*sin(th2)), ARC_CCW, 0 );
Close( STRAIGHT );
}
}
else if( type == PAD_SQUARE || type == PAD_RECT
|| type == PAD_RRECT || type == PAD_OVAL )
{
// draw 4 rectangles
int xL = x - dx;
int xR = x - spoke_w/2;
int yB = y - dy;
int yT = y - spoke_w/2;
AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT );
xL = x + spoke_w/2;
xR = x + dx;
AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT );
xL = x - dx;
xR = x - spoke_w/2;
yB = y + spoke_w/2;
yT = y + dy;
AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT );
xL = x + spoke_w/2;
xR = x + dx;
AppendCorner( xL, yB, STRAIGHT, 0 );
AppendCorner( xR, yB, STRAIGHT, 0 );
AppendCorner( xR, yT, STRAIGHT, 0 );
AppendCorner( xL, yT, STRAIGHT, 0 );
Close( STRAIGHT );
}
}
return;
}
void CPolyLine::AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num )
{
// get radius
double r = sqrt( (double)(xi-xc)*(xi-xc) + (double)(yi-yc)*(yi-yc) );
// get angles of start and finish
double th_i = atan2( (double)yi-yc, (double)xi-xc );
double th_f = atan2( (double)yf-yc, (double)xf-xc );
double th_d = (th_f - th_i)/(num-1);
double theta = th_i;
// generate arc
for( int ic=0; ic<num; ic++ )
{
int x = to_int(xc + r*cos(theta));
int y = to_int(yc + r*sin(theta));
AppendCorner( x, y, STRAIGHT, 0 );
theta += th_d;
}
Close( STRAIGHT );
}
void CPolyLine::ClipGpcPolygon( gpc_op op, CPolyLine * clip_poly )
{
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;
}
// PolyLine.h ... definition of CPolyLine class
//
// A polyline contains one or more contours, where each contour
// is defined by a list of corners and side-styles
// There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of
// each contour.
//
// When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper.
//
// If a CDisplayList pointer is provided, the polyline can draw itself
#ifndef POLYLINE_H
#define POLYLINE_H
#include <vector>
#include "defs-macros.h"
#include "GenericPolygonClipperLibrary.h"
#include "php_polygon.h"
#include "php_polygon_vertex.h"
#include "PolyLine2Kicad.h"
#include "freepcb_ids.h"
#include "freepcbDisplayList.h"
#include "math_for_graphics.h"
class CSegment {
public:
int xi, yi, xf, yf;
CSegment() {};
CSegment(int x0, int y0, int x1, int y1) {
xi = x0; yi = y0; xf = x1; yf = y1; }
};
class CArc {
public:
enum{ MAX_STEP = 50*25400 }; // max step is 20 mils
enum{ MIN_STEPS = 18 }; // min step is 5 degrees
int style;
int xi, yi, xf, yf;
int n_steps; // number of straight-line segments in gpc_poly
BOOL bFound;
};
class CPolyPt
{
public:
CPolyPt( int qx=0, int qy=0, BOOL qf=FALSE )
{ x=qx; y=qy; end_contour=qf; utility = 0; };
int x;
int y;
BOOL end_contour;
int utility;
};
class CPolyLine
{
public:
enum { STRAIGHT, ARC_CW, ARC_CCW }; // side styles
enum { NO_HATCH, DIAGONAL_FULL, DIAGONAL_EDGE }; // hatch styles
enum { DEF_SIZE = 50, DEF_ADD = 50 }; // number of array elements to add at a time
// constructors/destructor
CPolyLine( CDisplayList * dl );
CPolyLine();
~CPolyLine();
// functions for modifying polyline
void Start( int layer, int w, int sel_box, int x, int y,
int hatch );
void AppendCorner( int x, int y, int style = STRAIGHT, BOOL bDraw=TRUE );
void InsertCorner( int ic, int x, int y );
void DeleteCorner( int ic, BOOL bDraw=TRUE );
void MoveCorner( int ic, int x, int y );
void Close( int style = STRAIGHT, BOOL bDraw=TRUE );
void RemoveContour( int icont );
// drawing functions
void HighlightSide( int is );
void HighlightCorner( int ic );
void StartDraggingToInsertCorner( CDC * pDC, int ic, int x, int y);
void StartDraggingToMoveCorner( CDC * pDC, int ic, int x, int y);
void CancelDraggingToInsertCorner( int ic );
void CancelDraggingToMoveCorner( int ic );
void Undraw();
void Draw( CDisplayList * dl = NULL );
void Hatch();
void MakeVisible( BOOL visible = TRUE );
void MoveOrigin( int x_off, int y_off );
// misc. functions
CRect GetBounds();
CRect GetCornerBounds();
CRect GetCornerBounds( int icont );
void Copy( CPolyLine * src );
BOOL TestPointInside( int x, int y );
BOOL TestPointInsideContour( int icont, int x, int y );
int TestIntersection( CPolyLine * poly );
void AppendArc( int xi, int yi, int xf, int yf, int xc, int yc, int num );
// access functions
int GetNumCorners();
int GetNumSides();
int GetClosed();
int GetNumContours();
int GetContour( int ic );
int GetContourStart( int icont );
int GetContourEnd( int icont );
int GetContourSize( int icont );
int GetX( int ic );
int GetY( int ic );
int GetEndContour( int ic );
int GetUtility( int ic ){ return corner[ic].utility; };
void SetUtility( int ic, int utility ){ corner[ic].utility = utility; };
int GetW();
int GetSideStyle( int is );
id GetId();
int GetSelBoxSize();
CDisplayList * GetDisplayList(){ return m_dlist; };
int GetHatch(){ return m_HatchStyle; }
void SetHatch( int hatch ){ Undraw(); m_HatchStyle = hatch; Draw(); };
void SetX( int ic, int x );
void SetY( int ic, int y );
void SetEndContour( int ic, BOOL end_contour );
// void SetLayer( int layer );
void SetW( int w );
void SetSideStyle( int is, int style );
void SetSelBoxSize( int sel_box );
void SetDisplayList( CDisplayList * dl );
// 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 );
// PHP functions
int MakePhpPoly();
void FreePhpPoly();
void ClipPhpPolygon( int php_op, CPolyLine * poly );
private:
CDisplayList * m_dlist; // display list
int m_layer; // layer to draw on
int m_Width; // line width
int m_sel_box; // corner selection box width/2
public:
std::vector <CPolyPt> corner; // array of points for corners
std::vector <int> side_style; // array of styles for sides
private:
std::vector <dl_element*> dl_side; // graphic elements
std::vector <dl_element*> dl_side_sel;
std::vector <dl_element*> dl_corner_sel;
public:
int m_HatchStyle; // hatch style, see enum above
std::vector <CSegment> m_HatchLines; // hatch lines
private:
gpc_polygon * m_gpc_poly; // polygon in gpc format
polygon * m_php_poly;
BOOL bDrawn;
};
#endif // #ifndef POLYLINE_H
// PolyLine.h ... definition of CPolyLine class
//
// A polyline contains one or more contours, where each contour
// is defined by a list of corners and side-styles
// There may be multiple contours in a polyline.
// The last contour may be open or closed, any others must be closed.
// All of the corners and side-styles are concatenated into 2 arrays,
// separated by setting the end_contour flag of the last corner of
// each contour.
//
// When used for copper areas, the first contour is the outer edge
// of the area, subsequent ones are "holes" in the copper.
//
// If a CDisplayList pointer is provided, the polyline can draw itself
#ifndef POLYLINE2KICAD_H
#define POLYLINE2KICAD_H
#define PCBU_PER_MIL 10
#define MAX_LAYERS 32
#define NM_PER_MIL 10 // 25400
// pad shapes
enum
{
PAD_NONE = 0,
PAD_ROUND,
PAD_SQUARE,
PAD_RECT,
PAD_RRECT,
PAD_OVAL,
PAD_OCTAGON
};
/*
enum
{
// visible layers
LAY_SELECTION = 0,
LAY_BACKGND,
LAY_VISIBLE_GRID,
LAY_HILITE,
LAY_DRC_ERROR,
LAY_BOARD_OUTLINE,
LAY_RAT_LINE,
LAY_SILK_TOP,
LAY_SILK_BOTTOM,
LAY_SM_TOP,
LAY_SM_BOTTOM,
LAY_PAD_THRU,
LAY_TOP_COPPER,
LAY_BOTTOM_COPPER,
// invisible layers
LAY_MASK_TOP = -100,
LAY_MASK_BOTTOM = -101,
LAY_PASTE_TOP = -102,
LAY_PASTE_BOTTOM = -103
};
*/
#define LAY_SELECTION 0
#define LAY_TOP_COPPER 0
#define CDC wxDC
class wxDC;
#if 0
class dl_element;
class CDisplayList {
public:
void Set_visible(void*, int) {};
int Get_x(void) { return 0;};
int Get_y(void) { return 0;};
void StopDragging(void) {};
void CancelHighLight(void) {};
void StartDraggingLineVertex(...) {};
void Add() {};
};
#endif
class CRect {
public:
int left, right, top, bottom;
};
class CPoint {
public:
int x, y;
public:
CPoint(void) { x = y = 0;};
CPoint(int i, int j) { x = i; y = j;};
};
#endif // #ifndef POLYLINE2KICAD_H
/* stuff for class CDisplayList */
#include "PolyLine.h"
dl_element * CDisplayList::Add( id id, void * ptr, int glayer, int gtype, int visible,
int w, int holew, int x, int y, int xf, int yf, int xo, int yo,
int radius, int orig_layer )
{
return NULL;
}
dl_element * CDisplayList::AddSelector( id id, void * ptr, int glayer, int gtype, int visible,
int w, int holew, int x, int y, int xf, int yf, int xo, int yo, int radius )
{
return NULL;
}
void CDisplayList::Set_visible( dl_element * el, int visible )
{
}
int CDisplayList::StopDragging()
{
return 0;
}
int CDisplayList::CancelHighLight()
{
return 0;
}
void CDisplayList::Set_id( dl_element * el, id * id )
{
}
id CDisplayList::Remove( dl_element * element )
{
return 0;
}
int CDisplayList::Get_w( dl_element * el )
{
return 0;
}
int CDisplayList::Get_x( dl_element * el )
{
return 0;
}
int CDisplayList::Get_y( dl_element * el )
{
return 0;
}
int CDisplayList::Get_xf( dl_element * el )
{
return 0;
}
int CDisplayList::Get_yf( dl_element * el )
{
return 0;
}
int CDisplayList::HighLight( int gtype, int x, int y, int xf, int yf, int w, int orig_layer )
{
return 0;
}
int CDisplayList::StartDraggingLineVertex( CDC * pDC, int x, int y, int xi, int yi,
int xf, int yf,
int layer1, int layer2, int w1, int w2,
int style1, int style2,
int layer_no_via, int via_w, int via_holew, int dir,
int crosshair )
{
return 0;
}
int CDisplayList::StartDraggingArc( CDC * pDC, int style, int x, int y, int xi, int yi,
int layer, int w, int crosshair )
{
return 0;
}
// DisplayList.h : header file for CDisplayList class
//
#ifndef FP_DISPLAY_LIST_H
#define FP_DISPLAY_LIST_H
//#define DL_MAX_LAYERS 32
#define DL_MAGIC 2674
#define PCBU_PER_WU 25400 // conversion from PCB units to world units
// graphics element types
enum
{
DL_NONE = 0,
DL_LINE, // line segment with round end-caps
DL_CIRC, // filled circle
DL_HOLLOW_CIRC, // circle outline
DL_DONUT, // annulus
DL_SQUARE, // filled square
DL_RECT, // filled rectangle
DL_RRECT, // filled rounded rectangle
DL_OVAL, // filled oval
DL_OCTAGON, // filled octagon
DL_HOLE, // hole, shown as circle
DL_HOLLOW_RECT, // rectangle outline
DL_RECT_X, // rectangle outline with X
DL_POINT, // shape to highlight a point
DL_ARC_CW, // arc with clockwise curve
DL_ARC_CCW, // arc with counter-clockwise curve
DL_X // X
};
// dragging line shapes
enum
{
DS_NONE = 0,
DS_LINE_VERTEX, // vertex between two lines
DS_LINE, // line
DS_ARC_STRAIGHT, // straight line (used when drawing polylines)
DS_ARC_CW, // clockwise arc (used when drawing polylines)
DS_ARC_CCW // counterclockwise arc (used when drawing polylines)
};
// styles of line segment when dragging line or line vertex
enum
{
DSS_STRAIGHT = 100, // straight line
DSS_ARC_CW, // clockwise arc
DSS_ARC_CCW // counterclockwise arc
};
// inflection modes for DS_LINE and DS_LINE_VERTEX
enum
{
IM_NONE = 0,
IM_90_45,
IM_45_90,
IM_90
};
class CDisplayList;
// this structure contains an element of the display list
class dl_element
{
friend class CDisplayList;
public:
CDisplayList * dlist;
int magic;
dl_element * prev;
dl_element * next;
id m_id; // identifier (see ids.h)
void * ptr; // pointer to object drawing this element
int gtype; // type of primitive
int visible; // 0 to hide
//private:
int sel_vert; // for selection rectangles, 1 if part is vertical
int w; // width (for round or square shapes)
int holew; // hole width (for round holes)
int x_org, y_org; // x origin (for rotation, reflection, etc.)
int x, y; // starting or center position of element
int xf, yf; // opposite corner (for rectangle or line)
int radius; // radius of corners for DL_RRECT
int layer; // layer to draw on
int orig_layer; // for elements on highlight layer,
// the original layer, the highlight will
// only be drawn if this layer is visible
};
class CDisplayList
{
private:
// display-list parameters for each layer
dl_element m_start[MAX_LAYERS], m_end[MAX_LAYERS];
int m_rgb[MAX_LAYERS][3]; // layer colors
BOOL m_vis[MAX_LAYERS]; // layer visibility flags
int m_layer_in_order[MAX_LAYERS]; // array of layers in draw order
int m_order_for_layer[MAX_LAYERS]; // draw order for each layer
// window parameters
int m_pcbu_per_wu; // i.e. nm per world unit
CRect m_client_r; // client rect (pixels)
CRect m_screen_r; // client rect (screen coords)
int m_pane_org_x; // left border of drawing pane (pixels)
int m_pane_org_y; // bottom border of drawing pane (pixels)
int m_bottom_pane_h; // height of bottom pane
CDC * memDC; // pointer to memory DC
double m_scale; // world units per pixel
int m_org_x; // world x-coord of left side of screen (world units)
int m_org_y; // world y-coord of bottom of screen (world units)
int m_max_x; // world x_coord of right side of screen (world units)
int m_max_y; // world y_coord of top of screen (world units)
int w_ext_x, w_ext_y; // window extents (world units)
int v_ext_x, v_ext_y; // viewport extents (pixels)
double m_wu_per_pixel_x; // ratio w_ext_x/v_ext_x (world units per pixel)
double m_wu_per_pixel_y; // ratio w_ext_y/v_ext_y (world units per pixel)
double m_pcbu_per_pixel_x;
double m_pcbu_per_pixel_y;
// general dragging parameters
int m_drag_angle; // angle of rotation of selection rectangle (starts at 0)
int m_drag_side; // 0 = no change, 1 = switch to opposite
int m_drag_vert; // 1 if item being dragged is a vertical part
// parameters for dragging polyline sides and trace segments
// that can be modified while dragging
int m_drag_flag; // 1 if dragging something
int m_drag_shape; // shape
int m_last_drag_shape; // last shape drawn
int m_drag_x; // last cursor position for dragged shape
int m_drag_y;
int m_drag_xi; // start of rubberband drag line
int m_drag_yi;
int m_drag_xf; // end of rubberband drag line
int m_drag_yf;
int m_drag_layer_1; // line layer
int m_drag_w1; // line width
int m_drag_style1; // line style
int m_inflection_mode; // inflection mode
int m_last_inflection_mode; // last mode drawn
// extra parameters when dragging vertex between 2 line segments
int m_drag_style2;
int m_drag_layer_2;
int m_drag_w2;
// parameters used to draw leading via if necessary
int m_drag_layer_no_via;
int m_drag_via_w;
int m_drag_via_holew;
int m_drag_via_drawn;
// arrays of lines and ratlines being dragged
// these can be rotated and flipped while being dragged
int m_drag_layer; // layer
int m_drag_max_lines; // max size of array for line segments
int m_drag_num_lines; // number of line segments to drag
CPoint * m_drag_line_pt; // array of relative coords for line endpoints
int m_drag_max_ratlines; // max size of ratline array
int m_drag_num_ratlines; // number of ratlines to drag
CPoint * m_drag_ratline_start_pt; // absolute coords for ratline start points
CPoint * m_drag_ratline_end_pt; // relative coords for ratline endpoints
int m_drag_ratline_width;
// cursor parameters
int m_cross_hairs; // 0 = none, 1 = cross-hairs, 2 = diagonals
CPoint m_cross_left, m_cross_right, m_cross_top, m_cross_bottom; // end-points
CPoint m_cross_topleft, m_cross_topright, m_cross_botleft, m_cross_botright;
// grid
int m_visual_grid_on;
double m_visual_grid_spacing; // in world units
public:
CDisplayList( int pcbu_per_wu );
~CDisplayList();
void SetVisibleGrid( BOOL on, double grid );
void SetMapping( CRect *client_r, CRect *screen_r, int pane_org_x, int pane_bottom_h, double scale, int org_x, int org_y );
void SetDCToWorldCoords( CDC * pDC, CDC * mDC, int pcbu_org_x, int pcbu_org_y );
void SetLayerRGB( int layer, int r, int g, int b );
void SetLayerVisible( int layer, BOOL vis );
void SetLayerDrawOrder( int layer, int order )
{ m_layer_in_order[order] = layer; m_order_for_layer[layer] = order; };
dl_element * Add( id id, void * ptr, int glayer, int gtype, int visible,
int w, int holew, int x, int y, int xf, int yf, int xo, int yo,
int radius=0, int orig_layer=LAY_SELECTION );
dl_element * AddSelector( id id, void * ptr, int glayer, int gtype, int visible,
int w, int holew, int x, int y, int xf, int yf, int xo, int yo, int radius=0 );
void RemoveAll();
void RemoveAllFromLayer( int layer );
id Remove( dl_element * element );
void Draw( CDC * pDC );
int HighLight( int gtype, int x, int y, int xf, int yf, int w, int orig_layer=LAY_SELECTION );
int CancelHighLight();
void * TestSelect( int x, int y, id * sel_id, int * layer,
id * exclude_id = NULL, void * exclude_ptr = NULL, id * include_id = NULL,
int n_include_ids=1 );
int StartDraggingArray( CDC * pDC, int x, int y, int vert, int layer, int crosshair = 1 );
int StartDraggingRatLine( CDC * pDC, int x, int y, int xf, int yf, int layer,
int w, int crosshair = 1 );
int StartDraggingRectangle( CDC * pDC, int x, int y, int xi, int yi,
int xf, int yf, int vert, int layer );
int StartDraggingLineVertex( CDC * pDC, int x, int y, int xi, int yi,
int xf, int yf,
int layer1, int layer2, int w1, int w2,
int style1, int style2,
int layer_no_via, int via_w, int via_holew, int dir,
int crosshair );
int StartDraggingLine( CDC * pDC, int x, int y, int xi, int yi, int layer1, int w,
int layer_no_via, int via_w, int via_holew,
int crosshair, int style, int inflection_mode );
int StartDraggingArc( CDC * pDC, int style, int x, int y, int xi, int yi,
int layer, int w, int crosshair );
void SetDragArcStyle( int style );
void Drag( CDC * pDC, int x, int y );
int StopDragging();
void ChangeRoutingLayer( CDC * pDC, int layer1, int layer2, int w );
void IncrementDragAngle( CDC * pDC );
int MakeDragLineArray( int num_lines );
int MakeDragRatlineArray( int num_ratlines, int width );
int AddDragLine( CPoint pi, CPoint pf );
int AddDragRatline( CPoint pi, CPoint pf );
int GetDragAngle();
void FlipDragSide( CDC * pDC );
int GetDragSide();
void SetUpCrosshairs( int type, int x, int y );
void SetInflectionMode( int mode ){ m_inflection_mode = mode; };
CPoint ScreenToPCB( CPoint point );
CPoint PCBToScreen( CPoint point );
CPoint WindowToPCB( CPoint point );
// set element parameters
void Set_gtype( dl_element * el, int gtype );
void Set_visible( dl_element * el, int visible );
void Set_sel_vert( dl_element * el, int sel_vert );
void Set_w( dl_element * el, int w );
void Set_holew( dl_element * el, int holew );
void Set_x_org( dl_element * el, int x_org );
void Set_y_org( dl_element * el, int y_org );
void Set_x( dl_element * el, int x );
void Set_y( dl_element * el, int y );
void Set_xf( dl_element * el, int xf );
void Set_yf( dl_element * el, int yf );
void Set_id( dl_element * el, id * id );
void Set_layer( dl_element * el, int layer );
void Set_radius( dl_element * el, int radius );
void Move( dl_element * el, int dx, int dy );
// get element parameters
void * Get_ptr( dl_element * el );
int Get_gtype( dl_element * el );
int Get_visible( dl_element * el );
int Get_sel_vert( dl_element * el );
int Get_w( dl_element * el );
int Get_holew( dl_element * el );
int Get_x_org( dl_element * el );
int Get_y_org( dl_element * el );
int Get_x( dl_element * el );
int Get_y( dl_element * el );
int Get_xf( dl_element * el );
int Get_yf( dl_element * el );
int Get_radius( dl_element * el );
int Get_layer( dl_element * el );
id Get_id( dl_element * el );
};
#endif // #ifndef FP_DISPLAY_LIST_H
// definition of ID structure used by FreePCB
//
#pragma once
// struct id : this structure is used to identify PCB design elements
// such as instances of parts or nets, and their subelements
// Each element will have its own id.
// An id is attached to each item of the Display List so that it can
// be linked back to the PCB design element which drew it.
// These are mainly used to identify items selected by clicking the mouse
//
// In general:
// id.type = type of PCB element (e.g. part, net, text)
// id.st = subelement type (e.g. part pad, net connection)
// id.i = subelement index (zero-based)
// id.sst = subelement of subelement (e.g. net connection segment)
// id.ii = subsubelement index (zero-based)
//
// For example, the id for segment 0 of connection 4 of net 12 would be
// id = { ID_NET, 12, ID_CONNECT, 4, ID_SEG, 0 };
//
//
class id {
public:
// constructor
id( int qt=0, int qst=0, int qis=0, int qsst=0, int qiis=0 )
{ type=qt; st=qst; i=qis; sst=qsst; ii=qiis; }
// operators
friend int operator ==(id id1, id id2)
{ return (id1.type==id2.type
&& id1.st==id2.st
&& id1.sst==id2.sst
&& id1.i==id2.i
&& id1.ii==id2.ii );
}
// member functions
void Clear()
{ type=0; st=0; i=0; sst=0; ii=0; }
void Set( int qt, int qst=0, int qis=0, int qsst=0, int qiis=0 )
{ type=qt; st=qst; i=qis; sst=qsst; ii=qiis; }
// member variables
unsigned int type; // type of element
unsigned int st; // type of subelement
unsigned int i; // index of subelement
unsigned int sst; // type of subsubelement
unsigned int ii; // index of subsubelement
};
// these are constants used in ids
// root types
enum {
ID_NONE = 0, // an undefined type or st (or an error)
ID_BOARD, // board outline
ID_PART, // part
ID_NET, // net
ID_TEXT, // free-standing text
ID_DRC, // DRC error
ID_SM_CUTOUT, // cutout for solder mask
ID_MULTI // if multiple selections
};
// subtypes of ID_PART
enum {
ID_PAD = 1, // pad_stack in a part
ID_SEL_PAD, // selection rectangle for pad_stack in a part
ID_OUTLINE, // part outline
ID_REF_TXT, // text showing ref num for part
ID_ORIG, // part origin
ID_SEL_RECT, // selection rectangle for part
ID_SEL_REF_TXT // selection rectangle for ref text
};
// subtypes of ID_TEXT
enum {
ID_SEL_TXT = 1, // selection rectangle
ID_STROKE // stroke for text
};
// subtypes of ID_NET
enum {
ID_ENTIRE_NET = 0,
ID_CONNECT, // connection
ID_AREA // copper area
};
// subtypes of ID_BOARD
enum {
ID_BOARD_OUTLINE = 1,
};
// subsubtypes of ID_NET.ID_CONNECT
enum {
ID_ENTIRE_CONNECT = 0,
ID_SEG,
ID_SEL_SEG,
ID_VERTEX,
ID_SEL_VERTEX,
ID_VIA
};
// subsubtypes of ID_NET.ID_AREA, ID_BOARD.ID_BOARD_OUTLINE, ID_SM_CUTOUT
enum {
ID_SIDE = 1,
ID_SEL_SIDE,
ID_SEL_CORNER,
ID_HATCH,
ID_PIN_X, // only used by ID_AREA
ID_STUB_X // only used by ID_AREA
};
// subtypes of ID_DRC
// for subsubtypes, use types in DesignRules.h
enum {
ID_DRE = 1,
ID_SEL_DRE
};
......@@ -9,7 +9,8 @@ OBJECTS= \
php_polygon.o\
php_polygon_vertex.o\
PolyLine.o\
math_for_graphics.o
math_for_graphics.o\
cdisplaylist_stuff.o
GenericPolygonClipperLibrary.o: GenericPolygonClipperLibrary.cpp GenericPolygonClipperLibrary.h
......
// math for graphics utility routines, from FreePCB
using namespace std;
#include <vector>
#include <math.h>
#include <float.h>
#include <limits.h>
#include "defs-macros.h"
#include "PolyLine2Kicad.h"
#include "freepcb_ids.h"
#include "PolyLine.h"
// function to find inflection-pont to create a "dogleg" of two straight-line segments
// where one segment is vertical or horizontal and the other is at 45 degrees or 90 degrees
// enter with:
// pi = start point
// pf = end point
// mode = IM_90_45 or IM_45_90 or IM_90
//
CPoint GetInflectionPoint( CPoint pi, CPoint pf, int mode )
{
CPoint p = pi;
if( mode == IM_NONE )
return p;
int dx = pf.x - pi.x;
int dy = pf.y - pi.y;
if( dx == 0 || dy == 0 || abs(dx) == abs(dy) )
{
// only one segment needed
}
else
{
if( abs(dy) > abs(dx) )
{
// vertical > horizontal
if( mode == IM_90 )
{
p.x = pi.x;
p.y = pf.y;
}
else if( mode == IM_45_90 || mode == IM_90_45 )
{
int vert; // length of vertical line needed
if( dy > 0 )
vert = dy - abs(dx); // positive
else
vert = dy + abs(dx); // negative
if( mode == IM_90_45 )
p.y = pi.y + vert;
else if( mode == IM_45_90 )
{
p.y = pf.y - vert;
p.x = pf.x;
}
}
else
ASSERT(0);
}
else
{
// horizontal > vertical
if( mode == IM_90 )
{
p.x = pf.x;
p.y = pi.y;
}
else if( mode == IM_45_90 || mode == IM_90_45 )
{
int hor; // length of horizontal line needed
if( dx > 0 )
hor = dx - abs(dy); // positive
else
hor = dx + abs(dy); // negative
if( mode == IM_90_45 )
p.x = pi.x + hor;
else if( mode == IM_45_90 )
{
p.x = pf.x - hor;
p.y = pf.y;
}
}
else
ASSERT(0);
}
}
return p;
}
//
// function to rotate a point clockwise about another point
// currently, angle must be 0, 90, 180 or 270
//
void RotatePoint( CPoint *p, int angle, CPoint org )
{
if( angle == 90 )
{
int tempy = org.y + (org.x - p->x);
p->x = org.x + (p->y - org.y);
p->y = tempy;
}
else if( angle > 90 )
{
for( int i=0; i<(angle/90); i++ )
RotatePoint( p, 90, org );
}
}
// function to rotate a rectangle clockwise about a point
// angle must be 0, 90, 180 or 270
// on exit, r->top > r.bottom, r.right > r.left
//
void RotateRect( CRect *r, int angle, CPoint org )
{
CRect tr;
if( angle == 90 )
{
tr.left = org.x + (r->bottom - org.y);
tr.right = org.x + (r->top - org.y);
tr.top = org.y + (org.x - r->right);
tr.bottom = org.y + (org.x - r->left);
if( tr.left > tr.right )
{
int temp = tr.right;
tr.left = tr.right;
tr.left = temp;
}
if( tr.left > tr.right )
{
int temp = tr.right;
tr.left = tr.right;
tr.left = temp;
}
if( tr.bottom > tr.top )
{
int temp = tr.bottom;
tr.bottom = tr.top;
tr.top = temp;
}
}
else if( angle > 90 )
{
tr = *r;
for( int i=0; i<(angle/90); i++ )
RotateRect( &tr, 90, org );
}
*r = tr;
}
// test for hit on line segment
// i.e. cursor within a given distance from segment
// enter with: x,y = cursor coords
// (xi,yi) and (xf,yf) are the end-points of the line segment
// dist = maximum distance for hit
//
int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist )
{
double dd;
// test for vertical or horizontal segment
if( xf==xi )
{
// vertical segment
dd = fabs( (double)(x-xi) );
if( dd<dist && ( (yf>yi && y<yf && y>yi) || (yf<yi && y>yf && y<yi) ) )
return 1;
}
else if( yf==yi )
{
// horizontal segment
dd = fabs( (double)(y-yi) );
if( dd<dist && ( (xf>xi && x<xf && x>xi) || (xf<xi && x>xf && x<xi) ) )
return 1;
}
else
{
// oblique segment
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
double b = (double)(yf-yi)/(xf-xi);
double a = (double)yi-b*xi;
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double d = -1.0/b;
double c = (double)y-d*x;
// find nearest point to (x,y) on line segment (xi,yi) to (xf,yf)
double xp = (a-c)/(d-b);
double yp = a + b*xp;
// find distance
dd = sqrt((x-xp)*(x-xp)+(y-yp)*(y-yp));
if( fabs(b)>0.7 )
{
// line segment more vertical than horizontal
if( dd<dist && ( (yf>yi && yp<yf && yp>yi) || (yf<yi && yp>yf && yp<yi) ) )
return 1;
}
else
{
// line segment more horizontal than vertical
if( dd<dist && ( (xf>xi && xp<xf && xp>xi) || (xf<xi && xp>xf && xp<xi) ) )
return 1;
}
}
return 0; // no hit
}
// find intersection between y = a + bx and y = c + dx;
//
int FindLineIntersection( double a, double b, double c, double d, double * x, double * y )
{
*x = (c-a)/(b-d);
*y = a + b*(*x);
return 0;
}
// set EllipseKH struct to describe the ellipse for an arc
//
int MakeEllipseFromArc( int xi, int yi, int xf, int yf, int style, EllipseKH * el )
{
// arc (quadrant of ellipse)
// convert to clockwise arc
int xxi, xxf, yyi, yyf;
if( style == CPolyLine::ARC_CCW )
{
xxi = xf;
xxf = xi;
yyi = yf;
yyf = yi;
}
else
{
xxi = xi;
xxf = xf;
yyi = yi;
yyf = yf;
}
// find center and radii of ellipse
double xo, yo;
if( xxf > xxi && yyf > yyi )
{
xo = xxf;
yo = yyi;
el->theta1 = M_PI;
el->theta2 = M_PI/2.0;
}
else if( xxf < xxi && yyf > yyi )
{
xo = xxi;
yo = yyf;
el->theta1 = -M_PI/2.0;
el->theta2 = -M_PI;
}
else if( xxf < xxi && yyf < yyi )
{
xo = xxf;
yo = yyi;
el->theta1 = 0.0;
el->theta2 = -M_PI/2.0;
}
else if( xxf > xxi && yyf < yyi )
{
xo = xxi;
yo = yyf;
el->theta1 = M_PI/2.0;
el->theta2 = 0.0;
}
el->Center.X = xo;
el->Center.Y = yo;
el->xrad = abs(xf-xi);
el->yrad = abs(yf-yi);
#if 0
el->Phi = 0.0;
el->MaxRad = el->xrad;
el->MinRad = el->yrad;
if( el->MaxRad < el->MinRad )
{
el->MaxRad = el->yrad;
el->MinRad = el->xrad;
el->Phi = M_PI/2.0;
}
#endif
return 0;
}
// find intersections between line segment (xi,yi) to (xf,yf)
// and line segment (xi2,yi2) to (xf2,yf2)
// the line segments may be arcs (i.e. quadrant of an ellipse) or straight
// returns number of intersections found (max of 2)
// returns coords of intersections in arrays x[2], y[2]
//
int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
int xi2, int yi2, int xf2, int yf2, int style2,
double x[], double y[] )
{
double xr[12], yr[12];
int iret = 0;
if( max(xi,xf) < min(xi2,xf2)
|| min(xi,xf) > max(xi2,xf2)
|| max(yi,yf) < min(yi2,yf2)
|| min(yi,yf) > max(yi2,yf2) )
return 0;
if( style != CPolyLine::STRAIGHT && style2 != CPolyLine::STRAIGHT )
{
// two identical arcs intersect
if( style == style2 && xi == xi2 && yi == yi2 && xf == xf2 && yf == yf2 )
{
if( x && y )
{
x[0] = xi;
y[0] = yi;
}
return 1;
}
else if( style != style2 && xi == xf2 && yi == yf2 && xf == xi2 && yf == yi2 )
{
if( x && y )
{
x[0] = xi;
y[0] = yi;
}
return 1;
}
}
if( style == CPolyLine::STRAIGHT && style2 == CPolyLine::STRAIGHT )
{
// both straight-line segments
int x, y;
bool bYes = TestForIntersectionOfStraightLineSegments( xi, yi, xf, yf, xi2, yi2, xf2, yf2, &x, &y );
if( !bYes )
return 0;
xr[0] = x;
yr[0] = y;
iret = 1;
}
else if( style == CPolyLine::STRAIGHT )
{
// first segment is straight, second segment is an arc
int ret;
double x1r, y1r, x2r, y2r;
if( xf == xi )
{
// vertical first segment
double a = xi;
double b = DBL_MAX/2.0;
ret = FindLineSegmentIntersection( a, b, xi2, yi2, xf2, yf2, style2,
&x1r, &y1r, &x2r, &y2r );
}
else
{
double b = (double)(yf-yi)/(double)(xf-xi);
double a = yf - b*xf;
ret = FindLineSegmentIntersection( a, b, xi2, yi2, xf2, yf2, style2,
&x1r, &y1r, &x2r, &y2r );
}
if( ret == 0 )
return 0;
if( InRange( x1r, xi, xf ) && InRange( y1r, yi, yf ) )
{
xr[iret] = x1r;
yr[iret] = y1r;
iret++;
}
if( ret == 2 )
{
if( InRange( x2r, xi, xf ) && InRange( y2r, yi, yf ) )
{
xr[iret] = x2r;
yr[iret] = y2r;
iret++;
}
}
}
else if( style2 == CPolyLine::STRAIGHT )
{
// first segment is an arc, second segment is straight
int ret;
double x1r, y1r, x2r, y2r;
if( xf2 == xi2 )
{
// vertical second segment
double a = xi2;
double b = DBL_MAX/2.0;
ret = FindLineSegmentIntersection( a, b, xi, yi, xf, yf, style,
&x1r, &y1r, &x2r, &y2r );
}
else
{
double b = (double)(yf2-yi2)/(double)(xf2-xi2);
double a = yf2 - b*xf2;
ret = FindLineSegmentIntersection( a, b, xi, yi, xf, yf, style,
&x1r, &y1r, &x2r, &y2r );
}
if( ret == 0 )
return 0;
if( InRange( x1r, xi2, xf2 ) && InRange( y1r, yi2, yf2 ) )
{
xr[iret] = x1r;
yr[iret] = y1r;
iret++;
}
if( ret == 2 )
{
if( InRange( x2r, xi2, xf2 ) && InRange( y2r, yi2, yf2 ) )
{
xr[iret] = x2r;
yr[iret] = y2r;
iret++;
}
}
}
else
{
// both segments are arcs
EllipseKH el1;
EllipseKH el2;
MakeEllipseFromArc( xi, yi, xf, yf, style, &el1 );
MakeEllipseFromArc( xi2, yi2, xf2, yf2, style2, &el2 );
int n;
if( el1.xrad+el1.yrad > el2.xrad+el2.yrad )
n = GetArcIntersections( &el1, &el2 );
else
n = GetArcIntersections( &el2, &el1 );
iret = n;
}
if( x && y )
{
for( int i=0; i<iret; i++ )
{
x[i] = xr[i];
y[i] = yr[i];
}
}
return iret;
}
// find intersection between line y = a + bx and line segment (xi,yi) to (xf,yf)
// if b > DBL_MAX/10, assume vertical line at x = a
// the line segment may be an arc (i.e. quadrant of an ellipse)
// return 0 if no intersection
// returns 1 or 2 if intersections found
// sets coords of intersections in *x1, *y1, *x2, *y2
// if no intersection, returns min distance in dist
//
int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, int style,
double * x1, double * y1, double * x2, double * y2,
double * dist )
{
double xx, yy;
bool bVert = false;
if( b > DBL_MAX/10.0 )
bVert = true;
if( xf != xi )
{
// non-vertical segment, get intersection
if( style == CPolyLine::STRAIGHT || yf == yi )
{
// horizontal or oblique straight segment
// put into form y = c + dx;
double d = (double)(yf-yi)/(double)(xf-xi);
double c = yf - d*xf;
if( bVert )
{
// if vertical line, easy
if( InRange( a, xi, xf ) )
{
*x1 = a;
*y1 = c + d*a;
return 1;
}
else
{
if( dist )
*dist = min( abs(a-xi), abs(a-xf) );
return 0;
}
}
if( fabs(b-d) < 1E-12 )
{
// parallel lines
if( dist )
{
*dist = GetPointToLineDistance( a, b, xi, xf );
}
return 0; // lines parallel
}
// calculate intersection
xx = (c-a)/(b-d);
yy = a + b*(xx);
// see if intersection is within the line segment
if( yf == yi )
{
// horizontal line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf) )
return 0;
}
else
{
// oblique line
if( (xx>=xi && xx>xf) || (xx<=xi && xx<xf)
|| (yy>yi && yy>yf) || (yy<yi && yy<yf) )
return 0;
}
}
else if( style == CPolyLine::ARC_CW || style == CPolyLine::ARC_CCW )
{
// arc (quadrant of ellipse)
// convert to clockwise arc
int xxi, xxf, yyi, yyf;
if( style == CPolyLine::ARC_CCW )
{
xxi = xf;
xxf = xi;
yyi = yf;
yyf = yi;
}
else
{
xxi = xi;
xxf = xf;
yyi = yi;
yyf = yf;
}
// find center and radii of ellipse
double xo, yo, rx, ry;
if( xxf > xxi && yyf > yyi )
{
xo = xxf;
yo = yyi;
}
else if( xxf < xxi && yyf > yyi )
{
xo = xxi;
yo = yyf;
}
else if( xxf < xxi && yyf < yyi )
{
xo = xxf;
yo = yyi;
}
else if( xxf > xxi && yyf < yyi )
{
xo = xxi;
yo = yyf;
}
rx = fabs( (double)(xxi-xxf) );
ry = fabs( (double)(yyi-yyf) );
bool test;
double xx1, xx2, yy1, yy2, aa;
if( bVert )
{
// shift vertical line to coordinate system of ellipse
aa = a - xo;
test = FindVerticalLineEllipseIntersections( rx, ry, aa, &yy1, &yy2 );
if( !test )
return 0;
// shift back to PCB coordinates
yy1 += yo;
yy2 += yo;
xx1 = a;
xx2 = a;
}
else
{
// shift line to coordinate system of ellipse
aa = a + b*xo - yo;
test = FindLineEllipseIntersections( rx, ry, aa, b, &xx1, &xx2 );
if( !test )
return 0;
// shift back to PCB coordinates
yy1 = aa + b*xx1;
xx1 += xo;
yy1 += yo;
yy2 = aa + b*xx2;
xx2 += xo;
yy2 += yo;
}
int npts = 0;
if( (xxf>xxi && xx1<xxf && xx1>xxi) || (xxf<xxi && xx1<xxi && xx1>xxf) )
{
if( (yyf>yyi && yy1<yyf && yy1>yyi) || (yyf<yyi && yy1<yyi && yy1>yyf) )
{
*x1 = xx1;
*y1 = yy1;
npts = 1;
}
}
if( (xxf>xxi && xx2<xxf && xx2>xxi) || (xxf<xxi && xx2<xxi && xx2>xxf) )
{
if( (yyf>yyi && yy2<yyf && yy2>yyi) || (yyf<yyi && yy2<yyi && yy2>yyf) )
{
if( npts == 0 )
{
*x1 = xx2;
*y1 = yy2;
npts = 1;
}
else
{
*x2 = xx2;
*y2 = yy2;
npts = 2;
}
}
}
return npts;
}
else
ASSERT(0);
}
else
{
// vertical line segment
if( bVert )
return 0;
xx = xi;
yy = a + b*xx;
if( (yy>=yi && yy>yf) || (yy<=yi && yy<yf) )
return 0;
}
*x1 = xx;
*y1 = yy;
return 1;
}
// Test for intersection of line segments
// If lines are parallel, returns false
// If true, returns intersection coords in x, y
// if false, returns min. distance in dist (may be 0.0 if parallel)
// and coords on nearest point in one of the segments in (x,y)
//
bool TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f,
int x2i, int y2i, int x2f, int y2f,
int * x, int * y, double * d )
{
double a, b, dist;
// first, test for intersection
if( x1i == x1f && x2i == x2f )
{
// both segments are vertical, can't intersect
}
else if( y1i == y1f && y2i == y2f )
{
// both segments are horizontal, can't intersect
}
else if( x1i == x1f && y2i == y2f )
{
// first seg. vertical, second horizontal, see if they cross
if( InRange( x1i, x2i, x2f )
&& InRange( y2i, y1i, y1f ) )
{
if( x )
*x = x1i;
if( y )
*y = y2i;
if( d )
*d = 0.0;
return true;
}
}
else if( y1i == y1f && x2i == x2f )
{
// first seg. horizontal, second vertical, see if they cross
if( InRange( y1i, y2i, y2f )
&& InRange( x2i, x1i, x1f ) )
{
if( x )
*x = x2i;
if( y )
*y = y1i;
if( d )
*d = 0.0;
return true;
}
}
else if( x1i == x1f )
{
// first segment vertical, second oblique
// get a and b for second line segment, so that y = a + bx;
b = (double)(y2f-y2i)/(x2f-x2i);
a = (double)y2i - b*x2i;
double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 );
if( test )
{
if( InRange( y1, y1i, y1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) )
{
if( x )
*x = x1;
if( y )
*y = y1;
if( d )
*d = 0.0;
return true;
}
}
}
else if( y1i == y1f )
{
// first segment horizontal, second oblique
// get a and b for second line segment, so that y = a + bx;
b = (double)(y2f-y2i)/(x2f-x2i);
a = (double)y2i - b*x2i;
double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x1i, y1i, x1f, y1f, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 );
if( test )
{
if( InRange( x1, x1i, x1f ) && InRange( x1, x2i, x2f ) && InRange( y1, y2i, y2f ) )
{
if( x )
*x = x1;
if( y )
*y = y1;
if( d )
*d = 0.0;
return true;
}
}
}
else if( x2i == x2f )
{
// second segment vertical, first oblique
// get a and b for first line segment, so that y = a + bx;
b = (double)(y1f-y1i)/(x1f-x1i);
a = (double)y1i - b*x1i;
double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 );
if( test )
{
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) && InRange( y1, y2i, y2f ) )
{
if( x )
*x = x1;
if( y )
*y = y1;
if( d )
*d = 0.0;
return true;
}
}
}
else if( y2i == y2f )
{
// second segment horizontal, first oblique
// get a and b for second line segment, so that y = a + bx;
b = (double)(y1f-y1i)/(x1f-x1i);
a = (double)y1i - b*x1i;
double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 );
if( test )
{
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) )
{
if( x )
*x = x1;
if( y )
*y = y1;
if( d )
*d = 0.0;
return true;
}
}
}
else
{
// both segments oblique
if( (long)(y1f-y1i)*(x2f-x2i) != (long)(y2f-y2i)*(x1f-x1i) )
{
// not parallel, get a and b for first line segment, so that y = a + bx;
b = (double)(y1f-y1i)/(x1f-x1i);
a = (double)y1i - b*x1i;
double x1, y1, x2, y2;
int test = FindLineSegmentIntersection( a, b, x2i, y2i, x2f, y2f, CPolyLine::STRAIGHT,
&x1, &y1, &x2, &y2 );
// both segments oblique
if( test )
{
if( InRange( x1, x1i, x1f ) && InRange( y1, y1i, y1f ) )
{
if( x )
*x = x1;
if( y )
*y = y1;
if( d )
*d = 0.0;
return true;
}
}
}
}
// don't intersect, get shortest distance between each endpoint and the other line segment
dist = GetPointToLineSegmentDistance( x1i, y1i, x2i, y2i, x2f, y2f );
double xx = x1i;
double yy = y1i;
double dd = GetPointToLineSegmentDistance( x1f, y1f, x2i, y2i, x2f, y2f );
if( dd < dist )
{
dist = dd;
xx = x1f;
yy = y1f;
}
dd = GetPointToLineSegmentDistance( x2i, y2i, x1i, y1i, x1f, y1f );
if( dd < dist )
{
dist = dd;
xx = x2i;
yy = y2i;
}
dd = GetPointToLineSegmentDistance( x2f, y2f, x1i, y1i, x1f, y1f );
if( dd < dist )
{
dist = dd;
xx = x2f;
yy = y2f;
}
if( x )
*x = xx;
if( y )
*y = yy;
if( d )
*d = dist;
return false;
}
// quicksort algorithm
// sorts array numbers[], also moves elements of another array index[]
//
#define Q3WAY
void quickSort(int numbers[], int index[], int array_size)
{
#ifdef Q3WAY
q_sort_3way(numbers, index, 0, array_size - 1);
#else
q_sort(numbers, index, 0, array_size - 1);
#endif
}
// standard quicksort
//
void q_sort(int numbers[], int index[], int left, int right)
{
int pivot, pivot_index, l_hold, r_hold;
l_hold = left;
r_hold = right;
pivot = numbers[left];
pivot_index = index[left];
while (left < right)
{
while ((numbers[right] >= pivot) && (left < right))
right--;
if (left != right)
{
numbers[left] = numbers[right];
index[left] = index[right];
left++;
}
while ((numbers[left] <= pivot) && (left < right))
left++;
if (left != right)
{
numbers[right] = numbers[left];
index[right] = index[left];
right--;
}
}
numbers[left] = pivot;
index[left] = pivot_index;
pivot = left;
left = l_hold;
right = r_hold;
if (left < pivot)
q_sort(numbers, index, left, pivot-1);
if (right > pivot)
q_sort(numbers, index, pivot+1, right);
}
// 3-way quicksort...useful where there are duplicate values
//
void q_sort_3way( int a[], int b[], int l, int r )
{
#define EXCH(i,j) {int temp=a[i]; a[i]=a[j]; a[j]=temp; temp=b[i]; b[i]=b[j]; b[j]=temp;}
int i = l - 1;
int j = r;
int p = l - 1;
int q = r;
int v = a[r];
if( r <= l )
return;
for(;;)
{
while( a[++i] < v );
while( v < a[--j] )
if( j == 1 )
break;
if( i >= j )
break;
EXCH( i, j );
if( a[i] == v )
{
p++;
EXCH( p, i );
}
if( v == a[j] )
{
q--;
EXCH( j, q );
}
}
EXCH( i, r );
j = i - 1;
i = i + 1;
for( int k=l; k<p; k++, j-- )
EXCH( k, j );
for( int k=r-1; k>q; k--, i++ )
EXCH( i, k );
q_sort_3way( a, b, l, j );
q_sort_3way( a, b, i, r );
}
// solves quadratic equation
// i.e. ax**2 + bx + c = 0
// returns true if solution exist, with solutions in x1 and x2
// else returns false
//
bool Quadratic( double a, double b, double c, double *x1, double *x2 )
{
double root = b*b - 4.0*a*c;
if( root < 0.0 )
return false;
root = sqrt( root );
*x1 = (-b+root)/(2.0*a);
*x2 = (-b-root)/(2.0*a);
return true;
}
// finds intersections of vertical line at x
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in y1 and y2
// else returns false
//
bool FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 )
{
double y_sqr = (1.0-(x*x)/(a*a))*b*b;
if( y_sqr < 0.0 )
return false;
*y1 = sqrt(y_sqr);
*y2 = -*y1;
return true;
}
// finds intersections of straight line y = c + dx
// with ellipse defined by (x^2)/(a^2) + (y^2)/(b^2) = 1;
// returns true if solution exist, with solutions in x1 and x2
// else returns false
//
bool FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 )
{
// quadratic terms
double A = d*d+b*b/(a*a);
double B = 2.0*c*d;
double C = c*c-b*b;
return Quadratic( A, B, C, x1, x2 );
}
#if 0
// draw a straight line or an arc between xi,yi and xf,yf
//
void DrawArc( CDC * pDC, int shape, int xxi, int yyi, int xxf, int yyf, bool bMeta )
{
int xi, yi, xf, yf;
if( shape == DL_LINE || xxi == xxf || yyi == yyf )
{
// draw straight line
pDC->MoveTo( xxi, yyi );
pDC->LineTo( xxf, yyf );
}
else if( shape == DL_ARC_CCW || shape == DL_ARC_CW )
{
// set endpoints so we can always draw counter-clockwise arc
if( shape == DL_ARC_CW )
{
xi = xxf;
yi = yyf;
xf = xxi;
yf = yyi;
}
else
{
xi = xxi;
yi = yyi;
xf = xxf;
yf = yyf;
}
pDC->MoveTo( xi, yi );
if( xf > xi && yf > yi )
{
// quadrant 1
int w = (xf-xi)*2;
int h = (yf-yi)*2;
if( !bMeta )
pDC->Arc( xf-w, yi+h, xf, yi,
xi, yi, xf, yf );
else
pDC->Arc( xf-w, yi, xf, yi+h,
xf, yf, xi, yi );
}
else if( xf < xi && yf > yi )
{
// quadrant 2
int w = -(xf-xi)*2;
int h = (yf-yi)*2;
if( !bMeta )
pDC->Arc( xi-w, yf, xi, yf-h,
xi, yi, xf, yf );
else
pDC->Arc( xi-w, yf-h, xi, yf,
xf, yf, xi, yi );
}
else if( xf < xi && yf < yi )
{
// quadrant 3
int w = -(xf-xi)*2;
int h = -(yf-yi)*2;
if( !bMeta )
pDC->Arc( xf, yi, xf+w, yi-h,
xi, yi, xf, yf );
else
pDC->Arc( xf, yi-h, xf+w, yi,
xf, yf, xi, yi );
}
else if( xf > xi && yf < yi )
{
// quadrant 4
int w = (xf-xi)*2;
int h = -(yf-yi)*2;
if( !bMeta )
pDC->Arc( xi, yf+h, xi+w, yf,
xi, yi, xf, yf );
else
pDC->Arc( xi, yf, xi+w, yf+h,
xf, yf, xi, yi );
}
pDC->MoveTo( xxf, yyf );
}
else
ASSERT(0); // oops
}
#endif
// Get arrays of circles, rects and line segments to represent pad
// for purposes of drawing pad or calculating clearances
// margins of circles and line segments represent pad outline
// circles and rects are used to find points inside pad
//
void GetPadElements( int type, int x, int y, int wid, int len, int radius, int angle,
int * nr, my_rect r[], int * nc, my_circle c[], int * ns, my_seg s[] )
{
*nc = 0;
*nr = 0;
*ns = 0;
if( type == PAD_ROUND )
{
*nc = 1;
c[0] = my_circle(x,y,wid/2);
return;
}
if( type == PAD_SQUARE )
{
*nr = 1;
r[0] = my_rect(x-wid/2, y-wid/2,x+wid/2, y+wid/2);
*ns = 4;
s[0] = my_seg(x-wid/2, y+wid/2,x+wid/2, y+wid/2); // top
s[1] = my_seg(x-wid/2, y-wid/2,x+wid/2, y-wid/2); // bottom
s[2] = my_seg(x-wid/2, y-wid/2,x-wid/2, y+wid/2); // left
s[3] = my_seg(x+wid/2, y-wid/2,x+wid/2, y+wid/2); // right
return;
}
if( type == PAD_OCTAGON )
{
const double pi = 3.14159265359;
*nc = 1; // circle represents inside of polygon
c[0] = my_circle(x, y, wid/2);
*ns = 8; // now create sides of polygon
double theta = pi/8.0;
double radius = 0.5*(double)wid/cos(theta);
double last_x = x + radius*cos(theta);
double last_y = y + radius*sin(theta);
for( int is=0; is<8; is++ )
{
theta += pi/4.0;
double dx = x + radius*cos(theta);
double dy = y + radius*sin(theta);
s[is] = my_seg(last_x, last_y, x, y);
last_x = dx;
last_y = dy;
}
return;
}
//
int h;
int v;
if( angle == 90 || angle == 270 )
{
h = wid;
v = len;
}
else
{
v = wid;
h = len;
}
if( type == PAD_RECT )
{
*nr = 1;
r[0] = my_rect(x-h/2, y-v/2, x+h/2, y+v/2);
*ns = 4;
s[0] = my_seg(x-h/2, y+v/2,x+h/2, y+v/2); // top
s[1] = my_seg(x-h/2, y-v/2,x+h/2, y-v/2); // bottom
s[2] = my_seg(x-h/2, y-v/2,x-h/2, y+v/2); // left
s[3] = my_seg(x+h/2, y-v/2,x+h/2, y+v/2); // right
return;
}
if( type == PAD_RRECT )
{
*nc = 4;
c[0] = my_circle(x-h/2+radius, y-v/2+radius, radius); // bottom left circle
c[1] = my_circle(x+h/2-radius, y-v/2+radius, radius); // bottom right circle
c[2] = my_circle(x-h/2+radius, y+v/2-radius, radius); // top left circle
c[3] = my_circle(x+h/2-radius, y+v/2-radius, radius); // top right circle
*ns = 4;
s[0] = my_seg(x-h/2+radius, y+v/2, x+h/2-radius, y+v/2); // top
s[1] = my_seg(x-h/2+radius, y-v/2, x+h/2-radius, y+v/2); // bottom
s[2] = my_seg(x-h/2, y-v/2+radius, x-h/2, y+v/2-radius); // left
s[3] = my_seg(x+h/2, y-v/2+radius, x+h/2, y+v/2-radius); // right
return;
}
if( type == PAD_OVAL )
{
if( h > v )
{
// horizontal
*nc = 2;
c[0] = my_circle(x-h/2+v/2, y, v/2); // left circle
c[1] = my_circle(x+h/2-v/2, y, v/2); // right circle
*nr = 1;
r[0] = my_rect(x-h/2+v/2, y-v/2, x+h/2-v/2, y+v/2);
*ns = 2;
s[0] = my_seg(x-h/2+v/2, y+v/2, x+h/2-v/2, y+v/2); // top
s[1] = my_seg(x-h/2+v/2, y-v/2, x+h/2-v/2, y-v/2); // bottom
}
else
{
// vertical
*nc = 2;
c[0] = my_circle(x, y+v/2-h/2, h/2); // top circle
c[1] = my_circle(x, y-v/2+h/2, h/2); // bottom circle
*nr = 1;
r[0] = my_rect(x-h/2, y-v/2+h/2, x+h/2, y+v/2-h/2);
*ns = 2;
s[0] = my_seg(x-h/2, y-v/2+h/2, x-h/2, y+v/2-h/2); // left
s[1] = my_seg(x+h/2, y-v/2+h/2, x+h/2, y+v/2-h/2); // left
}
return;
}
ASSERT(0);
}
// Find distance from a staright line segment to a pad
//
int GetClearanceBetweenSegmentAndPad( int x1, int y1, int x2, int y2, int w,
int type, int x, int y, int wid, int len, int radius, int angle )
{
if( type == PAD_NONE )
return INT_MAX;
else
{
int nc, nr, ns;
my_circle c[4];
my_rect r[2];
my_seg s[8];
GetPadElements( type, x, y, wid, len, radius, angle,
&nr, r, &nc, c, &ns, s );
// first test for endpoints of line segment in rectangle
for( int ir=0; ir<nr; ir++ )
{
if( x1 >= r[ir].xlo && x1 <= r[ir].xhi && y1 >= r[ir].ylo && y1 <= r[ir].yhi )
return 0;
if( x2 >= r[ir].xlo && x2 <= r[ir].xhi && y2 >= r[ir].ylo && y2 <= r[ir].yhi )
return 0;
}
// now get distance from elements of pad outline
int dist = INT_MAX;
for( int ic=0; ic<nc; ic++ )
{
int d = GetPointToLineSegmentDistance( c[ic].x, c[ic].y, x1, y1, x2, y2 ) - c[ic].r - w/2;
dist = min(dist,d);
}
for( int is=0; is<ns; is++ )
{
double d;
TestForIntersectionOfStraightLineSegments( s[is].xi, s[is].yi, s[is].xf, s[is].yf,
x1, y1, x2, y2, NULL, NULL, &d );
d -= w/2;
dist = min(dist,d);
}
return max(0,dist);
}
}
// Get clearance between 2 segments
// Returns point in segment closest to other segment in x, y
// in clearance > max_cl, just returns max_cl and doesn't return x,y
//
int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, int w1,
int x2i, int y2i, int x2f, int y2f, int style2, int w2,
int max_cl, int * x, int * y )
{
// check clearance between bounding rectangles
int test = max_cl + w1/2 + w2/2;
if( min(x1i,x1f)-max(x2i,x2f) > test )
return max_cl;
if( min(x2i,x2f)-max(x1i,x1f) > test )
return max_cl;
if( min(y1i,y1f)-max(y2i,y2f) > test )
return max_cl;
if( min(y2i,y2f)-max(y1i,y1f) > test )
return max_cl;
if( style1 == CPolyLine::STRAIGHT && style1 == CPolyLine::STRAIGHT )
{
// both segments are straight lines
int xx, yy;
double dd;
TestForIntersectionOfStraightLineSegments( x1i, y1i, x1f, y1f,
x2i, y2i, x2f, y2f, &xx, &yy, &dd );
int d = max( 0, dd - w1/2 - w2/2 );
if( x )
*x = xx;
if( y )
*y = yy;
return d;
}
// not both straight-line segments
// see if segments intersect
double xr[2];
double yr[2];
test = FindSegmentIntersections( x1i, y1i, x1f, y1f, style1, x2i, y2i, x2f, y2f, style2, xr, yr );
if( test )
{
if( x )
*x = xr[0];
if( y )
*y = yr[0];
return 0.0;
}
// at least one segment is an arc
EllipseKH el1;
EllipseKH el2;
bool bArcs;
int xi, yi, xf, yf;
if( style2 == CPolyLine::STRAIGHT )
{
// style1 = arc, style2 = straight
MakeEllipseFromArc( x1i, y1i, x1f, y1f, style1, &el1 );
xi = x2i;
yi = y2i;
xf = x2f;
yf = y2f;
bArcs = false;
}
else if( style1 == CPolyLine::STRAIGHT )
{
// style2 = arc, style1 = straight
xi = x1i;
yi = y1i;
xf = x1f;
yf = y1f;
MakeEllipseFromArc( x2i, y2i, x2f, y2f, style2, &el1 );
bArcs = false;
}
else
{
// style1 = arc, style2 = arc
MakeEllipseFromArc( x1i, y1i, x1f, y1f, style1, &el1 );
MakeEllipseFromArc( x2i, y2i, x2f, y2f, style2, &el2 );
bArcs = true;
}
const int NSTEPS = 32;
if( el1.theta2 > el1.theta1 )
ASSERT(0);
if( bArcs && el2.theta2 > el2.theta1 )
ASSERT(0);
// test multiple points in both segments
double th1;
double th2;
double len2;
if( bArcs )
{
th1 = el2.theta1;
th2 = el2.theta2;
len2 = max(el2.xrad, el2.yrad);
}
else
{
th1 = 1.0;
th2 = 0.0;
len2 = abs(xf-xi)+abs(yf-yi);
}
double s_start = el1.theta1;
double s_end = el1.theta2;
double s_start2 = th1;
double s_end2 = th2;
double dmin = DBL_MAX;
double xmin, ymin, smin, smin2;
int nsteps = NSTEPS;
int nsteps2 = NSTEPS;
double step = (s_start-s_end)/(nsteps-1);
double step2 = (s_start2-s_end2)/(nsteps2-1);
while( (step * max(el1.xrad, el1.yrad)) > 0.1*NM_PER_MIL
&& (step2 * len2) > 0.1*NM_PER_MIL )
{
step = (s_start-s_end)/(nsteps-1);
for( int i=0; i<nsteps; i++ )
{
double s;
if( i < nsteps-1 )
s = s_start - i*step;
else
s = s_end;
double x = el1.Center.X + el1.xrad*cos(s);
double y = el1.Center.Y + el1.yrad*sin(s);
// if not an arc, use s2 as fractional distance along line
step2 = (s_start2-s_end2)/(nsteps2-1);
for( int i2=0; i2<nsteps2; i2++ )
{
double s2;
if( i2 < nsteps2-1 )
s2 = s_start2 - i2*step2;
else
s2 = s_end2;
double x2, y2;
if( !bArcs )
{
x2 = xi + (xf-xi)*s2;
y2 = yi + (yf-yi)*s2;
}
else
{
x2 = el2.Center.X + el2.xrad*cos(s2);
y2 = el2.Center.Y + el2.yrad*sin(s2);
}
double d = Distance( x, y, x2, y2 );
if( d < dmin )
{
dmin = d;
xmin = x;
ymin = y;
smin = s;
smin2 = s2;
}
}
}
if( step > step2 )
{
s_start = min(el1.theta1, smin + step);
s_end = max(el1.theta2, smin - step);
step = (s_start - s_end)/nsteps;
}
else
{
s_start2 = min(th1, smin2 + step2);
s_end2 = max(th2, smin2 - step2);
step2 = (s_start2 - s_end2)/nsteps2;
}
}
if( x )
*x = xmin;
if( y )
*y = ymin;
return max(0,dmin-w1/2-w2/2); // allow for widths
}
// Find clearance between pads
// For each pad:
// type = PAD_ROUND, PAD_SQUARE, etc.
// x, y = center position
// w, l = width and length
// r = corner radius
// angle = 0 or 90 (if 0, pad length is along x-axis)
//
int GetClearanceBetweenPads( int type1, int x1, int y1, int w1, int l1, int r1, int angle1,
int type2, int x2, int y2, int w2, int l2, int r2, int angle2 )
{
if( type1 == PAD_NONE )
return INT_MAX;
if( type2 == PAD_NONE )
return INT_MAX;
int dist = INT_MAX;
int nr, nc, ns, nrr, ncc, nss;
my_rect r[2], rr[2];
my_circle c[4], cc[4];
my_seg s[8], ss[8];
GetPadElements( type1, x1, y1, w1, l1, r1, angle1,
&nr, r, &nc, c, &ns, s );
GetPadElements( type2, x2, y2, w2, l2, r2, angle2,
&nrr, rr, &ncc, cc, &nss, ss );
// now find distance from every element of pad1 to every element of pad2
for( int ic=0; ic<nc; ic++ )
{
for( int icc=0; icc<ncc; icc++ )
{
int d = Distance( c[ic].x, c[ic].y, cc[icc].x, cc[icc].y )
- c[ic].r - cc[icc].r;
dist = min(dist,d);
}
for( int iss=0; iss<nss; iss++ )
{
int d = GetPointToLineSegmentDistance( c[ic].x, c[ic].y,
ss[iss].xi, ss[iss].yi, ss[iss].xf, ss[iss].yf ) - c[ic].r;
dist = min(dist,d);
}
}
for( int is=0; is<ns; is++ )
{
for( int icc=0; icc<ncc; icc++ )
{
int d = GetPointToLineSegmentDistance( cc[icc].x, cc[icc].y,
s[is].xi, s[is].yi, s[is].xf, s[is].yf ) - cc[icc].r;
dist = min(dist,d);
}
for( int iss=0; iss<nss; iss++ )
{
double d;
TestForIntersectionOfStraightLineSegments( s[is].xi, s[is].yi, s[is].xf, s[is].yf,
ss[iss].xi, ss[iss].yi, ss[iss].xf, ss[iss].yf, NULL, NULL, &d );
dist = min(dist,d);
}
}
return max(dist,0);
}
// Get min. distance from (x,y) to line y = a + bx
// if b > DBL_MAX/10, assume vertical line at x = a
// returns closest point on line in xp, yp
//
double GetPointToLineDistance( double a, double b, int x, int y, double * xpp, double * ypp )
{
if( b > DBL_MAX/10 )
{
// vertical line
if( xpp && ypp )
{
*xpp = a;
*ypp = y;
}
return abs(a-x);
}
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double d = -1.0/b;
double c = (double)y-d*x;
// find nearest point to (x,y) on line through (xi,yi) to (xf,yf)
double xp = (a-c)/(d-b);
double yp = a + b*xp;
if( xpp && ypp )
{
*xpp = xp;
*ypp = yp;
}
// find distance
return Distance( x, y, xp, yp );
}
/***********************************************************************************/
double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf )
/***********************************************************************************/
/** Function GetPointToLineSegmentDistance
* Get distance between line segment and point
* @param x,y = point
* @param xi,yi and xf,yf = the end-points of the line segment
* @return the distance
*/
{
// test for vertical or horizontal segment
if( xf==xi )
{
// vertical line segment
if( InRange( y, yi, yf ) )
return abs( x - xi );
else
return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) );
}
else if( yf==yi )
{
// horizontal line segment
if( InRange( x, xi, xf ) )
return abs( y - yi );
else
return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) );
}
else
{
// oblique segment
// find a,b such that (xi,yi) and (xf,yf) lie on y = a + bx
double b = (double)(yf-yi)/(xf-xi);
double a = (double)yi-b*xi;
// find c,d such that (x,y) lies on y = c + dx where d=(-1/b)
double d = -1.0/b;
double c = (double)y-d*x;
// find nearest point to (x,y) on line through (xi,yi) to (xf,yf)
double xp = (a-c)/(d-b);
double yp = a + b*xp;
// find distance
if( InRange( xp, xi, xf ) && InRange( yp, yi, yf ) )
return Distance( x, y, xp, yp );
else
return min( Distance( x, y, xi, yi ), Distance( x, y, xf, yf ) );
}
}
// test for value within range
//
bool InRange( double x, double xi, double xf )
{
if( xf>xi )
{
if( x >= xi && x <= xf )
return true;
}
else
{
if( x >= xf && x <= xi )
return true;
}
return false;
}
// Get distance between 2 points
//
double Distance( int x1, int y1, int x2, int y2 )
{
double d;
d = sqrt( (double)(x1-x2)*(x1-x2) + (double)(y1-y2)*(y1-y2) );
if( d > INT_MAX || d < INT_MIN )
ASSERT(0);
return (int)d;
}
// this finds approximate solutions
// note: this works best if el2 is smaller than el1
//
int GetArcIntersections( EllipseKH * el1, EllipseKH * el2,
double * x1, double * y1, double * x2, double * y2 )
{
if( el1->theta2 > el1->theta1 )
ASSERT(0);
if( el2->theta2 > el2->theta1 )
ASSERT(0);
const int NSTEPS = 32;
double xret[2], yret[2];
double xscale = 1.0/el1->xrad;
double yscale = 1.0/el1->yrad;
// now transform params of second ellipse into reference frame
// with origin at center if first ellipse,
// scaled so the first ellipse is a circle of radius = 1.0
double xo = (el2->Center.X - el1->Center.X)*xscale;
double yo = (el2->Center.Y - el1->Center.Y)*yscale;
double xr = el2->xrad*xscale;
double yr = el2->yrad*yscale;
// now test NSTEPS positions in arc, moving clockwise (ie. decreasing theta)
double step = M_PI/((NSTEPS-1)*2.0);
double d_prev, th_prev;
double th_interp;
double th1;
int n = 0;
for( int i=0; i<NSTEPS; i++ )
{
double theta;
if( i < NSTEPS-1 )
theta = el2->theta1 - i*step;
else
theta = el2->theta2;
double x = xo + xr*cos(theta);
double y = yo + yr*sin(theta);
double d = 1.0 - sqrt(x*x + y*y);
if( i>0 )
{
bool bInt = false;
if( d >= 0.0 && d_prev <= 0.0 )
{
th_interp = theta + (step*(-d_prev))/(d-d_prev);
bInt = true;
}
else if( d <= 0.0 && d_prev >= 0.0 )
{
th_interp = theta + (step*d_prev)/(d_prev-d);
bInt = true;
}
if( bInt )
{
x = xo + xr*cos(th_interp);
y = yo + yr*sin(th_interp);
th1 = atan2( y, x );
if( th1 <= el1->theta1 && th1 >= el1->theta2 )
{
xret[n] = x*el1->xrad + el1->Center.X;
yret[n] = y*el1->yrad + el1->Center.Y;
n++;
if( n > 2 )
ASSERT(0);
}
}
}
d_prev = d;
th_prev = theta;
}
if( x1 )
*x1 = xret[0];
if( y1 )
*y1 = yret[0];
if( x2 )
*x2 = xret[1];
if( y2 )
*y2 = yret[1];
return n;
}
// this finds approximate solution
//
//double GetSegmentClearance( EllipseKH * el1, EllipseKH * el2,
double GetArcClearance( EllipseKH * el1, EllipseKH * el2,
double * x1, double * y1 )
{
const int NSTEPS = 32;
if( el1->theta2 > el1->theta1 )
ASSERT(0);
if( el2->theta2 > el2->theta1 )
ASSERT(0);
// test multiple positions in both arcs, moving clockwise (ie. decreasing theta)
double th_start = el1->theta1;
double th_end = el1->theta2;
double th_start2 = el2->theta1;
double th_end2 = el2->theta2;
double dmin = DBL_MAX;
double xmin, ymin, thmin, thmin2;
int nsteps = NSTEPS;
int nsteps2 = NSTEPS;
double step = (th_start-th_end)/(nsteps-1);
double step2 = (th_start2-th_end2)/(nsteps2-1);
while( (step * max(el1->xrad, el1->yrad)) > 1.0*NM_PER_MIL
&& (step2 * max(el2->xrad, el2->yrad)) > 1.0*NM_PER_MIL )
{
step = (th_start-th_end)/(nsteps-1);
for( int i=0; i<nsteps; i++ )
{
double theta;
if( i < nsteps-1 )
theta = th_start - i*step;
else
theta = th_end;
double x = el1->Center.X + el1->xrad*cos(theta);
double y = el1->Center.Y + el1->yrad*sin(theta);
step2 = (th_start2-th_end2)/(nsteps2-1);
for( int i2=0; i2<nsteps2; i2++ )
{
double theta2;
if( i2 < nsteps2-1 )
theta2 = th_start2 - i2*step2;
else
theta2 = th_end2;
double x2 = el2->Center.X + el2->xrad*cos(theta2);
double y2 = el2->Center.Y + el2->yrad*sin(theta2);
double d = Distance( x, y, x2, y2 );
if( d < dmin )
{
dmin = d;
xmin = x;
ymin = y;
thmin = theta;
thmin2 = theta2;
}
}
}
if( step > step2 )
{
th_start = min(el1->theta1, thmin + step);
th_end = max(el1->theta2, thmin - step);
step = (th_start - th_end)/nsteps;
}
else
{
th_start2 = min(el2->theta1, thmin2 + step2);
th_end2 = max(el2->theta2, thmin2 - step2);
step2 = (th_start2 - th_end2)/nsteps2;
}
}
if( x1 )
*x1 = xmin;
if( y1 )
*y1 = ymin;
return dmin;
}
// math stuff for graphics, from FreePCB
typedef struct PointTag
{
double X,Y;
} Point;
typedef struct EllipseTag
{
Point Center; /* ellipse center */
// double MaxRad,MinRad; /* major and minor axis */
// double Phi; /* major axis rotation */
double xrad, yrad; // radii on x and y
double theta1, theta2; // start and end angle for arc
} EllipseKH;
const CPoint zero(0,0);
class my_circle {
public:
my_circle(){};
my_circle( int xx, int yy, int rr )
{
x = xx;
y = yy;
r = rr;
};
int x, y, r;
};
class my_rect {
public:
my_rect(){};
my_rect( int xi, int yi, int xf, int yf )
{
xlo = min(xi,xf);
xhi = max(xi,xf);
ylo = min(yi,yf);
yhi = max(yi,yf);
};
int xlo, ylo, xhi, yhi;
};
class my_seg {
public:
my_seg(){};
my_seg( int xxi, int yyi, int xxf, int yyf )
{
xi = xxi;
yi = yyi;
xf = xxf;
yf = yyf;
};
int xi, yi, xf, yf;
};
// math stuff for graphics
BOOL Quadratic( double a, double b, double c, double *x1, double *x2 );
void DrawArc( CDC * pDC, int shape, int xxi, int yyi, int xxf, int yyf, BOOL bMeta=FALSE );
void RotatePoint( CPoint *p, int angle, CPoint org );
void RotateRect( CRect *r, int angle, CPoint org );
int TestLineHit( int xi, int yi, int xf, int yf, int x, int y, double dist );
int FindLineIntersection( double a, double b, double c, double d, double * x, double * y );
int FindLineSegmentIntersection( double a, double b, int xi, int yi, int xf, int yf, int style,
double * x1, double * y1, double * x2, double * y2, double * dist=NULL );
int FindSegmentIntersections( int xi, int yi, int xf, int yf, int style,
int xi2, int yi2, int xf2, int yf2, int style2,
double x[]=NULL, double y[]=NULL );
BOOL FindLineEllipseIntersections( double a, double b, double c, double d, double *x1, double *x2 );
BOOL FindVerticalLineEllipseIntersections( double a, double b, double x, double *y1, double *y2 );
BOOL TestForIntersectionOfStraightLineSegments( int x1i, int y1i, int x1f, int y1f,
int x2i, int y2i, int x2f, int y2f,
int * x=NULL, int * y=NULL, double * dist=NULL );
void GetPadElements( int type, int x, int y, int wid, int len, int radius, int angle,
int * nr, my_rect r[], int * nc, my_circle c[], int * ns, my_seg s[] );
int GetClearanceBetweenPads( int type1, int x1, int y1, int w1, int l1, int r1, int angle1,
int type2, int x2, int y2, int w2, int l2, int r2, int angle2 );
int GetClearanceBetweenSegmentAndPad( int x1, int y1, int x2, int y2, int w,
int type, int x, int y, int wid, int len,
int radius, int angle );
int GetClearanceBetweenSegments( int x1i, int y1i, int x1f, int y1f, int style1, int w1,
int x2i, int y2i, int x2f, int y2f, int style2, int w2,
int max_cl, int * x, int * y );
/** Function GetPointToLineSegmentDistance
* Get distance between line segment and point
* @param x,y = point
* @param xi,yi and xf,yf = the end-points of the line segment
* @return the distance
*/
double GetPointToLineSegmentDistance( int x, int y, int xi, int yi, int xf, int yf );
double GetPointToLineDistance( double a, double b, int x, int y, double * xp=NULL, double * yp=NULL );
BOOL InRange( double x, double xi, double xf );
double Distance( int x1, int y1, int x2, int y2 );
int GetArcIntersections( EllipseKH * el1, EllipseKH * el2,
double * x1=NULL, double * y1=NULL,
double * x2=NULL, double * y2=NULL );
CPoint GetInflectionPoint( CPoint pi, CPoint pf, int mode );
// quicksort (2-way or 3-way)
void quickSort(int numbers[], int index[], int array_size);
void q_sort(int numbers[], int index[], int left, int right);
void q_sort_3way( int a[], int b[], int left, int right );
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment