diff options
Diffstat (limited to 'app/bin/cgroup.c')
-rw-r--r-- | app/bin/cgroup.c | 1210 |
1 files changed, 674 insertions, 536 deletions
diff --git a/app/bin/cgroup.c b/app/bin/cgroup.c index 1183e76..6940ea0 100644 --- a/app/bin/cgroup.c +++ b/app/bin/cgroup.c @@ -18,27 +18,32 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include <ctype.h> -#include <math.h> -#include <string.h> - +#include "cselect.h" #include "compound.h" #include "cundo.h" #include "custom.h" #include "fileio.h" -#include "i18n.h" #include "tbezier.h" #include "tcornu.h" #include "common.h" -#include "messages.h" #include "param.h" #include "shrtpath.h" #include "track.h" -#include "utility.h" +#include "trkendpt.h" +#include "common-ui.h" +/* + * Note: Bumper support + * Currently Ungroup will convert 1 ended Turnouts (Bumpers) to simple 2-ended Straight + * Group will remove any Bumpers from the Selected track list + * See TODO-BUMPER + * + * The remaining issue is that the ShortestPath logic aborts if it gets to the end of a + * path elem list and can't find the corresponing EP. + */ /***************************************************************************** * @@ -54,87 +59,96 @@ static dynArr_t pathPtr_da; static char groupManuf[STR_SIZE]; static char groupDesc[STR_SIZE]; static char groupPartno[STR_SIZE]; -static char groupTitle[STR_SIZE]; +static char groupTitle[STR_LONG_SIZE]; static int groupCompoundCount = 0; -extern TRKTYP_T T_BZRTRK; -extern TRKTYP_T T_BZRLIN; -extern TRKTYP_T T_CORNU; + +/***************************************************************************** + * + * Ungroup + * + */ typedef struct { - int segInx; - EPINX_T segEP; - int inx; - track_p trk; - } mergePt_t; + int segInx; + EPINX_T segEP; + int inx; + track_p trk; +} mergePt_t; static dynArr_t mergePt_da; #define mergePt(N) DYNARR_N( mergePt_t, mergePt_da, N ) static void AddMergePt( - int segInx, - EPINX_T segEP ) + int segInx, + EPINX_T segEP ) { int inx; mergePt_t * mp; for ( inx=0; inx<mergePt_da.cnt; inx++ ) { mp = &mergePt(inx); if ( mp->segInx == segInx && - mp->segEP == segEP ) + mp->segEP == segEP ) { return; + } } DYNARR_APPEND( mergePt_t, mergePt_da, 10 ); mp = &mergePt(mergePt_da.cnt-1); mp->segInx = segInx; mp->segEP = segEP; mp->inx = mergePt_da.cnt-1; -LOG( log_group, 2, ( " MergePt: %d.%d\n", segInx, segEP ) ); + LOG( log_group, 2, ( " MergePt: %d.%d\n", segInx, segEP ) ); } static EPINX_T FindEP( - EPINX_T epCnt, - trkEndPt_p endPts, - coOrd pos ) + EPINX_T epCnt, + trkEndPt_p endPts, + coOrd pos ) { DIST_T dist; EPINX_T ep; for ( ep=0; ep<epCnt; ep++ ) { - dist = FindDistance( pos, endPts[ep].pos ); - if ( dist < connectDistance ) + dist = FindDistance( pos, GetEndPtPos( EndPtIndex( endPts, ep ) ) ); + if ( dist < connectDistance ) { return ep; + } } return -1; } static void SegOnMP( - int segInx, - int mpInx, - int segCnt, - int * map ) + int segInx, + int mpInx, + int segCnt, + int * map ) { int inx; mergePt_t * mp; if ( map[segInx] < 0 ) { -LOG( log_group, 2, ( " S%d: on MP%d\n", segInx, mpInx ) ); + LOG( log_group, 2, ( " S%d: on MP%d\n", segInx, mpInx ) ); map[segInx] = mpInx; return; } -LOG( log_group, 2, ( " S%d: remapping MP%d to MP%d\n", segInx, mpInx, map[segInx] ) ); + LOG( log_group, 2, ( " S%d: remapping MP%d to MP%d\n", segInx, mpInx, + map[segInx] ) ); for ( inx=0; inx<segCnt; inx++ ) - if ( map[inx] == mpInx ) + if ( map[inx] == mpInx ) { map[inx] = map[segInx]; + } for ( inx=0; inx<mergePt_da.cnt; inx++ ) { - if ( inx == map[segInx] ) + if ( inx == map[segInx] ) { continue; + } mp = &mergePt(inx); - if ( mp->inx == mpInx ) + if ( mp->inx == mpInx ) { mp->inx = map[segInx]; + } } } static void GroupCopyTitle( - char * title ) + char * title ) { char *mP, *nP, *pP; int mL, nL, pL; @@ -153,23 +167,32 @@ static void GroupCopyTitle( groupPartno[pL] = '\0'; } else { if ( mL != (int)strlen( groupManuf ) || - strncmp( groupManuf, mP, mL ) != 0 ) + strncmp( groupManuf, mP, mL ) != 0 ) { groupManuf[0] = '\0'; + } if ( nL != (int)strlen( groupDesc ) || - strncmp( groupDesc, nP, nL ) != 0 ) + strncmp( groupDesc, nP, nL ) != 0 ) { groupDesc[0] = '\0'; + } if ( pL != (int)strlen( groupPartno ) || - strncmp( groupPartno, pP, pL ) != 0 ) + strncmp( groupPartno, pP, pL ) != 0 ) { groupPartno[0] = '\0'; + } } } +// TODO-BUMPER - handle paths which don't end on an EP +// Set GROUP_BUMPER_REFCOUT +// to 1 to convert Bumper tracks to Straight tracks with 2 EP +// to 2 to create 1 EP Turnout tracks +#define GROUP_BUMPER_REFCOUNT (1) EXPORT void UngroupCompound( - track_p trk ) + track_p trk ) { - struct extraData *xx = GetTrkExtraData(trk); - struct extraData *xx1; + struct extraDataCompound_t *xx = GET_EXTRA_DATA(trk, T_NOTRACK, + extraDataCompound_t); + struct extraDataCompound_t *xx1; trkSeg_p sp; track_p trk0, trk1; int segCnt, segInx, segInx1; @@ -187,7 +210,7 @@ EXPORT void UngroupCompound( typedef struct { track_p trk; EPINX_T ep[2]; - } segTrack_t; + } segTrack_t; #define segTrack(N) DYNARR_N( segTrack_t, segTrack_da, N ) static dynArr_t segTrack_da; segTrack_t * stp, * stp1; @@ -217,87 +240,114 @@ EXPORT void UngroupCompound( } #endif -LOG( log_group, 1, ( "Ungroup( T%d )\n", GetTrkIndex(trk) ) ); + LOG( log_group, 1, ( "Ungroup( T%d )\n", GetTrkIndex(trk) ) ); epCnt = GetTrkEndPtCnt(trk); - for ( segCnt=0; segCnt<xx->segCnt&&IsSegTrack(&xx->segs[segCnt]); segCnt++ ); - ASSERT( (epCnt==0) == (segCnt==0) ); + segCnt = xx->segCnt; + int trackCount = 0; + for ( sp=xx->segs; sp<&xx->segs[xx->segCnt]; sp++ ) { + if (IsSegTrack(sp)) { trackCount++; } + } + //CHECK( (epCnt==0) == (segCnt==0) ); + CHECK( (epCnt==0) == (trackCount==0) ); turnoutChanged = FALSE; if ( epCnt > 0 ) { turnoutChanged = TRUE; /* 1: collect EPs */ - DYNARR_SET( trkEndPt_t, tempEndPts_da, epCnt ); + TempEndPtsSet( epCnt ); DYNARR_SET( segTrack_t, segTrack_da, segCnt ); - memset( segTrack_da.ptr, 0, segCnt * sizeof segTrack(0) ); + memset( &segTrack(0), 0, segCnt * sizeof segTrack(0) ); for ( ep=0; ep<epCnt; ep++ ) { - epp = &tempEndPts(ep); - epp->pos = GetTrkEndPos( trk, ep ); - epp->angle = GetTrkEndAngle( trk, ep ); - Rotate( &epp->pos, xx->orig, -xx->angle ); - epp->pos.x -= xx->orig.x; - epp->pos.y -= xx->orig.y; - epp->track = GetTrkEndTrk( trk, ep ); - if ( epp->track ) - epp->index = GetEndPtConnectedToMe( epp->track, trk ); - else - epp->index = -1; -LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, epp->pos.y, epp->angle, epp->track?GetTrkIndex(epp->track):-1, epp->track?epp->index:-1 ) ); + epp = TempEndPt(ep); + coOrd pos = GetTrkEndPos( trk, ep ); + Rotate( &pos, xx->orig, -xx->angle ); + pos.x -= xx->orig.x; + pos.y -= xx->orig.y; + ANGLE_T angle = GetTrkEndAngle( trk, ep ); + track_p trk1 = GetTrkEndTrk( trk, ep ); + EPINX_T ep1; + ep1 = trk1 ? GetEndPtConnectedToMe( trk1, trk ) : -1 ; + SetEndPt( epp, pos, angle ); + SetEndPtTrack( epp, trk1 ); + // Remember what EP on trk1 was connecting to me + SetEndPtEndPt( epp, ep1 ); + LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, pos.x, pos.y, + angle, trk1?GetTrkIndex(trk1):-1, ep1 ) ); } /* 3: Count number of times each segment is referenced * If the refcount differs between adjacent segments * add segment with smaller count to mergePts * Treat EndPts as a phantom segment with inx above segCnt - * Path ends that don't map onto a real EndPt (bumpers) get a fake EP + * Path ends that don't map onto a real EndPt (bumpers) get a virtual EP */ DYNARR_SET( int, refCount_da, segCnt+epCnt ); - memset( refCount_da.ptr, 0, refCount_da.cnt * sizeof *(int*)0 ); - cp = (char *)xx->paths; + memset( &refCount(0), 0, refCount_da.cnt * sizeof *(int*)0 ); + cp = (char *)GetPaths( trk ); while ( cp[0] ) { cp += strlen(cp)+1; while ( cp[0] ) { + // Process 1st seg in sub-path GetSegInxEP( cp[0], &segInx, &segEP ); + // Find EP its connected to pos = GetSegEndPt( xx->segs+segInx, segEP, FALSE, NULL ); - segInx1 = FindEP( tempEndPts_da.cnt, &tempEndPts(0), pos ); + segInx1 = FindEP( TempEndPtsCount(), TempEndPt(0), pos ); if ( segInx1 >= 0 ) { + // Found existing EP, incr it's refCount segInx1 += segCnt; + if ( segInx1 >= refCount_da.cnt ) { + InputError( "Invalid segInx1 %d", TRUE, segInx1 ); + return; + } refCount(segInx1)++; } else { - DYNARR_APPEND( trkEndPt_t, tempEndPts_da, 10 ); + // No existing EP: must be a bumper, add virtual EP + epp = TempEndPtsAppend(); DYNARR_APPEND( int, refCount_da, 10 ); - epp = &tempEndPts(tempEndPts_da.cnt-1); - epp->pos = pos; - epp->angle = 0; + SetEndPt( epp, pos, 0 ); segInx1 = refCount_da.cnt-1; - refCount(segInx1) = 2; + refCount(segInx1) = GROUP_BUMPER_REFCOUNT; } segEP1 = 0; while ( cp[0] ) { + // Process remaining segs GetSegInxEP( cp[0], &segInx, &segEP ); + if ( segInx1 >= refCount_da.cnt ) { + InputError( "Invalid segInx1 %d", TRUE, segInx1 ); + return; + } + // Incr it's refCoount refCount(segInx)++; - if ( refCount(segInx) > refCount(segInx1) ) + // Is my refCount > then previous seg/EP? + if ( refCount(segInx) > refCount(segInx1) ) { AddMergePt( segInx, segEP ); - if ( refCount(segInx1) > refCount(segInx) ) + } + // Is previous seg/EP refCount > my refCount + if ( refCount(segInx1) > refCount(segInx) ) { AddMergePt( segInx1, segEP1 ); + } + // Advance to next seg segInx1 = segInx; segEP1 = 1-segEP; cp++; } + // Process last seg in sub-path GetSegInxEP( cp[-1], &segInx, &segEP ); + // Find EP its connected to pos = GetSegEndPt( xx->segs+segInx, 1-segEP, FALSE, NULL ); - segInx = FindEP( tempEndPts_da.cnt, &tempEndPts(0), pos ); + segInx = FindEP( TempEndPtsCount(), TempEndPt(0), pos ); if ( segInx >= 0 ) { + // Found EP, incr refCount segInx += segCnt; refCount(segInx)++; } else { - DYNARR_APPEND( trkEndPt_t, tempEndPts_da, 10 ); + // No existing EP: must be a bumper, add virtual EP + epp = TempEndPtsAppend(); DYNARR_APPEND( int, refCount_da, 10 ); - epp = &tempEndPts(tempEndPts_da.cnt-1); - epp->pos = pos; - epp->angle = 0; + SetEndPt( epp, pos, 0 ); segInx = refCount_da.cnt-1; - refCount(segInx) = 2; + refCount(segInx) = GROUP_BUMPER_REFCOUNT; } if ( refCount(segInx) > refCount(segInx1) ) { AddMergePt( segInx, 0 ); @@ -306,22 +356,21 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep } cp++; } - epCnt1 = tempEndPts_da.cnt; - + /* 4: For each path element, map segment to a mergePt if the adjacent segment * and EP is a mergePt * If segment is already mapped then merge mergePts */ DYNARR_SET( int, refCount_da, segCnt ); - memset( refCount_da.ptr, -1, segCnt * sizeof *(int*)0 ); - cp = (char *)xx->paths; + memset( &refCount(0), -1, segCnt * sizeof *(int*)0 ); + cp = (char *)GetPaths( trk ); while ( cp[0] ) { cp += strlen(cp)+1; while ( cp[0] ) { GetSegInxEP( cp[0], &segInx, &segEP ); pos = GetSegEndPt( xx->segs+segInx, segEP, FALSE, NULL ); /*REORIGIN1( pos, xx->angle, xx->orig );*/ - segInx1 = FindEP( tempEndPts_da.cnt, &tempEndPts(0), pos ); + segInx1 = FindEP( TempEndPtsCount(), TempEndPt(0), pos ); if ( segInx1 >= 0 ) { segInx1 += segCnt; } @@ -346,7 +395,7 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep GetSegInxEP( cp[-1], &segInx, &segEP ); pos = GetSegEndPt( xx->segs+segInx, 1-segEP, FALSE, NULL ); /*REORIGIN1( pos, xx->angle, xx->orig );*/ - segInx = FindEP( tempEndPts_da.cnt, &tempEndPts(0), pos ); + segInx = FindEP( TempEndPtsCount(), TempEndPt(0), pos ); if ( segInx >= 0 ) { segInx += segCnt; for ( inx=0; inx<mergePt_da.cnt; inx++ ) { @@ -365,8 +414,9 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep */ if ( mergePt_da.cnt > 0 ) { for ( segInx=0; segInx<segCnt; segInx++ ) - if ( refCount(segInx) != mergePt(0).inx ) + if ( refCount(segInx) != mergePt(0).inx ) { break; + } if ( segInx == segCnt ) { /* all segments on same turnout, nothing we can do here */ turnoutChanged = FALSE; @@ -383,11 +433,13 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep wDrawDelayUpdate( mainD.d, TRUE ); if ( turnoutChanged ) { for ( ep=0; ep<epCnt; ep++ ) { - epp = &tempEndPts(ep); - if ( epp->track ) { - DrawEndPt( &mainD, epp->track, epp->index, wDrawColorWhite ); + epp = TempEndPt(ep); + track_p trk1 = GetEndPtTrack(epp); + if ( trk1 ) { + EPINX_T ep1 = GetEndPtEndPt(epp); + DrawEndPt( &mainD, trk1, ep1, wDrawColorWhite ); DrawEndPt( &mainD, trk, ep, wDrawColorWhite ); - DisconnectTracks( trk, ep, epp->track, epp->index ); + DisconnectTracks( trk, ep, trk1, ep1 ); } } } @@ -418,11 +470,13 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep */ for ( inx=0; inx<mergePt_da.cnt; inx++ ) { mp = &mergePt(inx); - if ( mp->inx != inx ) + if ( mp->inx != inx ) { continue; + } DYNARR_RESET( trkSeg_t, tempSegs_da ); - DYNARR_SET( trkEndPt_t, tempEndPts_da, epCnt1 ); DYNARR_RESET( char, pathPtr_da ); + // Mark start of virtual EPs for this MergePt + epCnt1 = TempEndPtsCount(); for ( segInx=0; segInx<segCnt; segInx++ ) { if ( refCount(segInx) == inx ) { DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 ); @@ -437,22 +491,23 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep pathPtr(off+2) = '\0'; for ( ep=0; ep<2; ep++ ) { pos = GetSegEndPt( xx->segs+segInx, ep, FALSE, &angle ); - segEP = FindEP( epCnt1, &tempEndPts(0), pos ); + segEP = FindEP( epCnt1, TempEndPt(0), pos ); if ( segEP >= 0 && segEP >= epCnt && segEP < epCnt1 ) { /* was a bumper: no EP */ eps[ep] = -1; + // TODO-BUMPER To support Bumpers remove this continue continue; } REORIGIN1( pos, xx->angle, xx->orig ); angle = NormalizeAngle( xx->angle+angle ); - eps[ep] = FindEP( tempEndPts_da.cnt-epCnt1, &tempEndPts(epCnt1), pos ); + eps[ep] = -1; + if ( TempEndPtsCount()-epCnt1 > 0 ) { + eps[ep] = FindEP( TempEndPtsCount()-epCnt1, TempEndPt(epCnt1), pos ); + } if ( eps[ep] < 0 ) { - DYNARR_APPEND( trkEndPt_t, tempEndPts_da, 10 ); - eps[ep] = tempEndPts_da.cnt-1-epCnt1; - epp = &tempEndPts(tempEndPts_da.cnt-1); - memset( epp, 0, sizeof *epp ); - epp->pos = pos; - epp->angle = angle; + epp = TempEndPtsAppend(); + eps[ep] = TempEndPtsCount()-1-epCnt1; + SetEndPt( epp, pos, angle ); } } segTrack(segInx).ep[0] = eps[0]; @@ -461,10 +516,7 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep } DYNARR_SET( char, pathPtr_da, pathPtr_da.cnt+1 ); pathPtr(pathPtr_da.cnt-1) = '\0'; - if ( tempSegs_da.cnt == 0 ) { - AbortProg( "tempSegs_da.cnt == 0" ); - continue; - } + CHECK ( tempSegs_da.cnt != 0 ); GetSegBounds( zero, 0, tempSegs_da.cnt, &tempSegs(0), &orig, &size ); orig.x = -orig.x; orig.y = -orig.y; @@ -472,9 +524,13 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep Rotate( &orig, zero, xx->angle ); orig.x = xx->orig.x - orig.x; orig.y = xx->orig.y - orig.y; - trk1 = NewCompound( T_TURNOUT, 0, orig, xx->angle, xx->title, tempEndPts_da.cnt-epCnt1, &tempEndPts(epCnt1), NULL, pathPtr_da.cnt, &pathPtr(0), tempSegs_da.cnt, &tempSegs(0) ); - xx1 = GetTrkExtraData(trk1); + trk1 = NewCompound( T_TURNOUT, 0, orig, xx->angle, xx->title, + TempEndPtsCount()-epCnt1, TempEndPt(epCnt1), (PATHPTR_T)&pathPtr(0), + tempSegs_da.cnt, &tempSegs(0) ); + xx1 = GET_EXTRA_DATA(trk1, T_TURNOUT, extraDataCompound_t); xx1->ungrouped = TRUE; + xx1->pathOverRide = xx->pathOverRide; + xx1->pathNoCombine = xx->pathNoCombine; SetTrkVisible( trk1, TRUE ); SetTrkNoTies( trk1, FALSE ); @@ -490,7 +546,10 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep /* 8: for remaining segments, create simple tracks */ for ( segInx=0; segInx<segCnt; segInx++ ) { - if ( refCount(segInx) >= 0 ) continue; + if ( refCount(segInx) >= 0 ) { continue; } + if ( ! IsSegTrack( xx->segs+segInx ) ) { + continue; + } SegProc( SEGPROC_NEWTRACK, xx->segs+segInx, &segProcData ); SetTrkScale( segProcData.newTrack.trk, GetTrkScale(trk) ); SetTrkBits( segProcData.newTrack.trk, TB_SELECTED ); @@ -503,20 +562,23 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep /* 9: reconnect tracks */ - cp = (char *)xx->paths; + cp = (char *)GetPaths( trk ); while ( cp[0] ) { cp += strlen(cp)+1; while ( cp[0] ) { /* joint EP to this segment */ GetSegInxEP( cp[0], &segInx, &segEP ); stp = &segTrack(segInx); - ep = FindEP( epCnt, &tempEndPts(0), GetSegEndPt( xx->segs+segInx, segEP, FALSE, NULL ) ); + ep = FindEP( epCnt, TempEndPt(0), GetSegEndPt( xx->segs+segInx, segEP, FALSE, + NULL ) ); if ( ep >= 0 ) { - epp = &tempEndPts(ep); - if ( epp->track ) { - ConnectTracks( stp->trk, stp->ep[segEP], epp->track, epp->index ); - DrawEndPt( &mainD, epp->track, epp->index, GetTrkColor(epp->track,&mainD) ); - epp->track = NULL; + epp = TempEndPt(ep); + track_p trk1 = GetEndPtTrack(epp); + if ( trk1 ) { + EPINX_T ep1 = GetEndPtEndPt(epp); + ConnectTracks( stp->trk, stp->ep[segEP], trk1, ep1 ); + DrawEndPt( &mainD, trk1, ep1, GetTrkColor(trk1, &mainD) ); + SetEndPtTrack( epp, NULL ); // Finished with this EP } } stp1 = stp; @@ -525,28 +587,35 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep while ( cp[0] ) { GetSegInxEP( cp[0], &segInx, &segEP ); stp = &segTrack(segInx); + // Check EPs are not virtual (Bumpers) + // TODO-BUMPER May not be necessary + CHECK( stp->ep[segEP] >= 0 ); + CHECK( stp1->ep[segEP1] >= 0 ); trk0 = GetTrkEndTrk( stp->trk, stp->ep[segEP] ); trk1 = GetTrkEndTrk( stp1->trk, stp1->ep[segEP1] ); if ( trk0 == NULL ) { - if ( trk1 != NULL ) - AbortProg( "ungroup: seg half connected" ); + CHECK ( trk1 == NULL ); ConnectTracks( stp->trk, stp->ep[segEP], stp1->trk, stp1->ep[segEP1] ); } else { - if ( trk1 != stp->trk || stp1->trk != trk0 ) - AbortProg( "ungroup: last seg not connected to curr" ); + CHECK( trk1 == stp->trk ); + CHECK( stp1->trk == trk0 ); + // ungroup: last seg not connected to curr } stp1 = stp; segEP1 = 1-segEP; cp++; } /* joint EP to last segment */ - ep = FindEP( epCnt, &tempEndPts(0), GetSegEndPt( xx->segs+segInx, segEP1, FALSE, NULL ) ); + ep = FindEP( epCnt, TempEndPt(0), GetSegEndPt( xx->segs+segInx, segEP1, FALSE, + NULL ) ); if ( ep > 0 ) { - epp = &tempEndPts(ep); - if ( epp->track ) { - ConnectTracks( stp1->trk, stp1->ep[segEP1], epp->track, epp->index ); - DrawEndPt( &mainD, epp->track, epp->index, wDrawColorWhite ); - epp->track = NULL; + epp = TempEndPt(ep); + track_p trk1 = GetEndPtTrack( epp ); + if ( trk1 ) { + EPINX_T ep1 = GetEndPtEndPt( epp ); + ConnectTracks( stp1->trk, stp1->ep[segEP1], trk1, ep1 ); + DrawEndPt( &mainD, trk1, ep1, wDrawColorWhite ); + SetEndPtTrack( epp, NULL ); // Finished with this EP } } cp++; @@ -566,7 +635,9 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep mp->trk = NULL; } } else { - DrawNewTrack( segTrack(segInx).trk ); + if ( segTrack(segInx).trk ) { + DrawNewTrack( segTrack(segInx).trk ); + } } } wDrawDelayUpdate( mainD.d, FALSE ); @@ -575,15 +646,16 @@ LOG( log_group, 1, ( " EP%d = [%0.3f %0.3f] A%0.3f T%d.%d\n", ep, epp->pos.x, ep -EXPORT void DoUngroup( void ) +EXPORT void DoUngroup( void * unused ) { track_p trk = NULL; int ungroupCnt; int oldTrackCount; TRKINX_T lastTrackIndex; - if ( log_group < 0 ) + if ( log_group < 0 ) { log_group = LogFindIndex( "group" ); + } groupManuf[0] = 0; groupDesc[0] = 0; groupPartno[0] = 0; @@ -596,62 +668,71 @@ EXPORT void DoUngroup( void ) if ( GetTrkSelected( trk ) && GetTrkIndex(trk) <= lastTrackIndex ) { oldTrackCount = trackCount; UngroupTrack( trk ); - if ( oldTrackCount != trackCount ) + if ( oldTrackCount != trackCount ) { ungroupCnt++; + } } } - if ( ungroupCnt ) + if ( ungroupCnt ) { InfoMessage( _("%d objects ungrouped"), ungroupCnt ); - else + } else { InfoMessage( _("No objects ungrouped") ); + } } static drawCmd_t groupD = { - NULL, &tempSegDrawFuncs, DC_SEGTRACK, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix }; + NULL, &tempSegDrawFuncs, DC_SEGTRACK, 1, 0.0, {0.0, 0.0}, {0.0, 0.0}, Pix2CoOrd, CoOrd2Pix +}; static long groupSegCnt; static long groupReplace; +static long groupNoCombine; static double groupOriginX; static double groupOriginY; char * groupReplaceLabels[] = { N_("Replace with new group?"), NULL }; +char * groupNoCombineLabels[] = { N_("Turntable/TransferTable/DblSlipSwith?"), NULL }; static wWin_p groupW; static paramIntegerRange_t r0_999999 = { 0, 999999 }; static paramFloatRange_t r_1000_1000 = { -1000.0, 1000.0, 80 }; static paramData_t groupPLs[] = { -/*0*/ { PD_STRING, groupManuf, "manuf", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)350, N_("Manufacturer"), 0, 0, sizeof(groupManuf)}, -/*1*/ { PD_STRING, groupDesc, "desc", PDO_NOPREF | PDO_STRINGLIMITLENGTH, (void*)230, N_("Description"), 0, 0, sizeof(groupDesc)}, -/*2*/ { PD_STRING, groupPartno, "partno", PDO_NOPREF|PDO_DLGHORZ|PDO_DLGIGNORELABELWIDTH|PDO_STRINGLIMITLENGTH, (void*)100, N_("#"), 0, 0, sizeof(groupPartno)}, -/*3*/ { PD_LONG, &groupSegCnt, "segcnt", PDO_NOPREF, &r0_999999, N_("# Segments"), BO_READONLY }, + /*0*/ { PD_STRING, groupManuf, "manuf", PDO_NOPREF | PDO_NOTBLANK, I2VP(350), N_("Manufacturer"), 0, 0, sizeof(groupManuf)}, + /*1*/ { PD_STRING, groupDesc, "desc", PDO_NOPREF | PDO_NOTBLANK, I2VP(230), N_("Description"), 0, 0, sizeof(groupDesc)}, + /*2*/ { PD_STRING, groupPartno, "partno", PDO_NOPREF|PDO_DLGHORZ|PDO_DLGIGNORELABELWIDTH|PDO_NOTBLANK, I2VP(100), N_("#"), 0, 0, sizeof(groupPartno)}, + /*3*/ { PD_LONG, &groupSegCnt, "segcnt", PDO_NOPREF, &r0_999999, N_("# Segments"), BO_READONLY }, #define I_GROUP_ORIGIN_OFFSET 4 /* Need to change if add above */ -/*4*/ { PD_FLOAT, &groupOriginX, "orig", PDO_DIM, &r_1000_1000, N_("Offset X,Y:")}, -/*5*/ { PD_FLOAT, &groupOriginY, "origy",PDO_DIM | PDO_DLGHORZ, &r_1000_1000, ""}, -/*6*/ { PD_TOGGLE, &groupReplace, "replace", 0, groupReplaceLabels, "", BC_HORZ|BC_NOBORDER } }; -static paramGroup_t groupPG = { "group", 0, groupPLs, sizeof groupPLs/sizeof groupPLs[0] }; + /*4*/ { PD_FLOAT, &groupOriginX, "orig", PDO_DIM, &r_1000_1000, N_("Offset X,Y:")}, + /*5*/ { PD_FLOAT, &groupOriginY, "origy",PDO_DIM | PDO_DLGHORZ, &r_1000_1000, ""}, + /*6*/ { PD_TOGGLE, &groupNoCombine, "noCombine", 0, groupNoCombineLabels, "", BC_HORZ|BC_NOBORDER }, + /*7*/ { PD_TOGGLE, &groupReplace, "replace", 0, groupReplaceLabels, "", BC_HORZ|BC_NOBORDER } +}; +static paramGroup_t groupPG = { "group", 0, groupPLs, COUNT( groupPLs ) }; typedef struct { - track_p trk; - int segStart; - int segEnd; - } groupTrk_t, * groupTrk_p; + track_p trk; + int segStart; + int segEnd; + int totalSegStart; //Where we are overall + int totalSegEnd; +} groupTrk_t, * groupTrk_p; static dynArr_t groupTrk_da; #define groupTrk(N) DYNARR_N( groupTrk_t, groupTrk_da, N ) typedef struct { - int groupInx; - EPINX_T ep1, ep2; - PATHPTR_T path; - BOOL_T flip; - } pathElem_t, *pathElem_p; + int groupInx; + EPINX_T ep1, ep2; + PATHPTR_T path; + BOOL_T flip; +} pathElem_t, *pathElem_p; typedef struct { - int pathElemStart; - int pathElemEnd; - EPINX_T ep1, ep2; - int conflicts; - BOOL_T inGroup; - BOOL_T done; - } path_t, *path_p; + int pathElemStart; + int pathElemEnd; + EPINX_T ep1, ep2; + int conflicts; + BOOL_T inGroup; + BOOL_T done; +} path_t, *path_p; static dynArr_t path_da; #define path(N) DYNARR_N( path_t, path_da, N ) static dynArr_t pathElem_da; @@ -662,35 +743,37 @@ static int pathElemStart; /* * Find sub-path that connects the 2 EPs for the given track * - * \param trk IN Track + * \param trk IN Track * \param ep1, ep2 IN EndPt index * \param BOOL_T *flip OUT whether path is flipped * \return sub-path that connects the 2 EPs */ static char * FindPathBtwEP( - track_p trk, - EPINX_T ep1, - EPINX_T ep2, - BOOL_T * flip ) + track_p trk, + EPINX_T ep1, + EPINX_T ep2, + BOOL_T * flip ) { - struct extraData * xx = GetTrkExtraData( trk ); char * cp; coOrd trkPos[2]; - - LOG( log_group, 3, (" FindPathBtwEP: T%d .%d .%d = ", trk?GetTrkIndex(trk):-1, ep1, ep2 )); + + LOG( log_group, 3, (" FindPathBtwEP: T%d .%d .%d = ", trk?GetTrkIndex(trk):-1, + ep1, ep2 )); if ( GetTrkType(trk) != T_TURNOUT ) { - if ( ep1+ep2 != 1 ) - AbortProg( "findPathBtwEP" ); + CHECK( ep1+ep2 == 1 ); *flip = ( ep1 == 1 ); - if (GetTrkType(trk) == T_CORNU ) { // Cornu doesn't have a path but lots of segs! + if (GetTrkType(trk) == + T_CORNU ) { // Cornu doesn't have a path but lots of segs! cp = CreateSegPathList(trk); // Make path -LOG( log_group, 2, ( " Group: Cornu path:%s \n", cp ) ) - } else cp = "\1\0\0"; //One segment (but could be a Bezier) + LOG( log_group, 2, ( " Group: Cornu path:%s \n", cp ) ) + } else { cp = "\1\0\0"; } //One segment (but could be a Bezier) LOG( log_group, 3, (" Flip:%s Path= Seg=%d-\n", *flip?"T":"F", *cp ) ); return cp; } - cp = (char *)xx->paths; + struct extraDataCompound_t * xx = GET_EXTRA_DATA( trk, T_TURNOUT, + extraDataCompound_t ); + cp = (char *)GetPaths( trk ); trkPos[0] = GetTrkEndPos(trk,ep1); Rotate( &trkPos[0], xx->orig, -xx->angle ); trkPos[0].x -= xx->orig.x; @@ -718,7 +801,7 @@ LOG( log_group, 2, ( " Group: Cornu path:%s \n", cp ) ) cp += strlen(cp); GetSegInxEP( cp[-1], &segInx, &segEP ); segPos[1] = GetSegEndPt( &xx->segs[segInx], 1-segEP, FALSE, NULL ); - + // Find the closest seg end for ( int inx = 0; inx<2; inx++ ) { // Check 1st end @@ -728,7 +811,9 @@ LOG( log_group, 2, ( " Group: Cornu path:%s \n", cp ) ) DIST_T dist2 = FindDistance( trkPos[1], segPos[1-inx] ); if ( dist2 > dist1 ) // 2nd end is further away + { dist1 = dist2; + } if ( dist1 < connectDistance && dist1 < dist ) { // both ends are closest dist = dist1; @@ -742,18 +827,19 @@ LOG( log_group, 2, ( " Group: Cornu path:%s \n", cp ) ) } cp++; } -LOG( log_group, 3, (" %s: %d..%d Flip:%s\n", pName, path?path[0]:-1, path?path[strlen(path)-1]:-1, *flip?"T":"F" ) ); + LOG( log_group, 3, (" %s: %d..%d Flip:%s\n", pName, path?path[0]:-1, + path?path[strlen(path)-1]:-1, *flip?"T":"F" ) ); return path; } static int GroupShortestPathFunc( - SPTF_CMD cmd, - track_p trk, - EPINX_T ep1, - EPINX_T ep2, - DIST_T dist, - void * data ) + SPTF_CMD cmd, + track_p trk, + EPINX_T ep1, + EPINX_T ep2, + DIST_T dist, + void * data ) { track_p trk1; path_t *pp; @@ -766,13 +852,20 @@ static int GroupShortestPathFunc( switch ( cmd ) { case SPTC_MATCH: - if ( !GetTrkSelected(trk) ) + if ( !GetTrkSelected(trk) ) { return 0; + } + // TODO-BUMPER may not be necessary + if ( GetTrkEndPtCnt(trk) < 2 && ep1 >= 1 ) { + return 1; + } trk1 = GetTrkEndTrk(trk,ep1); - if ( trk1 == NULL ) + if ( trk1 == NULL ) { return 1; - if ( !GetTrkSelected(trk1) ) + } + if ( !GetTrkSelected(trk1) ) { return 1; + } return 0; case SPTC_MATCHANY: @@ -781,7 +874,7 @@ static int GroupShortestPathFunc( case SPTC_ADD_TRK: LOG( log_group, 4, ( " Add T%d[%d]\n", GetTrkIndex(trk), ep2 ) ) DYNARR_APPEND( pathElem_t, pathElem_da, 10 ); - ppp = &pathElem(pathElem_da.cnt-1); + ppp = &pathElem(pathElem_da.cnt-1); for ( inx=0; inx<groupTrk_da.cnt; inx++ ) { if ( groupTrk(inx).trk == trk ) { ppp->groupInx = inx; @@ -791,7 +884,9 @@ static int GroupShortestPathFunc( return 0; } } - AbortProg( "GroupShortestPathFunc(SPTC_ADD_TRK, T%d) - track not in group", GetTrkIndex(trk) ); + CHECKMSG( FALSE, + ( "GroupShortestPathFunc(SPTC_ADD_TRK, T%d) - track not in group", + GetTrkIndex(trk) ) ); case SPTC_TERMINATE: ppp = &pathElem(pathElemStart); @@ -803,31 +898,35 @@ static int GroupShortestPathFunc( pos2 = GetTrkEndPos( trk, ppp->ep1 ); ang2 = GetTrkEndAngle( trk, ppp->ep1 ); ep1 = ep2 = -1; - for ( ep=0; ep<tempEndPts_da.cnt; ep++ ) { + for ( ep=0; ep<TempEndPtsCount(); ep++ ) { if ( ep1 < 0 ) { - dist = FindDistance( pos1, tempEndPts(ep).pos ); - angle = NormalizeAngle( ang1 - tempEndPts(ep).angle + connectAngle/2.0 ); - if ( dist < connectDistance && angle < connectAngle ) + dist = FindDistance( pos1, GetEndPtPos(TempEndPt(ep))); + angle = NormalizeAngle( ang1 - GetEndPtAngle(TempEndPt(ep)) + + connectAngle/2.0 ); + if ( dist < connectDistance && angle < connectAngle ) { ep1 = ep; + } } if ( ep2 < 0 ) { - dist = FindDistance( pos2, tempEndPts(ep).pos ); - angle = NormalizeAngle( ang2 - tempEndPts(ep).angle + connectAngle/2.0 ); - if ( dist < connectDistance && angle < connectAngle ) + dist = FindDistance( pos2, GetEndPtPos(TempEndPt(ep)) ); + angle = NormalizeAngle( ang2 - GetEndPtAngle(TempEndPt(ep)) + + connectAngle/2.0 ); + if ( dist < connectDistance && angle < connectAngle ) { ep2 = ep; + } } } if ( ep1<0 || ep2<0 ) { -LOG( log_group, 4, ( " Remove: ep not found\n" ) ) - pathElem_da.cnt = pathElemStart; + LOG( log_group, 4, ( " Remove: ep not found\n" ) ) + DYNARR_SET( pathElem_t, pathElem_da, pathElemStart ); return 0; } for ( inx=0; inx<path_da.cnt; inx++ ) { pp = &path(inx); if ( ( ep1 < 0 || ( pp->ep1 == ep1 || pp->ep2 == ep1 ) ) && - ( ep2 < 0 || ( pp->ep1 == ep2 || pp->ep2 == ep2 ) ) ) { -LOG( log_group, 4, ( " Remove: duplicate path P%d\n", inx ) ) - pathElem_da.cnt = pathElemStart; + ( ep2 < 0 || ( pp->ep1 == ep2 || pp->ep2 == ep2 ) ) ) { + LOG( log_group, 4, ( " Remove: duplicate path P%d\n", inx ) ) + DYNARR_SET( pathElem_t, pathElem_da, pathElemStart ); return 0; } } @@ -839,18 +938,21 @@ LOG( log_group, 4, ( " Remove: duplicate path P%d\n", inx ) ) pp->ep1 = ep1; pp->ep2 = ep2; pathElemStart = pathElem_da.cnt; -LOG( log_group, 4, ( " Keep\n" ) ) + LOG( log_group, 4, ( " Keep\n" ) ) return 0; case SPTC_IGNNXTTRK: - if ( !GetTrkSelected(trk) ) + if ( !GetTrkSelected(trk) ) { return 1; - if ( ep1 == ep2 ) + } + if ( ep1 == ep2 ) { return 1; - if ( GetTrkEndPtCnt(trk) == 2 ) + } + if ( GetTrkEndPtCnt(trk) == 2 ) { return 0; - if ( GetTrkType(trk) != T_TURNOUT ) - AbortProg( "GroupShortestPathFunc(IGNNXTTRK,T%d:%d,%d)", GetTrkIndex(trk), ep1, ep2 ); + } + CHECKMSG( GetTrkType(trk) == T_TURNOUT, + ( "GroupShortestPathFunc(IGNNXTTRK,T%d:%d,%d)", GetTrkIndex(trk), ep1, ep2 ) ); return FindPathBtwEP( trk, ep2, ep1, &flip ) == NULL; case SPTC_VALID: @@ -862,8 +964,8 @@ LOG( log_group, 4, ( " Keep\n" ) ) static int CmpGroupOrder( - const void * ptr1, - const void * ptr2 ) + const void * ptr1, + const void * ptr2 ) { int inx1 = *(int*)ptr1; int inx2 = *(int*)ptr2; @@ -873,68 +975,76 @@ static int CmpGroupOrder( static coOrd endPtOrig; static ANGLE_T endPtAngle; static int CmpEndPtAngle( - const void * ptr1, - const void * ptr2 ) + const void * ptr1, + const void * ptr2 ) { ANGLE_T angle; trkEndPt_p epp1 = (trkEndPt_p)ptr1; trkEndPt_p epp2 = (trkEndPt_p)ptr2; - - angle = NormalizeAngle(FindAngle(endPtOrig,epp1->pos)-endPtAngle) - NormalizeAngle(FindAngle(endPtOrig,epp2->pos)-endPtAngle); + + angle = NormalizeAngle(FindAngle(endPtOrig, + GetEndPtPos(epp1))-endPtAngle) - NormalizeAngle(FindAngle(endPtOrig, + GetEndPtPos(epp2))-endPtAngle); return (int)angle; } static int ConflictPaths( - path_p path0, - path_p path1 ) + path_p path0, + path_p path1 ) { + if ( groupNoCombine != 0 ) { + // No grouping + return TRUE; + } /* do these paths share an EP? */ - if ( path0->ep1 == path1->ep1 ) return TRUE; - if ( path0->ep1 == path1->ep2 ) return TRUE; - if ( path0->ep2 == path1->ep1 ) return TRUE; - if ( path0->ep2 == path1->ep2 ) return TRUE; + if ( path0->ep1 == path1->ep1 ) { return TRUE; } + if ( path0->ep1 == path1->ep2 ) { return TRUE; } + if ( path0->ep2 == path1->ep1 ) { return TRUE; } + if ( path0->ep2 == path1->ep2 ) { return TRUE; } return FALSE; } static BOOL_T CheckPathEndPt( - track_p trk, - char cc, - EPINX_T ep ) + track_p trk, + char cc, + EPINX_T ep ) { - struct extraData *xx = GetTrkExtraData(trk); + struct extraDataCompound_t *xx = GET_EXTRA_DATA(trk, T_TURNOUT, + extraDataCompound_t); wIndex_t segInx; EPINX_T segEP, epCnt; DIST_T d; coOrd pos; GetSegInxEP( cc, &segInx, &segEP ); - if ( ep ) segEP = 1-segEP; + if ( ep ) { segEP = 1-segEP; } pos = GetSegEndPt( &xx->segs[segInx], segEP, FALSE, NULL ); REORIGIN1( pos, xx->angle, xx->orig ); epCnt = GetTrkEndPtCnt(trk); for ( ep=0; ep<epCnt; ep++ ) { d = FindDistance( pos, GetTrkEndPos( trk, ep ) ); - if ( d < connectDistance ) + if ( d < connectDistance ) { return TRUE; + } } return FALSE; } static BOOL_T CheckForBumper( - track_p trk ) + track_p trk ) { - struct extraData *xx = GetTrkExtraData(trk); char * cp; - cp = (char *)xx->paths; + cp = (char *)GetPaths( trk ); while ( cp[0] ) { cp += strlen(cp)+1; while ( cp[0] ) { - if ( !CheckPathEndPt( trk, cp[0], 0 ) ) return FALSE; - while ( cp[0] ) + if ( !CheckPathEndPt( trk, cp[0], 0 ) ) { return FALSE; } + while ( cp[0] ) { cp++; - if ( !CheckPathEndPt( trk, cp[-1], 1 ) ) return FALSE; + } + if ( !CheckPathEndPt( trk, cp[-1], 1 ) ) { return FALSE; } cp++; } cp++; @@ -942,41 +1052,15 @@ static BOOL_T CheckForBumper( return TRUE; } -typedef struct { - int inx; - wBool_t track; -} segInMap_t; -static dynArr_t segInMap_da; -#define segInMap(N) DYNARR_N( segInMap_t, segInMap_da, N) - -void AddToSegMap(int inx,wBool_t track) { - DYNARR_APPEND(segInMap_t,segInMap_da,10); - DYNARR_LAST(segInMap_t,segInMap_da).inx = inx; - DYNARR_LAST(segInMap_t,segInMap_da).track = track; -} - -void AddSegsToSegMap(int start, int end, wBool_t track) { - for (int i = start; i<= end; i++) { - AddToSegMap(i,track); - } -} - static dynArr_t trackSegs_da; #define trackSegs(N) DYNARR_N( trkSeg_t, trackSegs_da, N ) -trkSeg_p GetSegFromSegMap(int index) { - if (DYNARR_N( segInMap_t, segInMap_da, index).track) { - return &DYNARR_N(trkSeg_t,trackSegs_da,DYNARR_N( segInMap_t, segInMap_da, index).inx); - } else - return &DYNARR_N(trkSeg_t,tempSegs_da,DYNARR_N( segInMap_t, segInMap_da, index).inx); -} - static dynArr_t outputSegs_da; #define outputSegs(N) DYNARR_N( trkSeg_t, outputSegs_da, N) static void LogSeg( - trkSeg_p segP ) + trkSeg_p segP ) { if ( segP == NULL ) { LogPrintf( "<NULL>\n" ); @@ -990,24 +1074,26 @@ static void LogSeg( case SEG_BENCH: case SEG_TBLEDGE: LogPrintf( "[ %0.3f %0.3f ] [ %0.3f %0.3f ]\n", - segP->u.l.pos[0].x, segP->u.l.pos[0].y, - segP->u.l.pos[1].x, segP->u.l.pos[1].y ); + segP->u.l.pos[0].x, segP->u.l.pos[0].y, + segP->u.l.pos[1].x, segP->u.l.pos[1].y ); break; case SEG_CRVLIN: case SEG_CRVTRK: LogPrintf( "R:%0.3f [ %0.3f %0.3f } A0:%0.3f A1:%0.3f\n", - segP->u.c.radius, - segP->u.c.center.x, segP->u.c.center.y, - segP->u.c.a0, segP->u.c.a1 ); + segP->u.c.radius, + segP->u.c.center.x, segP->u.c.center.y, + segP->u.c.a0, segP->u.c.a1 ); break; default: LogPrintf( "%c:\n", segP->type ); } } + + /* * GroupOk: create a TURNOUT or STRUCTURE from the selected objects * 1 - Add selected tracks to groupTrk[] - * - Add each group trk's segments to trackSeg[] or tempSegs[] + * - Add each group trk's segments to trackSeg[] * - Add all segs to segInMap[] * - if no track segments goto step 9 * 2 - Collect boundary endPts and sort them in tempEndPts[] @@ -1017,16 +1103,16 @@ static void LogSeg( * 4 - Flip tracks so sub-path elements match up * 5 - Create conflict map * 6 - Flip paths to minimize the number of flipped segments - * 7 - Build the path ('P') string + * 7 - Build the path ('P') string (new-P) * 8 - Build segment list, adjust endPts in tempEndPts[] - * 9 - create new TURNOUT/STRUCTURE definition + * 9 - create new TURNOUT/STRUCTURE definition * 10 - write defn to xtrkcad.cus * 11 - optionally replace grouped tracks with new defn */ -static void GroupOk( void * junk ) +static void GroupOk( void * unused ) { - struct extraData *xx = NULL; + struct extraDataCompound_t *xx = NULL; turnoutInfo_t * to; int inx; EPINX_T ep, epCnt, epN; @@ -1055,21 +1141,16 @@ static void GroupOk( void * junk ) int groupCnt; int pinx, pinx2, ginx, ginx2, gpinx2; trkEndPt_p endPtP; - PATHPTR_T path; - int pathLen; signed char pathChar; - char *oldLocale = NULL; DYNARR_RESET( trkSeg_t, trackSegs_da ); DYNARR_RESET( trkSeg_t, tempSegs_da ); DYNARR_RESET( groupTrk_t, groupTrk_da ); DYNARR_RESET( path_t, path_da ); DYNARR_RESET( pathElem_t, pathElem_da ); - DYNARR_RESET( trkEndPt_t, tempEndPts_da ); + TempEndPtsReset(); DYNARR_RESET( char, pathPtr_da ); - DYNARR_RESET( segInMap_t, segInMap_da); - ParamUpdate( &groupPG ); if ( groupManuf[0]==0 || groupDesc[0]==0 || groupPartno[0]==0 ) { NoticeMessage2( 0, MSG_GROUP_NONBLANK, _("Ok"), NULL ); @@ -1078,8 +1159,9 @@ static void GroupOk( void * junk ) sprintf( message, "%s\t%s\t%s", groupManuf, groupDesc, groupPartno ); if ( strcmp( message, groupTitle ) != 0 ) { if ( FindCompound( FIND_TURNOUT|FIND_STRUCT, curScaleName, message ) ) - if ( !NoticeMessage2( 1, MSG_TODSGN_REPLACE, _("Yes"), _("No") ) ) + if ( !NoticeMessage2( 1, MSG_TODSGN_REPLACE, _("Yes"), _("No") ) ) { return; + } strcpy( groupTitle, message ); } @@ -1088,106 +1170,107 @@ static void GroupOk( void * junk ) * 1: Collect tracks */ trk = NULL; - int InInx = -1; +// int InInx = -1; + BOOL_T hasTracks = FALSE; + wIndex_t nTrkSeg = 0; + wIndex_t nSeg = 0; + wIndex_t iLastTrkSeg = 0; while ( TrackIterate( &trk ) ) { if ( GetTrkSelected( trk ) ) { - if ( IsTrack(trk) ) { - DYNARR_APPEND( groupTrk_t, groupTrk_da, 10 ); - groupP = &groupTrk(groupTrk_da.cnt-1); - groupP->trk = trk; - groupP->segStart = trackSegs_da.cnt; - if ( GetTrkType(trk) == T_TURNOUT ) { - xx = GetTrkExtraData(trk); - for ( pinx=0; pinx<xx->segCnt; pinx++ ) { - segPtr = &xx->segs[pinx]; - if ( IsSegTrack(segPtr) ) { - DYNARR_APPEND( trkSeg_t, trackSegs_da, 10 ); - trackSegs(trackSegs_da.cnt-1) = *segPtr; - - AddToSegMap(trackSegs_da.cnt-1,TRUE); /* Single Track Seg - Note no Cornu*/ - - RotateSegs( 1, &trackSegs(trackSegs_da.cnt-1), zero, xx->angle ); - MoveSegs( 1, &trackSegs(trackSegs_da.cnt-1), xx->orig ); - - } else { - int start = tempSegs_da.cnt; - DrawSegs( &groupD, xx->orig, xx->angle, segPtr, 1, trackGauge, wDrawColorBlack ); - - AddSegsToSegMap(start,tempSegs_da.cnt-1,FALSE); /* Multiple Non-Track Segs */ - } - } - } else if (GetTrkType(trk) == T_BEZIER || GetTrkType(trk) == T_BZRLIN ) { - DYNARR_APPEND(trkSeg_t, trackSegs_da, 10); - segPtr = &trackSegs(trackSegs_da.cnt-1); - - GetBezierSegmentFromTrack(trk,segPtr); + DYNARR_APPEND( groupTrk_t, groupTrk_da, 10 ); + groupP = &groupTrk(groupTrk_da.cnt-1); + groupP->trk = trk; + groupP->segStart = trackSegs_da.cnt; + groupP->totalSegStart = tempSegs_da.cnt+trackSegs_da.cnt; + if (IsTrack(trk)) { hasTracks = TRUE; } + if ( GetTrkType(trk) == T_TURNOUT || GetTrkType(trk) == T_STRUCTURE) { + xx = GET_EXTRA_DATA(trk, T_NOTRACK, extraDataCompound_t); + for ( pinx=0; pinx<xx->segCnt; pinx++ ) { + segPtr = &xx->segs[pinx]; + if ( IsSegTrack(segPtr) ) { + DYNARR_APPEND( trkSeg_t, trackSegs_da, 10 ); + trackSegs(trackSegs_da.cnt-1) = *segPtr; + hasTracks = TRUE; + RotateSegs( 1, &trackSegs(trackSegs_da.cnt-1), zero, xx->angle ); + MoveSegs( 1, &trackSegs(trackSegs_da.cnt-1), xx->orig ); + + } else { + DYNARR_APPEND( trkSeg_t, trackSegs_da, 10 ); + trackSegs(trackSegs_da.cnt-1) = *segPtr; + + RotateSegs( 1, &trackSegs(trackSegs_da.cnt-1), zero, xx->angle ); + MoveSegs( 1, &trackSegs(trackSegs_da.cnt-1), xx->orig ); - AddToSegMap(trackSegs_da.cnt-1,TRUE); // Add Single Bezier Track + } + } + } else if (GetTrkType(trk) == T_BEZIER || GetTrkType(trk) == T_BZRLIN ) { + DYNARR_APPEND(trkSeg_t, trackSegs_da, 10); + segPtr = &trackSegs(trackSegs_da.cnt-1); - } else if (GetTrkType(trk) == T_CORNU) { + GetBezierSegmentFromTrack(trk,segPtr); - int start = trackSegs_da.cnt; + } else if (GetTrkType(trk) == T_CORNU) { - GetBezierSegmentsFromCornu(trk,&trackSegs_da,TRUE); //Only give back Bezier - cant be undone +// int start = trackSegs_da.cnt; - AddSegsToSegMap(start,trackSegs_da.cnt-1,TRUE); /* Add Multiple Track Segs */ + GetBezierSegmentsFromCornu(trk,&trackSegs_da, + TRUE); //Only give back Bezier - cant be undone - } else { - segCnt = tempSegs_da.cnt; - DrawTrack( trk, &groupD, wDrawColorBlack ); + } else { + if (IsTrack(trk)) { hasTracks=TRUE; } + segCnt = tempSegs_da.cnt; + DrawTrack( trk, &groupD, wDrawColorBlack ); + for ( ; segCnt < tempSegs_da.cnt; segCnt++ ) { + // Copy drawn segments DYNARR_APPEND( trkSeg_t, trackSegs_da, 10 ); segPtr = &trackSegs(trackSegs_da.cnt-1); *segPtr = tempSegs( segCnt ); - - AddToSegMap(trackSegs_da.cnt-1,TRUE); // Add One Track - - if ( tempSegs_da.cnt != segCnt+1 || - !IsSegTrack(segPtr) ) { - NoticeMessage2( 0, MSG_CANNOT_GROUP_TRACK, _("Ok"), NULL ); - wHide( groupW ); - return; - } - - tempSegs_da.cnt = segCnt; } - groupP->segEnd = trackSegs_da.cnt-1; - } else { - int start = tempSegs_da.cnt; - - DrawTrack( trk, &groupD, wDrawColorBlack ); + } - AddSegsToSegMap(start,tempSegs_da.cnt-1,FALSE); /* Multiple Non-Track Segs */ + // Count number of track segs and if any appear after seg 127 + for ( ; nSeg < trackSegs_da.cnt; nSeg++ ) { + if ( IsSegTrack( &trackSegs( nSeg ) ) ) { + nTrkSeg++; + iLastTrkSeg = nSeg; + } } + groupP->segEnd = trackSegs_da.cnt-1; } } -if ( log_group >= 1 && logTable(log_group).level >= 4 ) { - LogPrintf( "Track Segs:\n"); - for ( int inx = 0; inx < trackSegs_da.cnt; inx++ ) { - LogPrintf( " %d: ", inx+1 ); - LogSeg( &trackSegs(inx) ); + if ( log_group >= 1 && logTable(log_group).level >= 4 ) { + LogPrintf( "Track Segs:\n"); + for ( int inx = 0; inx < trackSegs_da.cnt; inx++ ) { + if (IsSegTrack(&trackSegs(inx))) { + LogPrintf( " %d: ", inx+1 ); + LogSeg( &trackSegs(inx) ); + } + } + LogPrintf( "Other Segs:\n"); + for ( int inx = 0; inx < trackSegs_da.cnt; inx++ ) { + if (!IsSegTrack(&trackSegs(inx))) { + LogPrintf( " %d: ", inx+1 ); + LogSeg( &tempSegs(inx) ); + } + } } - LogPrintf( "Other Segs:\n"); - for ( int inx = 0; inx < tempSegs_da.cnt; inx++ ) { - LogPrintf( " %d: ", inx+1 ); - LogSeg( &tempSegs(inx) ); + + if ( nTrkSeg > MAX_PATH_SEGS ) { + // Too many track segs + NoticeMessage( MSG_TOOMANYSEGSINGROUP, _("Ok"), NULL ); + wDrawDelayUpdate( mainD.d, FALSE ); + wHide( groupW ); + return; } -} -if ( log_group >= 1 && logTable(log_group).level >= 3 ) { - LogPrintf( "Combined Segs:\n" ); - for ( int inx = 0; inx<segInMap_da.cnt; inx++ ) { - LogPrintf( "%d: %s X%d - ", inx+1, segInMap(inx).track?"Track":"Other", segInMap(inx).inx ); - LogSeg( GetSegFromSegMap( inx ) ); + if ( iLastTrkSeg > MAX_PATH_SEGS ) { + // track segs beyond threshold + NoticeMessage( MSG_TOOMANYSEGSINGROUP2, _("Ok"), NULL ); + wDrawDelayUpdate( mainD.d, FALSE ); + wHide( groupW ); + return; } -} - - if ( groupTrk_da.cnt>0 ) { - if ( groupTrk_da.cnt > 128 ) { - NoticeMessage( MSG_TOOMANYSEGSINGROUP, _("Ok"), NULL ); - wDrawDelayUpdate( mainD.d, FALSE ); - wHide( groupW ); - return; - } + if ( groupTrk_da.cnt>0 && hasTracks) { /* * Collect EndPts and find paths */ @@ -1200,51 +1283,49 @@ if ( log_group >= 1 && logTable(log_group).level >= 3 ) { trk1 = GetTrkEndTrk(trk,ep); if ( trk1 == NULL || !GetTrkSelected(trk1) ) { /* boundary EP */ - for ( epN=0; epN<tempEndPts_da.cnt; epN++ ) { - dist = FindDistance( GetTrkEndPos(trk,ep), tempEndPts(epN).pos ); - angle = NormalizeAngle( GetTrkEndAngle(trk,ep) - tempEndPts(epN).angle + connectAngle/2.0 ); - if ( dist < connectDistance && angle < connectAngle ) + for ( epN=0; epN<TempEndPtsCount(); epN++ ) { + dist = FindDistance( GetTrkEndPos(trk,ep), GetEndPtPos(TempEndPt(epN)) ); + angle = NormalizeAngle( GetTrkEndAngle(trk, + ep) - GetEndPtAngle(TempEndPt(epN)) + connectAngle/2.0 ); + if ( dist < connectDistance && angle < connectAngle ) { break; + } } - if ( epN>=tempEndPts_da.cnt ) { - DYNARR_APPEND( trkEndPt_t, tempEndPts_da, 10 ); - endPtP = &tempEndPts(tempEndPts_da.cnt-1); - memset( endPtP, 0, sizeof *endPtP ); - endPtP->pos = GetTrkEndPos(trk,ep); - endPtP->angle = GetTrkEndAngle(trk,ep); - endPtP->track = trk1; - endPtP->index = (trk1?GetEndPtConnectedToMe(trk1,trk):-1); - endPtOrig.x += endPtP->pos.x; - endPtOrig.y += endPtP->pos.y; + if ( epN>=TempEndPtsCount() ) { + endPtP = TempEndPtsAppend(); + SetEndPt( endPtP, GetTrkEndPos(trk,ep), GetTrkEndAngle(trk,ep)); + SetEndPtTrack( endPtP, trk1 ); + // Remember what EP on trk1 was connecting to me + SetEndPtEndPt( endPtP, trk1?GetEndPtConnectedToMe(trk1,trk):-1 ); + endPtOrig.x += GetEndPtPos(endPtP).x; + endPtOrig.y += GetEndPtPos(endPtP).y; } } } } -if ( log_group >= 1 && logTable(log_group).level >= 4 ) { - LogPrintf( "EndPts:\n" ); - for ( int inx=0; inx<tempEndPts_da.cnt; inx++ ) { - endPtP = &tempEndPts(inx); - LogPrintf( " [ %0.3f %0.3f ] A:%0.3f, T:%d.%d\n", - endPtP->pos.x, endPtP->pos.y, endPtP->angle, endPtP->track?GetTrkIndex(endPtP->track):-1, endPtP->index ); - } -} + if ( log_group >= 1 && logTable(log_group).level >= 4 ) { + LogPrintf( "EndPts:\n" ); + for ( int inx=0; inx<TempEndPtsCount(); inx++ ) { + endPtP = TempEndPt(inx); + LogPrintf( " [ %0.3f %0.3f ] A:%0.3f, T:%d.%d\n", + GetEndPtPos(endPtP).x, GetEndPtPos(endPtP).y, GetEndPtAngle(endPtP), + GetEndPtTrack(endPtP)?GetTrkIndex(GetEndPtTrack(endPtP)):-1, + GetEndPtEndPt(endPtP) ); + } + } /* * 2: Collect EndPts */ - if ( tempEndPts_da.cnt <= 0 ) { + if ( TempEndPtsCount() <= 0 ) { NoticeMessage( _("No endpts"), _("Ok"), NULL ); wDrawDelayUpdate( mainD.d, FALSE ); wHide( groupW ); return; } - if ( groupTrk_da.cnt == 1 && GetTrkType( groupTrk(0).trk ) == T_TURNOUT ) { - path = xx->paths; - pathLen = xx->pathLen; - goto groupSimpleTurnout; - } /* Make sure no turnouts in groupTrk list have a path end which is not an EndPt */ - //TODO Add Trap Points (which are Turnouts with a bumper track) + // TODO-BUMPER Add Trap Points (which are Turnouts with a bumper track) + // for Bumper support remove this loop for ( inx=0; inx<groupTrk_da.cnt; inx++ ) { trk = groupTrk(0).trk; if ( GetTrkType( trk ) == T_TURNOUT ) { @@ -1272,37 +1353,38 @@ if ( log_group >= 1 && logTable(log_group).level >= 4 ) { /* * Sort EndPts by angle */ - endPtOrig.x /= tempEndPts_da.cnt; - endPtOrig.y /= tempEndPts_da.cnt; + endPtOrig.x /= TempEndPtsCount(); + endPtOrig.y /= TempEndPtsCount(); angleN = 270.0; epN = -1; - for ( ep=0; ep<tempEndPts_da.cnt; ep++ ) { - angle = FindAngle(endPtOrig,tempEndPts(ep).pos); + for ( ep=0; ep<TempEndPtsCount(); ep++ ) { + angle = FindAngle(endPtOrig,GetEndPtPos(TempEndPt(ep))); if ( fabs(angle-270.0) < angleN ) { epN = ep; angleN = fabs(angle-270.0); endPtAngle = angle; } } - qsort( tempEndPts_da.ptr, tempEndPts_da.cnt, sizeof *endPtP, CmpEndPtAngle ); - if ( NormalizeAngle( tempEndPts(0).angle - tempEndPts(tempEndPts_da.cnt-1).angle ) > - NormalizeAngle( tempEndPts(1).angle - tempEndPts(0).angle ) ) { - - for ( ep=1; ep<(tempEndPts_da.cnt+1)/2; ep++ ) { - trkEndPt_t tempEndPt; - tempEndPt = tempEndPts(ep); - tempEndPts(ep) = tempEndPts(tempEndPts_da.cnt-ep); - tempEndPts(tempEndPts_da.cnt-ep) = tempEndPt; + qsort( TempEndPt(0), TempEndPtsCount(), EndPtSize(1), CmpEndPtAngle ); + // TODO-BUMPER - handle TempEndPt(1) + if ( NormalizeAngle( GetEndPtAngle(TempEndPt(0)) - GetEndPtAngle(TempEndPt( + TempEndPtsCount()-1)) ) > + NormalizeAngle( GetEndPtAngle(TempEndPt(1)) - GetEndPtAngle(TempEndPt(0)) ) ) { + + for ( ep=1; ep<(TempEndPtsCount()+1)/2; ep++ ) { + SwapEndPts( TempEndPt(0), ep, TempEndPtsCount()-ep ); + } + } + if ( log_group >= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Sorted EndPts:\n" ); + for ( int inx=0; inx<TempEndPtsCount(); inx++ ) { + endPtP = TempEndPt(inx); + track_p trk1 = GetEndPtTrack(endPtP); + LogPrintf( " [ %0.3f %0.3f ] A:%0.3f, T:%d.%d\n", + GetEndPtPos(endPtP).x, GetEndPtPos(endPtP).y, GetEndPtAngle(endPtP), + trk1?GetTrkIndex(trk1):-1, GetEndPtEndPt(endPtP) ); } } -if ( log_group >= 1 && logTable(log_group).level >= 3 ) { - LogPrintf( "Sorted EndPts:\n" ); - for ( int inx=0; inx<tempEndPts_da.cnt; inx++ ) { - endPtP = &tempEndPts(inx); - LogPrintf( " [ %0.3f %0.3f ] A:%0.3f, T:%d.%d\n", - endPtP->pos.x, endPtP->pos.y, endPtP->angle, endPtP->track?GetTrkIndex(endPtP->track):-1, endPtP->index ); - } -} /* * 3: Find shortest Paths @@ -1319,35 +1401,40 @@ if ( log_group >= 1 && logTable(log_group).level >= 3 ) { } } } -if ( log_group >= 1 && logTable(log_group).level >= 3 ) { - LogPrintf( "Shortest path:\n Group Tracks\n" ); - for ( int inx=0; inx<groupTrk_da.cnt; inx++ ) { - groupTrk_p gtp = &groupTrk(inx); - LogPrintf( " %d: T%d S%d-%d\n", inx, GetTrkIndex( gtp->trk ), gtp->segStart+1, gtp->segEnd+1 ); - } - LogPrintf( " Path Elem\n" ); - for ( int inx=0; inx<pathElem_da.cnt; inx++ ) { - ppp = &pathElem(inx); - LogPrintf( " %d: GTx: %d, EP: %d %d, F:%s, P:", - inx, ppp->groupInx, ppp->ep1, ppp->ep2, ppp->flip?"T":"F" ); - for ( PATHPTR_T cp = ppp->path; cp[0] || cp[1]; cp++ ) { - LogPrintf( " %d", *cp ); - } - LogPrintf( " 0\n" ); - } - LogPrintf( " Path\n" ); - for ( int inx=0; inx<path_da.cnt; inx++ ) { - path_p pp = &path(inx); - LogPrintf( " %d: PE: %d-%d, EP: %d-%d, Conf: %d, InGrp: %s, Done: %s\n", - inx, pp->pathElemStart, pp->pathElemEnd, pp->ep1, pp->ep2, - pp->conflicts, pp->inGroup?"T":"F", pp->done?"T":"F" ); - } -} + if ( log_group >= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Shortest path:\n Group Tracks\n" ); + for ( int inx=0; inx<groupTrk_da.cnt; inx++ ) { + groupTrk_p gtp = &groupTrk(inx); + LogPrintf( " %d: T%d S%d-%d\n", inx, GetTrkIndex( gtp->trk ), + gtp->segStart+1, gtp->segEnd+1 ); + } + LogPrintf( " Path Elem\n" ); + for ( int inx=0; inx<pathElem_da.cnt; inx++ ) { + ppp = &pathElem(inx); + LogPrintf( " %d: GTx: %d, EP: %d %d, F:%s, P:", + inx, ppp->groupInx, ppp->ep1, ppp->ep2, ppp->flip?"T":"F" ); + if ( ppp->path == NULL ) { + LogPrintf( "No Paths!\n" ); + } else { + for ( PATHPTR_T cp = ppp->path; cp[0] || cp[1]; cp++ ) { + LogPrintf( " %d", *cp ); + } + } + LogPrintf( " 0\n" ); + } + LogPrintf( " Path\n" ); + for ( int inx=0; inx<path_da.cnt; inx++ ) { + path_p pp = &path(inx); + LogPrintf( " %d: PE: %d-%d, EP: %d-%d, Conf: %d, InGrp: %s, Done: %s\n", + inx, pp->pathElemStart, pp->pathElemEnd, pp->ep1, pp->ep2, + pp->conflicts, pp->inGroup?"T":"F", pp->done?"T":"F" ); + } + } /* * 4: Flip paths so they align */ if ( path_da.cnt == 0 ) { - NoticeMessage( _("No paths"), _("Ok"), NULL ); + NoticeMessage( MSG_GROUP_NO_PATHS, _("Ok"), NULL ); wDrawDelayUpdate( mainD.d, FALSE ); wHide( groupW ); return; @@ -1359,24 +1446,25 @@ if ( log_group >= 1 && logTable(log_group).level >= 3 ) { inx = -1; for ( pinx=0; pinx<path_da.cnt; pinx++ ) { pp = &path(pinx); - if ( pp->done ) continue; + if ( pp->done ) { continue; } for ( pinx2=0; pinx2<path_da.cnt; pinx2++ ) { - if ( pinx2==pinx ) continue; + if ( pinx2==pinx ) { continue; } ppN = &path(pinx2); if ( pp->ep1 == ppN->ep1 || - pp->ep2 == ppN->ep2 ) { + pp->ep2 == ppN->ep2 ) { pp->done = TRUE; allDone = FALSE; -LOG( log_group, 1, ( "P%d aligns with P%d\n", pinx, pinx2 ) ); + LOG( log_group, 1, ( "P%d aligns with P%d\n", pinx, pinx2 ) ); break; } if ( pp->ep1 == ppN->ep2 || - pp->ep2 == ppN->ep1 ) { + pp->ep2 == ppN->ep1 ) { pp->done = TRUE; allDone = FALSE; -LOG( log_group, 1, ( "P%d aligns flipped with P%d\n", pinx, pinx2 ) ); + LOG( log_group, 1, ( "P%d aligns flipped with P%d\n", pinx, pinx2 ) ); inx = (pp->pathElemStart+pp->pathElemEnd-1)/2; - for ( ginx=pp->pathElemStart,ginx2=pp->pathElemEnd; ginx<=inx; ginx++,ginx2-- ) { + for ( ginx=pp->pathElemStart,ginx2=pp->pathElemEnd; ginx<=inx; + ginx++,ginx2-- ) { pathElemTemp = pathElem(ginx); pathElem(ginx) = pathElem(ginx2); pathElem(ginx2) = pathElemTemp; @@ -1394,33 +1482,35 @@ LOG( log_group, 1, ( "P%d aligns flipped with P%d\n", pinx, pinx2 ) ); break; } } - if ( inx<0 && !pp->done ) + if ( inx<0 && !pp->done ) { inx = pinx; + } } if ( allDone && inx>=0 ) { allDone = FALSE; path(inx).done = TRUE; - } - } -if ( log_group >= 1 && logTable(log_group).level >= 1 ) { - LogPrintf( "Group Paths\n" ); - for ( pinx=0; pinx<path_da.cnt; pinx++ ) { - pp = &path(pinx); - LogPrintf( " P%2d:%d.%d ", pinx, pp->ep1, pp->ep2 ); - for ( pinx2=pp->pathElemEnd; pinx2>=pp->pathElemStart; pinx2-- ) { - ppp = &pathElem(pinx2); - LogPrintf( " %sT%d:%d.%d", ppp->flip?"-":"", GetTrkIndex(groupTrk(ppp->groupInx).trk), ppp->ep1, ppp->ep2 ); - } - LogPrintf( "\n" ); - } -} + } + } + if ( log_group >= 1 && logTable(log_group).level >= 1 ) { + LogPrintf( "Group Paths\n" ); + for ( pinx=0; pinx<path_da.cnt; pinx++ ) { + pp = &path(pinx); + LogPrintf( " P%2d:%d.%d ", pinx, pp->ep1, pp->ep2 ); + for ( pinx2=pp->pathElemEnd; pinx2>=pp->pathElemStart; pinx2-- ) { + ppp = &pathElem(pinx2); + LogPrintf( " %sT%d:%d.%d", ppp->flip?"-":"", + GetTrkIndex(groupTrk(ppp->groupInx).trk), ppp->ep1, ppp->ep2 ); + } + LogPrintf( "\n" ); + } + } /* * 5: Create Conflict Map */ DYNARR_SET( int, conflictMap_da, path_da.cnt*path_da.cnt ); - memset( conflictMap_da.ptr, 0, conflictMap_da.max * sizeof conflictMap(0,0) ); + memset( &conflictMap(0,0), 0, conflictMap_da.cnt * sizeof conflictMap(0,0) ); for ( pinx=0; pinx<path_da.cnt; pinx++ ) { for ( pinx2=pinx+1; pinx2<path_da.cnt; pinx2++ ) { if ( ConflictPaths( &path(pinx), &path(pinx2) ) ) { @@ -1435,27 +1525,28 @@ if ( log_group >= 1 && logTable(log_group).level >= 1 ) { * Sort Paths by number of conflicts */ DYNARR_SET( int, groupOrder_da, path_da.cnt ); - for ( pinx=0; pinx<path_da.cnt; pinx++ ) groupOrder(pinx) = pinx; - qsort( groupOrder_da.ptr, path_da.cnt, sizeof groupOrder(0), CmpGroupOrder ); + for ( pinx=0; pinx<path_da.cnt; pinx++ ) { groupOrder(pinx) = pinx; } + qsort( &groupOrder(0), path_da.cnt, sizeof groupOrder(0), CmpGroupOrder ); /* - * Group Paths, 1st pass: + * Group Paths, 1st pass: */ DYNARR_SET( int, groupMap_da, path_da.cnt*(path_da.cnt+1) ); - memset( groupMap_da.ptr, -1, groupMap_da.max * sizeof groupMap(0,0) ); + memset( &groupMap(0,0), -1, groupMap_da.cnt * sizeof groupMap(0,0) ); groupCnt = 0; for ( pinx=0; pinx<path_da.cnt; pinx++ ) { pp = &path(groupOrder(pinx)); - if ( pp->inGroup ) continue; + if ( pp->inGroup ) { continue; } pp->inGroup = TRUE; groupCnt++; groupMap( groupCnt-1, 0 ) = groupOrder(pinx); ginx = 1; for ( pinx2=pinx+1; pinx2<path_da.cnt; pinx2++ ) { gpinx2 = groupOrder(pinx2); - if ( path(gpinx2).inGroup ) continue; - for ( ginx2=0; ginx2<ginx && !conflictMap(groupMap(groupCnt-1,ginx2),gpinx2); ginx2++ ); - if ( ginx2<ginx ) continue; + if ( path(gpinx2).inGroup ) { continue; } + for ( ginx2=0; ginx2<ginx + && !conflictMap(groupMap(groupCnt-1,ginx2),gpinx2); ginx2++ ); + if ( ginx2<ginx ) { continue; } path(gpinx2).inGroup = TRUE; groupMap( groupCnt-1, ginx++ ) = gpinx2; } @@ -1469,22 +1560,24 @@ if ( log_group >= 1 && logTable(log_group).level >= 1 ) { for ( pinx2=0; pinx2<path_da.cnt; pinx2++ ) { gpinx2 = groupOrder(pinx2); for ( ginx2=0; ginx2<ginx && groupMap(pinx,ginx2)!=gpinx2; ginx2++ ); - if ( ginx2<ginx ) continue; /* already on list */ - for ( ginx2=0; ginx2<ginx && !conflictMap(groupMap(pinx,ginx2),gpinx2); ginx2++ ); - if ( ginx2<ginx ) continue; /* conflicts with someone on list */ + if ( ginx2<ginx ) { continue; } /* already on list */ + for ( ginx2=0; ginx2<ginx + && !conflictMap(groupMap(pinx,ginx2),gpinx2); ginx2++ ); + if ( ginx2<ginx ) { continue; } /* conflicts with someone on list */ groupMap(pinx,ginx++) = gpinx2; } } -if ( log_group >= 1 && logTable(log_group).level >= 3 ) { - LogPrintf( "Group Map\n"); - for ( pinx=0; pinx<groupCnt; pinx++ ) { - LogPrintf( "G%d:", pinx ); - for ( ginx=0; groupMap(pinx,ginx) >= 0; ginx++ ) - LogPrintf( " %d: %d", ginx, groupMap(pinx,ginx) ); - LogPrintf( "\n" ); - } -} + if ( log_group >= 1 && logTable(log_group).level >= 3 ) { + LogPrintf( "Group Map\n"); + for ( pinx=0; pinx<groupCnt; pinx++ ) { + LogPrintf( "G%d:", pinx ); + for ( ginx=0; groupMap(pinx,ginx) >= 0; ginx++ ) { + LogPrintf( " %d: %d", ginx, groupMap(pinx,ginx) ); + } + LogPrintf( "\n" ); + } + } /* * 6: Count number of times each segment is used as flipped @@ -1493,34 +1586,36 @@ if ( log_group >= 1 && logTable(log_group).level >= 3 ) { memset( &segFlip(0), 0, trackSegs_da.cnt * sizeof segFlip(0) ); for ( pinx=0; pinx<pathElem_da.cnt; pinx++ ) { ppp = &pathElem(pinx); - for ( path=ppp->path; *path; path++ ) { - inx = *path; - if ( inx<0 ) + for ( PATHPTR_T pPaths=ppp->path; pPaths && *pPaths; pPaths++ ) { + inx = *pPaths; + if ( inx<0 ) { inx = - inx; - if ( inx > trackSegs_da.cnt ) - AbortProg( "inx > trackSegs_da.cnt" ); - flip = *path<0; - if ( ppp->flip ) + } + CHECK( inx <= trackSegs_da.cnt ); + flip = *pPaths<0; + if ( ppp->flip ) { flip = !flip; + } inx += groupTrk(ppp->groupInx).segStart - 1; - if ( !flip ) + if ( !flip ) { segFlip(inx)++; - else + } else { segFlip(inx)--; + } } } /* * Flip each segment that is used as flipped more than not */ -LOG( log_group, 3, ( "Flipping Segments:" ) ); + LOG( log_group, 3, ( "Flipping Segments:" ) ); for ( pinx=0; pinx<trackSegs_da.cnt; pinx++ ) { if ( segFlip(pinx) < 0 ) { - SegProc( SEGPROC_FLIP, &trackSegs(pinx), NULL ); -LOG( log_group, 3, ( " %d", pinx ) ); + SegProc( SEGPROC_FLIP, &trackSegs(pinx), NULL ); + LOG( log_group, 3, ( " %d", pinx ) ); } } -LOG( log_group, 3, ( "\n" ) ); + LOG( log_group, 3, ( "\n" ) ); /* * 7: Output Path lists @@ -1532,30 +1627,39 @@ LOG( log_group, 3, ( "\n" ) ); memcpy( &pathPtr(inx), message, pathPtr_da.cnt-inx ); for ( ginx=0; groupMap(pinx,ginx) >= 0; ginx++ ) { pp = &path(groupMap(pinx,ginx)); - LOG( log_group, 3, (" Group Map(%d, %d): elem %d-%d, EP %d %d, Conflicts %d, inGrp %d, Done: %s\n", pinx, ginx, pp->pathElemStart, pp->pathElemEnd, pp->ep1, pp->ep2, pp->conflicts, pp->inGroup, pp->done?"T":"F" ) ); + LOG( log_group, 3, + (" Group Map(%d, %d): elem %d-%d, EP %d %d, Conflicts %d, inGrp %d, Done: %s\n", + pinx, ginx, pp->pathElemStart, pp->pathElemEnd, pp->ep1, pp->ep2, pp->conflicts, + pp->inGroup, pp->done?"T":"F" ) ); for ( pinx2=pp->pathElemEnd; pinx2>=pp->pathElemStart; pinx2-- ) { ppp = &pathElem( pinx2 ); - LOG( log_group, 3, (" PE %d: GI %d, EP %d %d, Flip %d =", pinx2, ppp->groupInx, ppp->ep1, ppp->ep2, ppp->flip )); + LOG( log_group, 3, (" PE %d: GI %d, EP %d %d, Flip %d =", pinx2, + ppp->groupInx, ppp->ep1, ppp->ep2, ppp->flip )); groupP = &groupTrk( ppp->groupInx ); - path = ppp->path; + PATHPTR_T pPaths = ppp->path; flip = ppp->flip; - if ( path == NULL ) - AbortProg( "Missing Path T%d:%d.%d", GetTrkIndex(groupP->trk), ppp->ep2, ppp->ep1 ); - if ( flip ) path += strlen((char *)path)-1; - while ( *path && (path >= ppp->path) ) { //Add Guard for flip backwards + if ( pPaths == NULL ) { + ErrorMessage( MSG_GROUP_NO_PATHS, _("Ok"), NULL ); + wDrawDelayUpdate( mainD.d, FALSE ); + wHide( groupW ); + return; + } + if ( flip ) { pPaths += strlen((char *)pPaths)-1; } + while ( *pPaths && (pPaths >= ppp->path) ) { //Add Guard for flip backwards DYNARR_APPEND( char, pathPtr_da, 10 ); - pathChar = *path; + pathChar = *pPaths; flip1 = flip; if ( pathChar < 0 ) { flip1 = !flip; pathChar = - pathChar; } pathChar = groupP->segStart+pathChar; - if ( segFlip(pathChar-1)<0 ) + if ( segFlip(pathChar-1)<0 ) { flip1 = ! flip1; - if ( flip1 ) pathChar = - pathChar; + } + if ( flip1 ) { pathChar = - pathChar; } pathPtr(pathPtr_da.cnt-1) = pathChar; - path += (flip?-1:1); + pPaths += (flip?-1:1); LOG( log_group, 3, (" %d", pathChar ) ); } LOG( log_group, 3, ("\n") ); @@ -1568,49 +1672,58 @@ LOG( log_group, 3, ( "\n" ) ); } DYNARR_APPEND( char, pathPtr_da, 10 ); pathPtr(pathPtr_da.cnt-1) = 0; - path = (PATHPTR_T)&pathPtr(0); - pathLen = pathPtr_da.cnt; -groupSimpleTurnout: /* * 8: Copy and Reorigin Segments - Start by putting them out in the original order */ DYNARR_RESET(trkSeg_t, outputSegs_da); - for (int i=0; i<segInMap_da.cnt;i++) { + for (int i=0; i<trackSegs_da.cnt; i++) { DYNARR_APPEND(trkSeg_t,outputSegs_da,10); - trkSeg_p from_p = GetSegFromSegMap(i); + trkSeg_p from_p = &trackSegs(i); trkSeg_p to_p = &DYNARR_LAST(trkSeg_t, outputSegs_da); - memcpy((void *)to_p,(void *)from_p,sizeof( trkSeg_t)); + memcpy(to_p,from_p,sizeof( trkSeg_t)); } - CloneFilledDraw( outputSegs_da.cnt, outputSegs_da.ptr, FALSE ); + CloneFilledDraw( outputSegs_da.cnt, &outputSegs(0), FALSE ); GetSegBounds( zero, 0, outputSegs_da.cnt, &outputSegs(0), &orig, &size ); - orig.x = - tempEndPts(0).pos.x; - orig.y = - tempEndPts(0).pos.y; + orig.x = - GetEndPtPos(TempEndPt(0)).x; + orig.y = - GetEndPtPos(TempEndPt(0)).y; MoveSegs( outputSegs_da.cnt, &outputSegs(0), orig ); - for ( ep=0; ep<tempEndPts_da.cnt; ep++ ) { - tempEndPts(ep).pos.x += orig.x; - tempEndPts(ep).pos.y += orig.y; + for ( ep=0; ep<TempEndPtsCount(); ep++ ) { + trkEndPt_p epp = TempEndPt(ep); + coOrd pos = GetEndPtPos(epp); + pos.x += orig.x; + pos.y += orig.y; + SetEndPt( epp, pos, GetEndPtAngle(epp) ); } /* * 9: Final: create new definition */ - CheckPaths( outputSegs_da.cnt, &outputSegs(0), path ); + PATHPTR_T pPaths = (PATHPTR_T)&pathPtr(0); + CheckPaths( outputSegs_da.cnt, &outputSegs(0), pPaths, groupTitle ); - to = CreateNewTurnout( curScaleName, groupTitle, outputSegs_da.cnt, &outputSegs(0), pathLen, path, tempEndPts_da.cnt, &tempEndPts(0), NULL, TRUE ); + long options = 0; + if ( groupNoCombine != 0 ) { + options |= COMPOUND_OPTION_PATH_NOCOMBINE; + } + to = CreateNewTurnout( curScaleName, groupTitle, outputSegs_da.cnt, + &outputSegs(0), pPaths, TempEndPtsCount(), TempEndPt(0), TRUE, options ); /* * 10: Write defn to xtrkcad.cus */ f = OpenCustom("a"); if (f && to) { - oldLocale = SaveLocale("C"); - rc &= fprintf( f, "TURNOUT %s \"%s\"\n", curScaleName, PutTitle(to->title) )>0; - rc &= WriteCompoundPathsEndPtsSegs( f, path, outputSegs_da.cnt, &outputSegs(0), tempEndPts_da.cnt, &tempEndPts(0) ); + SetCLocale(); + rc &= fprintf( f, "TURNOUT %s \"%s\" %ld\n", curScaleName, PutTitle(to->title), + options )>0; + rc &= WriteCompoundPathsEndPtsSegs( f, pPaths, outputSegs_da.cnt, + &outputSegs(0), TempEndPtsCount(), TempEndPt(0) ); + SetUserLocale(); } if ( groupReplace ) { /* @@ -1619,17 +1732,21 @@ groupSimpleTurnout: UndoStart( _("Group Tracks"), "group" ); orig.x = - orig.x; orig.y = - orig.y; - for ( ep=0; ep<tempEndPts_da.cnt; ep++ ) { - endPtP = &tempEndPts(ep); - if ( endPtP->track ) { - trk = GetTrkEndTrk( endPtP->track, endPtP->index ); - epN = GetEndPtConnectedToMe( trk, endPtP->track ); - DrawEndPt( &mainD, endPtP->track, endPtP->index, wDrawColorWhite ); + for ( ep=0; ep<TempEndPtsCount(); ep++ ) { + endPtP = TempEndPt(ep); + track_p trk1 = GetEndPtTrack(endPtP); + if ( trk1 ) { + EPINX_T ep1 = GetEndPtEndPt(endPtP); + trk = GetTrkEndTrk( trk1, ep1 ); + epN = GetEndPtConnectedToMe( trk, trk1 ); + DrawEndPt( &mainD, trk1, ep1, wDrawColorWhite ); DrawEndPt( &mainD, trk, epN, wDrawColorWhite ); - DisconnectTracks( trk, epN, endPtP->track, endPtP->index ); + DisconnectTracks( trk, epN, trk1, ep1 ); } - endPtP->pos.x += orig.x; - endPtP->pos.y += orig.y; + coOrd pos = GetEndPtPos(endPtP); + pos.x += orig.x; + pos.y += orig.y; + SetEndPt( endPtP, pos, GetEndPtAngle(endPtP) ); } trk = NULL; while ( TrackIterate( &trk ) ) { @@ -1639,31 +1756,43 @@ groupSimpleTurnout: trackCount--; } } - trk = NewCompound( T_TURNOUT, 0, orig, 0.0, to->title, tempEndPts_da.cnt, &tempEndPts(0), NULL, pathLen, (char *)path, outputSegs_da.cnt, &outputSegs(0) ); + SelectRecount(); + trk = NewCompound( T_TURNOUT, 0, orig, 0.0, to->title, TempEndPtsCount(), + TempEndPt(0), pPaths, outputSegs_da.cnt, &outputSegs(0) ); + struct extraDataCompound_t *xx = GET_EXTRA_DATA(trk, T_TURNOUT, + extraDataCompound_t); + xx->pathOverRide = FALSE; + xx->pathNoCombine = groupNoCombine; SetTrkVisible( trk, TRUE ); - for ( ep=0; ep<tempEndPts_da.cnt; ep++ ) { - if ( tempEndPts(ep).track ) { - ConnectTracks( trk, ep, tempEndPts(ep).track, (EPINX_T)tempEndPts(ep).index ); - DrawEndPt( &mainD, tempEndPts(ep).track, (EPINX_T)tempEndPts(ep).index, GetTrkColor( tempEndPts(ep).track, &mainD ) ); + for ( ep=0; ep<TempEndPtsCount(); ep++ ) { + trkEndPt_p epp = TempEndPt(ep); + track_p trk1 = GetEndPtTrack(epp); + if ( trk1 ) { + EPINX_T ep1 = GetEndPtEndPt(epp); + ConnectTracks( trk, ep, trk1, ep1 ); + DrawEndPt( &mainD, trk1, ep1, GetTrkColor(trk1, &mainD ) ); } } DrawNewTrack( trk ); EnableCommands(); } } else { - CloneFilledDraw( tempSegs_da.cnt, &tempSegs(0), TRUE ); - GetSegBounds( zero, 0, tempSegs_da.cnt, &tempSegs(0), &orig, &size ); + CloneFilledDraw( trackSegs_da.cnt, &trackSegs(0), TRUE ); + GetSegBounds( zero, 0, trackSegs_da.cnt, &trackSegs(0), &orig, &size ); orig.x = - orig.x-groupOriginX; //Include orig offset orig.y = - orig.y-groupOriginY; - MoveSegs( tempSegs_da.cnt, &tempSegs(0), orig ); - to = CreateNewStructure( curScaleName, groupTitle, tempSegs_da.cnt, &tempSegs(0), TRUE ); + MoveSegs( trackSegs_da.cnt, &trackSegs(0), orig ); + to = CreateNewStructure( curScaleName, groupTitle, trackSegs_da.cnt, + &trackSegs(0), TRUE ); f = OpenCustom("a"); if (f && to) { - oldLocale = SaveLocale("C"); - rc &= fprintf( f, "STRUCTURE %s \"%s\"\n", curScaleName, PutTitle(groupTitle) )>0; - rc &= WriteSegs( f, tempSegs_da.cnt, &tempSegs(0) ); + SetCLocale(); + rc &= fprintf( f, "STRUCTURE %s \"%s\"\n", curScaleName, + PutTitle(groupTitle) )>0; + rc &= WriteSegs( f, trackSegs_da.cnt, &trackSegs(0) ); + SetUserLocale(); } if ( groupReplace ) { UndoStart( _("Group Tracks"), "group" ); @@ -1675,16 +1804,17 @@ groupSimpleTurnout: trackCount--; } } + SelectRecount(); orig.x = - orig.x; orig.y = - orig.y; - trk = NewCompound( T_STRUCTURE, 0, orig, 0.0, groupTitle, 0, NULL, NULL, 0, "", tempSegs_da.cnt, &tempSegs(0) ); + trk = NewCompound( T_STRUCTURE, 0, orig, 0.0, groupTitle, 0, NULL, NULL, + trackSegs_da.cnt, &trackSegs(0) ); SetTrkVisible( trk, TRUE ); DrawNewTrack( trk ); EnableCommands(); } } - if (f) fclose(f); - RestoreLocale(oldLocale); + if (f) { fclose(f); } DoChangeNotification( CHANGE_PARAMS ); wHide( groupW ); wDrawDelayUpdate( mainD.d, FALSE ); @@ -1693,10 +1823,10 @@ groupSimpleTurnout: } -EXPORT void DoGroup( void ) +EXPORT void DoGroup( void * unused ) { track_p trk = NULL; - struct extraData *xx; + struct extraDataCompound_t *xx; TRKTYP_T trkType; xx = NULL; groupSegCnt = 0; @@ -1705,16 +1835,22 @@ EXPORT void DoGroup( void ) groupOriginY = 0.0; BOOL_T isTurnout = FALSE; + groupNoCombine = FALSE; while ( TrackIterate( &trk ) ) { if ( GetTrkSelected( trk ) ) { trkType = GetTrkType(trk); - if ( IsTrack(trk) ) isTurnout = TRUE; + if ( IsTrack(trk) ) { isTurnout = TRUE; } if ( trkType == T_TURNOUT || trkType == T_STRUCTURE ) { - xx = GetTrkExtraData(trk); + xx = GET_EXTRA_DATA(trk, trkType, extraDataCompound_t); groupSegCnt += xx->segCnt; GroupCopyTitle( xtitle(xx) ); - } else + if ( trkType == T_TURNOUT && GetTrkEndPtCnt(trk) > 2 + && xx->pathNoCombine != 0 ) { + groupNoCombine = TRUE; + } + } else { groupSegCnt += 1; + } } } if ( groupSegCnt <= 0 ) { @@ -1722,11 +1858,13 @@ EXPORT void DoGroup( void ) return; } sprintf( groupTitle, "%s\t%s\t%s", groupManuf, groupDesc, groupPartno ); - if ( log_group < 0 ) + if ( log_group < 0 ) { log_group = LogFindIndex( "group" ); + } if ( !groupW ) { ParamRegister( &groupPG ); - groupW = ParamCreateDialog( &groupPG, MakeWindowTitle(_("Group Objects")), _("Ok"), GroupOk, wHide, TRUE, NULL, F_BLOCK, NULL ); + groupW = ParamCreateDialog( &groupPG, MakeWindowTitle(_("Group Objects")), + _("Ok"), GroupOk, wHide, TRUE, NULL, F_BLOCK, NULL ); groupD.dpi = mainD.dpi; } if (isTurnout) { |