/*******************************/ /* 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" /* Routines Locales */ static void Exit_Editrack(WinEDA_DrawPanel * panel, wxDC *DC); void ShowNewTrackWhenMovingCursor(WinEDA_DrawPanel * panel, wxDC * DC, bool erase); static int Met_Coude_a_45(WinEDA_BasePcbFrame * frame, wxDC * DC, TRACK * ptfinsegment); static void ComputeBreakPoint( TRACK * track, int n ); 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->GetScreen()->m_CurrentItem; if( track != NULL ) { /* 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(); TRACK * previoustrack; // Delete current (new) track for( ;track != NULL; track = previoustrack) { previoustrack = (TRACK*) track->Pback; delete track; } } Panel->ManageCurseur = NULL; Panel->ForceCloseManageCurseur = NULL; frame->GetScreen()->m_CurrentItem = 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 * adr_buf = NULL, * Track; int masquelayer = g_TabOneLayerMask[GetScreen()->m_Active_Layer]; EDA_BaseStruct * LockPoint; wxPoint pos = GetScreen()->m_Curseur; DrawPanel->ManageCurseur = ShowNewTrackWhenMovingCursor; DrawPanel->ForceCloseManageCurseur = Exit_Editrack; if(track == NULL ) /* debut reel du trace */ { /* effacement surbrillance ancienne */ OldNetCodeSurbrillance = g_HightLigth_NetCode; OldEtatSurbrillance = g_HightLigt_Status; if(g_HightLigt_Status) Hight_Light(DC); g_FirstTrackSegment = g_CurrentTrackSegment = new TRACK(m_Pcb); g_CurrentTrackSegment->m_Flags = IS_NEW; g_TrackSegmentCount = 1; g_HightLigth_NetCode = 0; /* Localisation de la pastille de reference de la piste: */ LockPoint = LocateLockPoint(m_Pcb, pos, masquelayer); if( LockPoint ) { if( LockPoint->m_StructType == TYPEPAD ) { pt_pad = (D_PAD *) LockPoint; /* le debut de la piste est remis sur le centre du pad */ pos = pt_pad->m_Pos; g_HightLigth_NetCode = pt_pad->m_NetCode; } else /* le point d'accrochage est un segment */ { adr_buf = (TRACK *) LockPoint; g_HightLigth_NetCode = adr_buf->m_NetCode; CreateLockPoint( &pos.x, &pos.y, adr_buf, NULL); } } build_ratsnest_pad(LockPoint, wxPoint(0,0), TRUE); Hight_Light(DC); g_CurrentTrackSegment->m_Flags = IS_NEW; g_CurrentTrackSegment->m_Layer = GetScreen()->m_Active_Layer; g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth ; g_CurrentTrackSegment->m_Start = pos; g_CurrentTrackSegment->m_End = g_CurrentTrackSegment->m_Start; g_CurrentTrackSegment->m_NetCode = g_HightLigth_NetCode ; if(pt_pad) { g_CurrentTrackSegment->start = pt_pad ; g_CurrentTrackSegment->SetState(BEGIN_ONPAD,ON); } else g_CurrentTrackSegment->start = adr_buf ; if ( g_TwoSegmentTrackBuild ) { // Create 2 segments g_CurrentTrackSegment = new TRACK(*g_CurrentTrackSegment); 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); } Affiche_Infos_Piste(this, g_CurrentTrackSegment) ; GetScreen()->m_CurrentItem = g_CurrentTrackSegment; DrawPanel->ManageCurseur(DrawPanel, DC, FALSE); if( Drc_On && (Drc(this, DC,g_CurrentTrackSegment,m_Pcb->m_Track,1 ) == BAD_DRC) ) { return g_CurrentTrackSegment; } } else /* Track in progress : segment coordinates are updated by ShowNewTrackWhenMovingCursor*/ { /* Tst for a D.R.C. error: */ if ( Drc_On ) { if ( Drc(this, DC,g_CurrentTrackSegment,m_Pcb->m_Track,1 ) == BAD_DRC) return NULL; if ( g_TwoSegmentTrackBuild && // We must handle 2 segments g_CurrentTrackSegment->Back() ) { if( Drc(this, DC,g_CurrentTrackSegment->Back(),m_Pcb->m_Track,1 ) == BAD_DRC ) 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( Met_Coude_a_45(this, 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->m_Layer = GetScreen()->m_Active_Layer; g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth ; /* Show the new position */ ShowNewTrackWhenMovingCursor(DrawPanel, DC, FALSE); } Affiche_Infos_Piste(this, g_CurrentTrackSegment) ; } GetScreen()->m_CurrentItem = g_CurrentTrackSegment; return g_CurrentTrackSegment; } /**************************************************************************/ int Met_Coude_a_45(WinEDA_BasePcbFrame * frame, 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->m_StructType != TYPETRACK ) || (Previous->m_StructType != TYPETRACK) ) { return(0) ; } pas_45 = frame->GetScreen()->GetGrid().x / 2 ; if( pas_45 < pt_segm->m_Width ) pas_45 = frame->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 && (Drc(frame, DC, pt_segm, frame->m_Pcb->m_Track, 1) == BAD_DRC) ) { delete NewTrack; return(0) ; } Previous->m_End = NewTrack->m_Start; pt_segm->m_Start = NewTrack->m_End; NewTrack->Insert(frame->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 && (Drc(frame, DC, NewTrack, frame->m_Pcb->m_Track, 1) == BAD_DRC) ) { delete NewTrack; return(0); } Previous->m_End = NewTrack->m_Start; pt_segm->m_Start = NewTrack->m_End; NewTrack->Insert(frame->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) */ { TRACK * pt_track; int masquelayer = g_TabOneLayerMask[GetScreen()->m_Active_Layer]; wxPoint pos; EDA_BaseStruct * LockPoint; TRACK * adr_buf; if( track == NULL ) return; if ( Drc_On && ( Drc(this, DC,g_CurrentTrackSegment,m_Pcb->m_Track,1 ) == BAD_DRC) ) 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->m_StructType == 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->m_NetCode; /* 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 buffer: search the best insertion poinr */ pt_track = g_FirstTrackSegment->GetBestInsertPoint(m_Pcb); /* Uut track in linked list */ g_FirstTrackSegment->Insert(m_Pcb, pt_track); 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->m_NetCode ); GetScreen()->SetModify(); Affiche_Infos_Status_Pcb(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; GetScreen()->m_CurrentItem = NULL; } /****************************************************************************/ 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->m_Layer = screen->m_Active_Layer; g_CurrentTrackSegment->m_Width = g_DesignSettings.m_CurrentTrackWidth; if (Track_45_Only) { if ( g_TwoSegmentTrackBuild ) ComputeBreakPoint(g_CurrentTrackSegment, g_TrackSegmentCount); 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 ) /********************************************************/ /** * 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 = ActiveScreen->m_Curseur.x - track->m_Start.x; iDy = ActiveScreen->m_Curseur.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 ( (ActiveScreen->m_Curseur.x - track->m_Start.x) < 0 ) track->m_End.x = ActiveScreen->m_Curseur.x + iDy; else track->m_End.x = ActiveScreen->m_Curseur.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( (ActiveScreen->m_Curseur.x - track->m_Start.x) < 0 ) iDx = -iDx; if( (ActiveScreen->m_Curseur.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 ( (ActiveScreen->m_Curseur.y - track->m_Start.y) < 0 ) track->m_End.y = ActiveScreen->m_Curseur.y + iDx; else track->m_End.y = ActiveScreen->m_Curseur.y - iDx; track->m_End.x = track->m_Start.x; break ; } if ( track ) { if ( track->IsNull() ) track->m_End = ActiveScreen->m_Curseur; NewTrack->m_Start = track->m_End; } NewTrack->m_End = ActiveScreen->m_Curseur; } /****************************************************************************/ 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; EDA_BaseStruct * LockPoint; 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->m_StructType == 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 = new TRACK(*lasttrack); 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); }