/*******************************/ /* Edition des pistes */ /* Routines de trace de pistes */ /*******************************/ #include "fctsys.h" #include "gr_basic.h" #include "common.h" #include "pcbnew.h" #include "autorout.h" #include "protos.h" #include "drc_stuff.h" #include "trigo.h" /* Routines Locales */ static void Exit_Editrack( WinEDA_DrawPanel* panel, wxDC* DC ); void ShowNewTrackWhenMovingCursor( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ); static void ComputeBreakPoint( TRACK* track, int n, wxPoint end ); static TRACK* DeleteNullTrackSegments( BOARD* pcb, TRACK* track, int* segmcount ); static void EnsureEndTrackOnPad( D_PAD* Pad ); /* variables locales */ static int OldNetCodeSurbrillance; static int OldEtatSurbrillance; /************************************************************/ static void Exit_Editrack( WinEDA_DrawPanel* Panel, wxDC* DC ) /************************************************************/ /* routine d'annulation de la Commande Begin_Route si une piste est en cours * de tracage, ou de sortie de l'application EDITRACK. */ { WinEDA_PcbFrame* frame = (WinEDA_PcbFrame*) Panel->m_Parent; TRACK* track = (TRACK*) frame->GetCurItem(); if( track && ( track->Type()==TYPEVIA || track->Type()==TYPETRACK ) ) { /* Erase the current drawing */ ShowNewTrackWhenMovingCursor( Panel, DC, FALSE ); if( g_HightLigt_Status ) frame->Hight_Light( DC ); g_HightLigth_NetCode = OldNetCodeSurbrillance; if( OldEtatSurbrillance ) frame->Hight_Light( DC ); frame->MsgPanel->EraseMsgBox(); // Delete current (new) track TRACK* previoustrack; for( ; track; track = previoustrack ) { previoustrack = (TRACK*) track->Pback; delete track; } } Panel->ManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL; frame->SetCurItem( NULL ); } /*************************************************************/ TRACK* WinEDA_PcbFrame::Begin_Route( TRACK* track, wxDC* DC ) /*************************************************************/ /* * Routine d'initialisation d'un trace de piste et/ou de mise en place d'un * nouveau point piste * * Si pas de piste en cours de trace: * - Recherche de netname de la nouvelle piste ( pad de depart out netname * de la piste si depart sur une ancienne piste * - Met en surbrillance tout le net * - Initilise les divers pointeurs de trace * Si piste en cours: * - controle DRC * - si DRC OK : addition d'un nouveau point piste */ { D_PAD* pt_pad = NULL; TRACK* TrackOnStartPoint = NULL, * Track; int masquelayer = g_TabOneLayerMask[((PCB_SCREEN*)GetScreen())->m_Active_Layer]; EDA_BaseStruct* LockPoint; wxPoint pos = GetScreen()->m_Curseur; static int InitialTrackWidthValue; /* first track segment width. * used when we are in the auto tack width mode */ DrawPanel->ManageCurseur = ShowNewTrackWhenMovingCursor; DrawPanel->ForceCloseManageCurseur = Exit_Editrack; if( track == NULL ) /* Starting a new track */ { /* undrw old hightlight */ OldNetCodeSurbrillance = g_HightLigth_NetCode; OldEtatSurbrillance = g_HightLigt_Status; if( g_HightLigt_Status ) Hight_Light( DC ); InitialTrackWidthValue = -1; // Set to "no value" g_FirstTrackSegment = g_CurrentTrackSegment = new TRACK( m_Pcb ); g_CurrentTrackSegment->m_Flags = IS_NEW; g_TrackSegmentCount = 1; g_HightLigth_NetCode = 0; /* Search for a pad at starting point of the new track: */ LockPoint = LocateLockPoint( m_Pcb, pos, masquelayer ); if( LockPoint ) // An item (pad or track) is found { if( LockPoint->Type() == TYPEPAD ) { pt_pad = (D_PAD*) LockPoint; /* A pad is found: put the starting point on pad centre */ pos = pt_pad->m_Pos; g_HightLigth_NetCode = pt_pad->GetNet(); } else /* A track segment is found */ { TrackOnStartPoint = (TRACK*) LockPoint; g_HightLigth_NetCode = TrackOnStartPoint->GetNet(); CreateLockPoint( &pos.x, &pos.y, TrackOnStartPoint, NULL ); } } build_ratsnest_pad( LockPoint, wxPoint( 0, 0 ), TRUE ); Hight_Light( DC ); g_CurrentTrackSegment->m_Flags = IS_NEW; g_CurrentTrackSegment->SetLayer( ((PCB_SCREEN*)GetScreen())->m_Active_Layer ); g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth; if( g_DesignSettings.m_UseConnectedTrackWidth ) { if( TrackOnStartPoint && TrackOnStartPoint->Type() == TYPETRACK ) { InitialTrackWidthValue = TrackOnStartPoint->m_Width; g_CurrentTrackSegment->m_Width = InitialTrackWidthValue; } } g_CurrentTrackSegment->m_Start = pos; g_CurrentTrackSegment->m_End = g_CurrentTrackSegment->m_Start; g_CurrentTrackSegment->SetNet( g_HightLigth_NetCode ); if( pt_pad ) { g_CurrentTrackSegment->start = pt_pad; g_CurrentTrackSegment->SetState( BEGIN_ONPAD, ON ); } else g_CurrentTrackSegment->start = TrackOnStartPoint; if( g_TwoSegmentTrackBuild ) { // Create 2 segments g_CurrentTrackSegment = g_CurrentTrackSegment->Copy(); g_TrackSegmentCount++; g_CurrentTrackSegment->Pback = g_FirstTrackSegment; g_FirstTrackSegment->Pnext = g_CurrentTrackSegment; g_CurrentTrackSegment->start = g_FirstTrackSegment; g_FirstTrackSegment->end = g_CurrentTrackSegment; g_FirstTrackSegment->SetState( BEGIN_ONPAD | END_ONPAD, OFF ); } g_CurrentTrackSegment->Display_Infos( this ); SetCurItem( g_CurrentTrackSegment ); DrawPanel->ManageCurseur( DrawPanel, DC, FALSE ); if( Drc_On ) { if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment, m_Pcb->m_Track ) ) { return g_CurrentTrackSegment; } } } else /* Track in progress : segment coordinates are updated by ShowNewTrackWhenMovingCursor*/ { /* Tst for a D.R.C. error: */ if( Drc_On ) { if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment, m_Pcb->m_Track ) ) return NULL; if( g_TwoSegmentTrackBuild // We must handle 2 segments && g_CurrentTrackSegment->Back() ) { if( BAD_DRC == m_drc->Drc( g_CurrentTrackSegment->Back(), m_Pcb->m_Track ) ) return NULL; } } /* Current track is Ok: current segment is kept, and a new one is created * unless the current segment is null, or 2 last are null if a 2 segments track build */ bool CanCreateNewSegment = TRUE; if( !g_TwoSegmentTrackBuild && g_CurrentTrackSegment->IsNull() ) CanCreateNewSegment = FALSE; if( g_TwoSegmentTrackBuild && g_CurrentTrackSegment->IsNull() && g_CurrentTrackSegment->Back() && g_CurrentTrackSegment->Back()->IsNull() ) CanCreateNewSegment = FALSE; if( CanCreateNewSegment ) { /* Erase old track on screen */ ShowNewTrackWhenMovingCursor( DrawPanel, DC, FALSE ); if( g_Raccord_45_Auto ) { if( Add_45_degrees_Segment( DC, g_CurrentTrackSegment ) != 0 ) g_TrackSegmentCount++; } Track = g_CurrentTrackSegment->Copy(); Track->Insert( m_Pcb, g_CurrentTrackSegment ); Track->SetState( BEGIN_ONPAD | END_ONPAD, OFF ); g_CurrentTrackSegment->end = Locate_Pad_Connecte( m_Pcb, g_CurrentTrackSegment, END ); if( g_CurrentTrackSegment->end ) { g_CurrentTrackSegment->SetState( END_ONPAD, ON ); Track->SetState( BEGIN_ONPAD, ON ); } Track->start = g_CurrentTrackSegment->end; g_CurrentTrackSegment = Track; g_CurrentTrackSegment->m_Flags = IS_NEW; g_TrackSegmentCount++; g_CurrentTrackSegment->m_Start = g_CurrentTrackSegment->m_End; g_CurrentTrackSegment->SetLayer( ((PCB_SCREEN*)GetScreen())->m_Active_Layer ); if( !g_DesignSettings.m_UseConnectedTrackWidth ) { g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth; } /* Show the new position */ ShowNewTrackWhenMovingCursor( DrawPanel, DC, FALSE ); } g_CurrentTrackSegment->Display_Infos( this ); } SetCurItem( g_CurrentTrackSegment ); return g_CurrentTrackSegment; } /**************************************************************************/ int WinEDA_PcbFrame::Add_45_degrees_Segment( wxDC* DC, TRACK* pt_segm ) /***************************************************************************/ /* rectifie un virage a 90 et le modifie par 2 coudes a 45 * n'opere que sur des segments horizontaux ou verticaux. * * entree : pointeur sur le segment qui vient d'etre trace * On suppose que le segment precedent est celui qui a ete * precedement trace * retourne: * 1 si ok * 0 si impossible */ { TRACK* Previous; TRACK* NewTrack; int pas_45; int dx0, dy0, dx1, dy1; if( g_TrackSegmentCount < 2 ) return 0; /* il faut au moins 2 segments */ Previous = (TRACK*) pt_segm->Pback; // pointe le segment precedent // Test s'il y a 2 segments consecutifs a raccorder if( (pt_segm->Type() != TYPETRACK ) || (Previous->Type() != TYPETRACK) ) { return 0; } pas_45 = GetScreen()->GetGrid().x / 2; if( pas_45 < pt_segm->m_Width ) pas_45 = GetScreen()->GetGrid().x; while( pas_45 < pt_segm->m_Width ) pas_45 *= 2; // OK : tst si les segments sont a 90 degre et vertic ou horiz dx0 = Previous->m_End.x - Previous->m_Start.x; dy0 = Previous->m_End.y - Previous->m_Start.y; dx1 = pt_segm->m_End.x - pt_segm->m_Start.x; dy1 = pt_segm->m_End.y - pt_segm->m_Start.y; // les segments doivent etre de longueur suffisante: if( MAX( abs( dx0 ), abs( dy0 ) ) < (pas_45 * 2) ) return 0; if( MAX( abs( dx1 ), abs( dy1 ) ) < (pas_45 * 2) ) return 0; /* creation du nouveau segment, raccordant des 2 segm: */ NewTrack = pt_segm->Copy(); NewTrack->m_Start.x = Previous->m_End.x; NewTrack->m_Start.y = Previous->m_End.y; NewTrack->m_End.x = pt_segm->m_Start.x; NewTrack->m_End.y = pt_segm->m_Start.y; if( dx0 == 0 ) // Segment precedent Vertical { if( dy1 != 0 ) // les 2 segments ne sont pas a 90 ; { delete NewTrack; return 0; } /* Calcul des coordonnees du point de raccord : * le nouveau segment raccorde le 1er segment Vertical * au 2eme segment Horizontal */ if( dy0 > 0 ) NewTrack->m_Start.y -= pas_45; else NewTrack->m_Start.y += pas_45; if( dx1 > 0 ) NewTrack->m_End.x += pas_45; else NewTrack->m_End.x -= pas_45; if( Drc_On && BAD_DRC==m_drc->Drc( pt_segm, m_Pcb->m_Track ) ) { delete NewTrack; return 0; } Previous->m_End = NewTrack->m_Start; pt_segm->m_Start = NewTrack->m_End; NewTrack->Insert( m_Pcb, Previous ); return 1; } if( dy0 == 0 ) // Segment precedent Horizontal : dy0 = 0 { if( dx1 != 0 ) // les 2 segments ne sont pas a 90 ; { delete NewTrack; return 0; } // Segments a 90 /* Modif des coordonnees du point de raccord : * un nouveau segment a ete cree, raccordant le 1er segment Horizontal * au 2eme segment Vertical */ if( dx0 > 0 ) NewTrack->m_Start.x -= pas_45; else NewTrack->m_Start.x += pas_45; if( dy1 > 0 ) NewTrack->m_End.y += pas_45; else NewTrack->m_End.y -= pas_45; if( Drc_On && BAD_DRC==m_drc->Drc( NewTrack, m_Pcb->m_Track ) ) { delete NewTrack; return 0; } Previous->m_End = NewTrack->m_Start; pt_segm->m_Start = NewTrack->m_End; NewTrack->Insert( m_Pcb, Previous ); return 1; } return 0; } /**************************************************************/ void WinEDA_PcbFrame::End_Route( TRACK* track, wxDC* DC ) /*************************************************************/ /* * Routine de fin de trace d'une piste (succession de segments) */ { int masquelayer = g_TabOneLayerMask[((PCB_SCREEN*)GetScreen())->m_Active_Layer]; wxPoint pos; EDA_BaseStruct* LockPoint; TRACK* adr_buf; if( track == NULL ) return; if( Drc_On && BAD_DRC==m_drc->Drc( g_CurrentTrackSegment, m_Pcb->m_Track ) ) return; /* Sauvegarde des coord du point terminal de la piste */ pos = g_CurrentTrackSegment->m_End; if( Begin_Route( track, DC ) == NULL ) return; ShowNewTrackWhenMovingCursor( DrawPanel, DC, TRUE ); /* mise a jour trace reel */ ShowNewTrackWhenMovingCursor( DrawPanel, DC, FALSE ); /* efface trace piste*/ trace_ratsnest_pad( DC ); /* efface trace chevelu*/ // cleanup if( g_CurrentTrackSegment->Pnext != NULL ) { delete g_CurrentTrackSegment->Pnext; g_CurrentTrackSegment->Pnext = NULL; } /* La piste est ici non chainee a la liste des segments de piste. * Il faut la replacer dans la zone de net, * le plus pres possible du segment d'attache ( ou de fin ), car * ceci contribue a la reduction du temps de calcul */ /* Accrochage de la fin de la piste */ LockPoint = LocateLockPoint( m_Pcb, pos, masquelayer ); if( LockPoint ) /* La fin de la piste est sur un PAD */ { if( LockPoint->Type() == TYPEPAD ) { EnsureEndTrackOnPad( (D_PAD*) LockPoint ); } else /* la fin de la piste est sur une autre piste: il faudra * peut-etre creer un point d'ancrage */ { adr_buf = (TRACK*) LockPoint; g_HightLigth_NetCode = adr_buf->GetNet(); /* creation eventuelle d'un point d'accrochage */ LockPoint = CreateLockPoint( &g_CurrentTrackSegment->m_End.x, &g_CurrentTrackSegment->m_End.y, adr_buf, g_CurrentTrackSegment ); } } // Delete Null segments: g_FirstTrackSegment = DeleteNullTrackSegments( m_Pcb, g_FirstTrackSegment, &g_TrackSegmentCount ); /* Test if no segment left. Can happend on a double click on the start point */ if( g_FirstTrackSegment != NULL ) { // Put new track in board m_Pcb->Add( g_FirstTrackSegment ); trace_ratsnest_pad( DC ); Trace_Une_Piste( DrawPanel, DC, g_FirstTrackSegment, g_TrackSegmentCount, GR_OR ); // Reset flags: TRACK* ptr = g_FirstTrackSegment; int ii; for( ii = 0; (ptr != NULL) && (ii < g_TrackSegmentCount); ii++ ) { ptr->m_Flags = 0; ptr = ptr->Next(); } /* Delete the old track, if exists */ if( g_AutoDeleteOldTrack ) { EraseOldTrack( this, m_Pcb, DC, g_FirstTrackSegment, g_TrackSegmentCount ); } /* compute the new rastnest : */ test_1_net_connexion( DC, g_FirstTrackSegment->GetNet() ); GetScreen()->SetModify(); m_Pcb->Display_Infos( this ); } /* Finish the work, clear used variables */ g_FirstTrackSegment = NULL; if( g_HightLigt_Status ) Hight_Light( DC ); g_HightLigth_NetCode = OldNetCodeSurbrillance; if( OldEtatSurbrillance ) Hight_Light( DC ); DrawPanel->ManageCurseur = NULL; DrawPanel->ForceCloseManageCurseur = NULL; SetCurItem( NULL ); } TRACK* LocateIntrusion( TRACK* start, int net, int width ) { int layer = ( (PCB_SCREEN*) ActiveScreen )->m_Active_Layer; int layer_mask = g_TabOneLayerMask[layer]; wxPoint ref = ActiveScreen->RefPos( 1 ); TRACK* track, * found = NULL; for( track = start; track; track = track->Next() ) { int dist; wxPoint pos, vec; int64_t tmp; /* Locate_Pistes */ if( track->GetState( BUSY | DELETED ) ) continue; if( !(g_TabOneLayerMask[track->GetLayer()] & layer_mask) ) continue; if( track->GetNet() == net ) continue; if( track->Type() == TYPEVIA ) continue; /* TRACK::HitTest */ dist = width / 2 + track->m_Width / 2 + g_DesignSettings.m_TrackClearence; pos = ref - track->m_Start; vec = track->m_End - track->m_Start; if( !DistanceTest( dist, vec.x, vec.y, pos.x, pos.y ) ) continue; found = track; /* prefer intrusions from the side, not the end */ tmp = (int64_t) pos.x * vec.x + (int64_t) pos.y * vec.y; if( tmp >= 0 && tmp <= (int64_t) vec.x * vec.x + (int64_t) vec.y * vec.y ) break; } return found; } /** * Function PushTrack * detects if the mouse is pointing into a conflicting track. * In this case, it tries to push the new track out of the conflicting track's * clearance zone. This gives us a cheap mechanism for drawing tracks that * tightly follow others, independent of grid settings. * * KNOWN BUGS: * - we do the same sort of search and calculation up to three times: * 1) we search for magnetic hits (in controle.cpp) * 2) we check if there's a DRC violation in the making (also controle.cpp) * 3) we try to fix the DRC violation (here) * - if we have a magnetic hit and a DRC violation at the same time, we choose * the magnetic hit instead of solving the violation * - should locate conflicting tracks also when we're crossing over them */ static void PushTrack( WinEDA_DrawPanel* panel ) { BOARD* pcb = ( (WinEDA_BasePcbFrame*) (panel->m_Parent) )->m_Pcb; wxPoint cursor = ActiveScreen->m_Curseur; wxPoint cv, vec, n; TRACK* track = g_CurrentTrackSegment; TRACK* other; int64_t det; int dist; double f; other = LocateIntrusion( pcb->m_Track, track->GetNet(), track->m_Width ); /* are we currently pointing into a conflicting trace ? */ if( !other ) return; if( other->GetNet() == track->GetNet() ) return; cv = cursor - other->m_Start; vec = other->m_End - other->m_Start; det = (int64_t) cv.x * vec.y - (int64_t) cv.y * vec.x; /* cursor is right at the center of the old track */ if( !det ) return; dist = (track->m_Width + 1) / 2 + (other->m_Width + 1) / 2 + g_DesignSettings.m_TrackClearence + 2; /* * DRC wants >, so +1. * We may have a quantization error of 1/sqrt(2), so +1 again. */ /* Vector "n" is perpendicular to "other", pointing towards the cursor. */ if( det > 0 ) { n.x = vec.y; n.y = -vec.x; } else { n.x = -vec.y; n.y = vec.x; } f = dist / hypot( n.x, n.y ); n.x = (int) round( f * n.x ); n.y = (int) round( f * n.y ); Project( track->m_End, cursor, other ); track->m_End += n; } /****************************************************************************/ void ShowNewTrackWhenMovingCursor( WinEDA_DrawPanel* panel, wxDC* DC, bool erase ) /****************************************************************************/ /* redessin du contour de la piste lors des deplacements de la souris * Cette routine est utilisee comme .ManageCurseur() * si ShowIsolDuringCreateTrack_Item.State == RUN la marge d'isolation * est aussi affichee */ { int IsolTmp, Track_fill_copy; PCB_SCREEN* screen = (PCB_SCREEN*) panel->GetScreen(); Track_fill_copy = DisplayOpt.DisplayPcbTrackFill; DisplayOpt.DisplayPcbTrackFill = SKETCH; IsolTmp = DisplayOpt.DisplayTrackIsol; if( g_ShowIsolDuringCreateTrack ) DisplayOpt.DisplayTrackIsol = TRUE; /* efface ancienne position si elle a ete deja dessinee */ if( erase ) { Trace_Une_Piste( panel, DC, g_FirstTrackSegment, g_TrackSegmentCount, GR_XOR ); ( (WinEDA_BasePcbFrame*) (panel->m_Parent) )->trace_ratsnest_pad( DC ); } /* dessin de la nouvelle piste : mise a jour du point d'arrivee */ g_CurrentTrackSegment->SetLayer( screen->m_Active_Layer ); if( ! g_DesignSettings.m_UseConnectedTrackWidth ) g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth; if( g_TwoSegmentTrackBuild ) { TRACK* previous_track = (TRACK*) g_CurrentTrackSegment->Pback; if( previous_track && (previous_track->Type() == TYPETRACK) ) { previous_track->SetLayer( screen->m_Active_Layer ); if( ! g_DesignSettings.m_UseConnectedTrackWidth ) previous_track->m_Width = g_DesignSettings.m_CurrentTrackWidth; } } if( Track_45_Only ) { if( g_TwoSegmentTrackBuild ) { g_CurrentTrackSegment->m_End = ActiveScreen->m_Curseur; if (Drc_On) PushTrack(panel); ComputeBreakPoint( g_CurrentTrackSegment, g_TrackSegmentCount, g_CurrentTrackSegment->m_End); } else { /* Calcul de l'extremite de la piste pour orientations permises: * horiz,vertical ou 45 degre */ Calcule_Coord_Extremite_45( g_CurrentTrackSegment->m_Start.x, g_CurrentTrackSegment->m_Start.y, &g_CurrentTrackSegment->m_End.x, &g_CurrentTrackSegment->m_End.y ); } } else /* ici l'angle d'inclinaison est quelconque */ { g_CurrentTrackSegment->m_End = screen->m_Curseur; } Trace_Une_Piste( panel, DC, g_FirstTrackSegment, g_TrackSegmentCount, GR_XOR ); DisplayOpt.DisplayTrackIsol = IsolTmp; DisplayOpt.DisplayPcbTrackFill = Track_fill_copy; ( (WinEDA_BasePcbFrame*) (panel->m_Parent) )-> build_ratsnest_pad( NULL, g_CurrentTrackSegment->m_End, FALSE ); ( (WinEDA_BasePcbFrame*) (panel->m_Parent) )->trace_ratsnest_pad( DC ); } /*****************************************************************/ void Calcule_Coord_Extremite_45( int ox, int oy, int* fx, int* fy ) /*****************************************************************/ /* determine les parametres .fx et .fy du segment pointe par pt_segm * pour avoir un segment oriente a 0, 90 ou 45 degres, selon position * du oint d'origine et de la souris */ { int deltax, deltay, angle; deltax = ActiveScreen->m_Curseur.x - ox; deltay = ActiveScreen->m_Curseur.y - oy; /* calcul de l'angle preferentiel : 0, 45 , 90 degre */ deltax = abs( deltax ); deltay = abs( deltay ); angle = 45; if( deltax >= deltay ) { if( deltax == 0 ) angle = 0; else if( ( (deltay << 6 ) / deltax ) < 26 ) angle = 0; } else { angle = 45; if( deltay == 0 ) angle = 90; else if( ( (deltax << 6 ) / deltay ) < 26 ) angle = 90; } switch( angle ) { case 0: *fx = ActiveScreen->m_Curseur.x; *fy = oy; break; case 45: deltax = MIN( deltax, deltay ); deltay = deltax; /* recalcul des signes de deltax et deltay */ if( (ActiveScreen->m_Curseur.x - ox) < 0 ) deltax = -deltax; if( (ActiveScreen->m_Curseur.y - oy) < 0 ) deltay = -deltay; *fx = ox + deltax; *fy = oy + deltay; break; case 90: *fx = ox; *fy = ActiveScreen->m_Curseur.y; break; } } /********************************************************/ void ComputeBreakPoint( TRACK* track, int SegmentCount, wxPoint end ) /********************************************************/ /** * Compute new track angle based on previous track. */ { int iDx = 0; int iDy = 0; int iAngle = 0; if( SegmentCount <= 0 ) return; if( track == NULL ) return; TRACK* NewTrack = track; track = (TRACK*) track->Pback; SegmentCount--; if( track ) { iDx = end.x - track->m_Start.x; iDy = end.y - track->m_Start.y; iDx = abs( iDx ); iDy = abs( iDy ); } TRACK* LastTrack = track ? (TRACK*) track->Pback : NULL; if( LastTrack ) { if( (LastTrack->m_End.x == LastTrack->m_Start.x) || (LastTrack->m_End.y == LastTrack->m_Start.y) ) { iAngle = 45; } } if( iAngle == 0 ) { if( iDx >= iDy ) iAngle = 0; else iAngle = 90; } if( track == NULL ) iAngle = -1; switch( iAngle ) { case - 1: break; case 0: if( (end.x - track->m_Start.x) < 0 ) track->m_End.x = end.x + iDy; else track->m_End.x = end.x - iDy; track->m_End.y = track->m_Start.y; break; case 45: iDx = MIN( iDx, iDy ); iDy = iDx; /* recalcul des signes de deltax et deltay */ if( (end.x - track->m_Start.x) < 0 ) iDx = -iDx; if( (end.y - track->m_Start.y) < 0 ) iDy = -iDy; track->m_End.x = track->m_Start.x + iDx; track->m_End.y = track->m_Start.y + iDy; break; case 90: if( (end.y - track->m_Start.y) < 0 ) track->m_End.y = end.y + iDx; else track->m_End.y = end.y - iDx; track->m_End.x = track->m_Start.x; break; } if( track ) { if( track->IsNull() ) track->m_End = end; NewTrack->m_Start = track->m_End; } NewTrack->m_End = end; } /****************************************************************************/ TRACK* DeleteNullTrackSegments( BOARD* pcb, TRACK* track, int* segmcount ) /****************************************************************************/ /* Delete track segments which have len = 0; after creating a new track * return a pointer on the first segment (start of track list) */ { TRACK* firsttrack = track; TRACK* oldtrack; int nn = 0; BOARD_ITEM* LockPoint; if( track == 0 ) return NULL; LockPoint = track->start; while( track != NULL ) { oldtrack = track; track = track->Next(); if( !oldtrack->IsNull() ) { nn++; continue; } // NULL segment, delete it if( firsttrack == oldtrack ) firsttrack = track; oldtrack->UnLink(); delete oldtrack; } if( segmcount ) *segmcount = nn; if( nn == 0 ) return NULL; // all the new track segments have been deleted // we must set the pointers on connected items and the connection status oldtrack = track = firsttrack; firsttrack->start = NULL; while( track != NULL ) { oldtrack = track; track = track->Next(); oldtrack->end = track; if( track ) track->start = oldtrack; oldtrack->SetStatus( 0 ); } firsttrack->start = LockPoint; if( LockPoint && (LockPoint->Type() == TYPEPAD ) ) firsttrack->SetState( BEGIN_ONPAD, ON ); track = firsttrack; while( track != NULL ) { TRACK* next_track = track->Next(); LockPoint = Locate_Pad_Connecte( pcb, track, END ); if( LockPoint ) { track->end = LockPoint; track->SetState( END_ONPAD, ON ); if( next_track ) { next_track->start = LockPoint; next_track->SetState( BEGIN_ONPAD, ON ); } } track = next_track; } return firsttrack; } /************************************/ void EnsureEndTrackOnPad( D_PAD* Pad ) /************************************/ /* Ensure the end point of g_CurrentTrackSegment is on the pas "Pad" * if no, create a new track segment if necessary * and move current (or new) end segment on pad */ { if( g_CurrentTrackSegment->m_End == Pad->m_Pos ) // Ok ! { g_CurrentTrackSegment->end = Pad; g_CurrentTrackSegment->SetState( END_ONPAD, ON ); return; } TRACK* lasttrack = g_CurrentTrackSegment; if( !g_CurrentTrackSegment->IsNull() ) { /* Must create a new segment, from track end to pad center */ g_CurrentTrackSegment = lasttrack->Copy(); g_TrackSegmentCount++; lasttrack->Pnext = g_CurrentTrackSegment; g_CurrentTrackSegment->Pback = lasttrack; lasttrack->end = g_CurrentTrackSegment; } g_CurrentTrackSegment->m_End = Pad->m_Pos; g_CurrentTrackSegment->SetState( END_ONPAD, OFF ); g_CurrentTrackSegment->end = Pad; g_CurrentTrackSegment->SetState( END_ONPAD, ON ); }