///////////////////////////////////////////////////////////////////////////// // 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" #include "protos.h" // For compilers that support precompilation, includes "wx/wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif ////@begin includes ////@end includes ////@begin XPM images ////@end XPM images /* 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 ); /* 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 #define ZONE_NET_SORT_OPTION_KEY wxT("Zone_NetSort_Opt") enum zone_cmd { ZONE_ABORT, ZONE_OK }; #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 ) /**********************************************************/ /* Remove the zone which include the segment aZone. * A zone is a group of segments which have the same TimeStamp */ { if( aZone == NULL ) return; int nb_segm = 0; bool modify = FALSE; unsigned long TimeStamp = aZone->m_TimeStamp; // Save reference time stamp (aZone will be deleted) SEGZONE* next; for( SEGZONE* zone = m_Pcb->m_Zone; zone != NULL; zone = next ) { next = zone->Next(); if( zone->m_TimeStamp == TimeStamp ) { modify = TRUE; /* Erase segment from screen */ Trace_Une_Piste( DrawPanel, DC, zone, nb_segm, GR_XOR ); /* remove item from linked list and free memory */ zone->DeleteStructure(); } } if( modify ) { GetScreen()->SetModify(); GetScreen()->SetRefreshReq(); } } /*****************************************************************************/ EDGE_ZONE* WinEDA_PcbFrame::Del_SegmEdgeZone( wxDC* DC, EDGE_ZONE* edge_zone ) /*****************************************************************************/ /* Routine d'effacement du segment de limite zone en cours de trace */ { EDGE_ZONE* segm; if( m_Pcb->m_CurrentLimitZone ) segm = m_Pcb->m_CurrentLimitZone; else segm = edge_zone; if( segm == NULL ) return NULL; Trace_DrawSegmentPcb( DrawPanel, DC, segm, GR_XOR ); m_Pcb->m_CurrentLimitZone = segm->Next(); delete segm; segm = m_Pcb->m_CurrentLimitZone; SetCurItem( segm ); if( segm ) { segm->Pback = NULL; if( DrawPanel->ManageCurseur ) DrawPanel->ManageCurseur( DrawPanel, DC, TRUE ); } else { DrawPanel->ManageCurseur = NULL; DrawPanel->ForceCloseManageCurseur = NULL; SetCurItem( NULL ); } return segm; } /*********************************************/ 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 ) /********************************************************/ /** * Function Exit_Zones * cancels the Begin_Zone state if at least one EDGE_ZONE has been created. */ { WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) Panel->m_Parent; if( pcbframe->m_Pcb->m_CurrentLimitZone ) { if( Panel->ManageCurseur ) // trace in progress { Panel->ManageCurseur( Panel, DC, 0 ); } pcbframe->DelLimitesZone( DC, TRUE ); } Panel->ManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL; pcbframe->SetCurItem( NULL ); } /**************************************************************/ void WinEDA_BasePcbFrame::DelLimitesZone( wxDC* DC, bool Redraw ) /**************************************************************/ { EDGE_ZONE* segment; EDGE_ZONE* next; 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 ) { next = segment->Next(); if( Redraw && DC ) Trace_DrawSegmentPcb( DrawPanel, DC, segment, GR_XOR ); delete segment; } m_Pcb->m_CurrentLimitZone = NULL; SetCurItem( NULL ); } /** * 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; oldedge = m_Pcb->m_CurrentLimitZone; if( m_Pcb->m_CurrentLimitZone == NULL ) /* Start a new contour: init zone params (net and layer) */ { DrawPanel->m_IgnoreMouseEvents = TRUE; WinEDA_ZoneFrame* frame = new WinEDA_ZoneFrame( this ); int diag = frame->ShowModal(); frame->Destroy(); DrawPanel->MouseToCursorSchema(); DrawPanel->m_IgnoreMouseEvents = FALSE; if( diag == ZONE_ABORT ) return NULL; GetScreen()->m_Active_Layer = s_Zone_Layer; /* 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 ); } // if first segment if( (m_Pcb->m_CurrentLimitZone == NULL ) /* debut reel du trace */ || (DrawPanel->ManageCurseur == NULL) ) /* reprise d'un trace complementaire */ { newedge = new EDGE_ZONE( m_Pcb ); newedge->m_Flags = IS_NEW | STARTPOINT | IS_MOVED; newedge->m_Start = newedge->m_End = GetScreen()->m_Curseur; newedge->SetLayer( GetScreen()->m_Active_Layer ); // link into list: newedge->Pnext = oldedge; if( oldedge ) oldedge->Pback = newedge; m_Pcb->m_CurrentLimitZone = newedge; DrawPanel->ManageCurseur = Show_Zone_Edge_While_MoveMouse; DrawPanel->ForceCloseManageCurseur = Exit_Zones; } // 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*/ { if( oldedge->m_Start != oldedge->m_End ) { oldedge->m_Flags &= ~(IS_NEW | IS_MOVED); newedge = new EDGE_ZONE( oldedge ); newedge->m_Flags = IS_NEW | IS_MOVED; newedge->m_Start = newedge->m_End = oldedge->m_End; newedge->SetLayer( GetScreen()->m_Active_Layer ); // link into list: newedge->Pnext = oldedge; oldedge->Pback = newedge; m_Pcb->m_CurrentLimitZone = newedge; } } return newedge; } /*********************************************/ void WinEDA_PcbFrame::End_Zone( wxDC* DC ) /*********************************************/ /* * Routine de fin de trace d'une zone (succession de segments) */ { EDGE_ZONE* edge; if( m_Pcb->m_CurrentLimitZone ) { Begin_Zone( DC ); /* le dernier point genere est de longueur tj nulle donc inutile. */ /* il sera raccorde au point de depart */ edge = m_Pcb->m_CurrentLimitZone; edge->m_Flags &= ~(IS_NEW | IS_MOVED); while( edge && edge->Next() ) { edge = edge->Next(); if( edge->m_Flags & STARTPOINT ) break; edge->m_Flags &= ~(IS_NEW | IS_MOVED); } if( edge ) { edge->m_Flags &= ~(IS_NEW | IS_MOVED); m_Pcb->m_CurrentLimitZone->m_End = edge->m_Start; } Trace_DrawSegmentPcb( DrawPanel, DC, m_Pcb->m_CurrentLimitZone, GR_XOR ); } DrawPanel->ManageCurseur = NULL; DrawPanel->ForceCloseManageCurseur = NULL; } /******************************************************************************************/ static void Show_Zone_Edge_While_MoveMouse( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ) /******************************************************************************************/ /* redessin du contour de la piste lors des deplacements de la souris */ { EDGE_ZONE* edge; EDGE_ZONE* currentEdge; WinEDA_PcbFrame* pcbframe = (WinEDA_PcbFrame*) panel->m_Parent; if( pcbframe->m_Pcb->m_CurrentLimitZone == NULL ) return; /* efface ancienne position si elle a ete deja dessinee */ if( erase ) { edge = pcbframe->m_Pcb->m_CurrentLimitZone; // for( ; edge; edge = edge->Next() ) { Trace_DrawSegmentPcb( panel, DC, edge, GR_XOR ); } } /* mise a jour de la couche */ 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 */ 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 currentEdge->m_End = pcbframe->GetScreen()->m_Curseur; Calcule_Coord_Extremite_45( currentEdge->m_Start.x, currentEdge->m_Start.y, ¤tEdge->m_End.x, ¤tEdge->m_End.y ); } else /* ici l'angle d'inclinaison est quelconque */ { currentEdge->m_End = pcbframe->GetScreen()->m_Curseur; } // for( ; currentEdge; currentEdge = currentEdge->Next() ) { Trace_DrawSegmentPcb( panel, DC, currentEdge, GR_XOR ); } } /**********************************************/ 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 */ { 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 ); int diag = frame->ShowModal(); frame->Destroy(); DrawPanel->MouseToCursorSchema(); DrawPanel->m_IgnoreMouseEvents = FALSE; 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() ) { Trace_DrawSegmentPcb( DrawPanel, DC, PtLim, GR_XOR ); PtLim->SetLayer( s_Zone_Layer ); Trace_DrawSegmentPcb( DrawPanel, DC, PtLim, GR_XOR ); } /* Show the Net */ if( (g_HightLigth_NetCode > 0) && (g_HightLigth_NetCode != s_NetcodeSelection) ) { Hight_Light( DC ); // Remoive old hightlight selection } g_HightLigth_NetCode = s_NetcodeSelection; if ( ! g_HightLigt_Status ) Hight_Light( DC ); if( g_HightLigth_NetCode > 0 ) { pt_equipot = m_Pcb->FindNet( g_HightLigth_NetCode ); if( pt_equipot == NULL ) { if( g_HightLigth_NetCode > 0 ) DisplayError( this, wxT( "Unable to find Net name" ) ); } else msg = pt_equipot->m_Netname; } else msg = _( "No Net" ); Affiche_1_Parametre( this, 22, _( "NetName" ), msg, RED ); Build_Zone( this, DC, g_HightLigth_NetCode, Zone_Exclude_Pads, s_Zone_Create_Thermal_Relief ); GetScreen()->SetModify(); }