diff options
author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 21:26:53 +0200 |
---|---|---|
committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2020-08-24 21:26:53 +0200 |
commit | df247efec654e512242e4f4f1b0212034f9e01fe (patch) | |
tree | 25c02e16957f3aa613af30c140fd8e8a3d52fda6 /app/bin/cturnout.c | |
parent | d0b6a8a4ec298024f14f704f9e40a6f9d324ccf3 (diff) | |
parent | a5ade52caa489cf0a713e0f02b764000d203140e (diff) |
Merge branch 'release/debian/1%5.2.0Beta2.1-1' into masterdebian/1%5.2.0Beta2.1-1
Diffstat (limited to 'app/bin/cturnout.c')
-rw-r--r-- | app/bin/cturnout.c | 1186 |
1 files changed, 880 insertions, 306 deletions
diff --git a/app/bin/cturnout.c b/app/bin/cturnout.c index eace782..150f381 100644 --- a/app/bin/cturnout.c +++ b/app/bin/cturnout.c @@ -27,6 +27,7 @@ #include "ccurve.h" #include "tbezier.h" +#include "tcornu.h" #include "cjoin.h" #include "compound.h" #include "cstraigh.h" @@ -37,7 +38,9 @@ #include "layout.h" #include "messages.h" #include "param.h" +#include "include/paramfile.h" #include "track.h" +#include "trackx.h" #include "utility.h" EXPORT TRKTYP_T T_TURNOUT = -1; @@ -50,9 +53,12 @@ EXPORT dynArr_t turnoutInfo_da; EXPORT turnoutInfo_t * curTurnout = NULL; EXPORT long curTurnoutEp = 0; +static int curTurnoutInx = -1; static int log_turnout = 0; static int log_traverseTurnout = 0; +static int log_suppressCheckPaths = 0; +static int log_splitturnout = 0; static wMenu_p turnoutPopupM; @@ -71,6 +77,7 @@ static wIndex_t turnoutInx; static long hideTurnoutWindow; static void RedrawTurnout(void); static void SelTurnoutEndPt( wIndex_t, coOrd ); +static void HilightEndPt( void ); static wPos_t turnoutListWidths[] = { 80, 80, 220 }; static const char * turnoutListTitles[] = { N_("Manufacturer"), N_("Part No"), N_("Description") }; @@ -111,6 +118,7 @@ EXPORT turnoutInfo_t * CreateNewTurnout( PATHPTR_T paths, EPINX_T endPtCnt, trkEndPt_t * endPts, + DIST_T * radii, wBool_t updateList ) { turnoutInfo_t * to; @@ -126,7 +134,14 @@ EXPORT turnoutInfo_t * CreateNewTurnout( changes = CHANGE_PARAMS; } to->segCnt = segCnt; - to->segs = (trkSeg_p)memdup( segData, (sizeof *segData) * segCnt ); + trkSeg_p seg_p; + to->segs = (trkSeg_p)memdup( segData, (sizeof (*segData) * segCnt )); + seg_p = to->segs; + for (int i=0;i<segCnt;i++) { + seg_p[i].bezSegs.ptr = NULL; + seg_p[i].bezSegs.cnt = 0; + seg_p[i].bezSegs.max = 0; + } CopyPoly(to->segs,segCnt); FixUpBezierSegs(to->segs,to->segCnt); GetSegBounds( zero, 0.0, segCnt, to->segs, &to->orig, &to->size ); @@ -137,7 +152,7 @@ EXPORT turnoutInfo_t * CreateNewTurnout( to->paths = (PATHPTR_T)memdup( paths, (sizeof *to->paths) * to->pathLen ); to->paramFileIndex = curParamFileIndex; if (curParamFileIndex == PARAM_CUSTOM) - to->contentsLabel = "Custom Turnouts"; + to->contentsLabel = MyStrdup("Custom Turnouts"); else to->contentsLabel = curSubContents; #ifdef TURNOUTCMD @@ -150,11 +165,137 @@ EXPORT turnoutInfo_t * CreateNewTurnout( to->barScale = curBarScale>0?curBarScale:-1; to->special = TOnormal; + if (radii) { + to->special = TOcurved; + DYNARR_SET(DIST_T,to->u.curved.radii,to->endCnt); + for (int i=0;i<to->endCnt;i++) { + DYNARR_N(DIST_T,to->u.curved.radii,i) = radii[i]; + } + } if (updateList && changes) DoChangeNotification( changes ); return to; } +/** + * Delete a turnout parameter from the list and free the related memory + * + * \param [IN] to turnout definition to be deleted + */ + +BOOL_T +DeleteTurnout(void *toInfo) +{ + turnoutInfo_t * to = (turnoutInfo_t *)toInfo; + MyFree(to->title); + MyFree(to->segs); + MyFree(to->endPt); + MyFree(to->paths); + if (to->special) { + DYNARR_FREE(DIST_T, to->u.curved.radii); + } + + MyFree(to); + return(TRUE); +} + +/** + * Delete all turnout definitions that came from a specific parameter file. + * Due to the way the definitions are loaded from file it is safe to + * assume that they form a contiguous block in the array. + * + * \param [IN] fileIndex parameter file + */ + +void +DeleteTurnoutParams(int fileIndex) +{ + int inx=0; + int startInx = -1; + int cnt = 0; + + // go to the start of the block + while (inx < turnoutInfo_da.cnt && + turnoutInfo(inx)->paramFileIndex != fileIndex) { + startInx = inx++; + } + + // delete them + for (; inx < turnoutInfo_da.cnt && + turnoutInfo(inx)->paramFileIndex == fileIndex; inx++) { + turnoutInfo_t * to = turnoutInfo(inx); + if (to->paramFileIndex == fileIndex) { + DeleteTurnout(to); + cnt++; + } + } + + // copy down the rest of the list to fill the gap + startInx++; + while (inx < turnoutInfo_da.cnt) { + turnoutInfo(startInx++) = turnoutInfo(inx++); + } + + // and reduce the actual number + turnoutInfo_da.cnt -= cnt; +} + +/** + * Check to find out to what extent the contents of the parameter file can be used with + * the current layout scale / gauge. + * + * If parameter scale == layout and parameter gauge == layout we have an exact fit. + * If parameter gauge == layout we have compatible track. + * OO scale is special cased. If the layout is in OO scale track in HO is considered + * an exact fit in spite of scale differences. + * + * \param paramFileIndex + * \param scaleIndex + * \return + */ + +enum paramFileState +GetTrackCompatibility(int paramFileIndex, SCALEINX_T scaleIndex) +{ + int i; + enum paramFileState ret = PARAMFILE_NOTUSABLE; + DIST_T gauge = GetScaleTrackGauge(scaleIndex); + + if (!IsParamValid(paramFileIndex)) { + return(PARAMFILE_UNLOADED); + } + + // loop over all parameter entries or until a exact fit is found + for (i = 0; i < turnoutInfo_da.cnt && ret < PARAMFILE_FIT; i++) { + turnoutInfo_t *to = turnoutInfo( i ); + if (to->paramFileIndex == paramFileIndex ) { + if (to->scaleInx == scaleIndex ) { + ret = PARAMFILE_FIT; + break; + } else { + if (GetScaleTrackGauge(to->scaleInx) == gauge && + ret < PARAMFILE_COMPATIBLE) { + ret = PARAMFILE_COMPATIBLE; + // handle special cases + // if layout is OO scale, HO scale track is considered exact + char *layoutScaleName = GetScaleName(scaleIndex); + char *paramScaleName = GetScaleName(to->scaleInx); + if (!strcmp(layoutScaleName, "OO") && + !strcmp(paramScaleName, "HO")) { + ret = PARAMFILE_FIT; + } + //if layout is in Japanese or British N scale, N scale is exact + if ((!strcmp(layoutScaleName, "N(UK)") || + !strcmp(layoutScaleName, "N(JP)")) && + !strcmp(paramScaleName, "N")) { + ret = PARAMFILE_FIT; + } + } + } + } + } + return(ret); +} EXPORT wIndex_t CheckPaths( @@ -162,31 +303,59 @@ EXPORT wIndex_t CheckPaths( trkSeg_p segs, PATHPTR_T paths ) { + if ((segCnt == 0) || !segs) return -1; int pc, ps; PATHPTR_T pp = 0; - int inx, inx1; + int inx; static dynArr_t segMap_da; int segInx[2], segEp[2]; int segTrkLast = -1; - trkSeg_t tempSeg; -#define segMap(N) DYNARR_N( trkSeg_p, segMap_da, N ) + // Check that each track segment is on at least one path + int suppressCheckPaths = log_suppressCheckPaths > 0 ? logTable(log_suppressCheckPaths).level : 0; + if ( suppressCheckPaths == 0 ) { + char trkSegInx = 0; + for ( int inx = 0; inx<segCnt; inx++ ) { + if ( IsSegTrack( &segs[inx] ) ) { + trkSegInx++; + PATHPTR_T cp = paths; + while ( *cp ) { + // path is: 'N' 'A' 'M' 'E' 0 1 2 0 3 4 0 0 + // skip name + for ( ; *cp; cp++ ); + cp++; + // check each path component + for ( ; cp[0] || cp[1]; cp++ ) + if ( abs(*cp) == trkSegInx ) + break; + if ( *cp ) // we broke early + break; + cp += 2;; // Skip 2nd 0 + } + if ( !*cp ) { // we looked and didn't find + InputError( "Track segment %d not on Path", FALSE, inx+1 ); + return -1;; + } + } + } + } - DYNARR_RESET( trkSeg_p, segMap_da ); +typedef struct { + trkSeg_p seg; + int indx; +} segMap_t, * segMap_p; + +#define segMap(N) DYNARR_N( segMap_t, segMap_da, N ) + segMap_p sg; + DYNARR_RESET( segMap_t, segMap_da ); + // Don't reshuffle segs, but build an offset map instead just of the tracks + // Use the map to set up the paths to point at the correct segs in the Turnout for ( inx=0; inx<segCnt; inx++ ) { if ( IsSegTrack(&segs[inx]) ) { - if ( segTrkLast != inx-1 ) { - tempSeg = segs[inx]; - segTrkLast++; - for ( inx1=inx; inx1>segTrkLast; inx1-- ) { - segs[inx1] = segs[inx1-1]; - } - segs[segTrkLast] = tempSeg; - } else { - segTrkLast = inx; - } - DYNARR_APPEND( trkSeg_p, segMap_da, 10 ); - segMap(segMap_da.cnt-1) = &segs[inx]; + DYNARR_APPEND( segMap_t, segMap_da, 10 ); + sg = &DYNARR_LAST(segMap_t,segMap_da); + sg->seg = &segs[inx]; + sg->indx = inx; } } @@ -203,8 +372,27 @@ EXPORT wIndex_t CheckPaths( return -1; } #endif - + //Rewrite the Path to point to the nth Track seg using the Map + int old_inx; + EPINX_T old_EP; + if (pp[0]!=0 && ps==0) { // First or only one + GetSegInxEP( pp[0], &old_inx, &old_EP ); + if (old_inx<0 || old_inx>= segMap_da.cnt) { + InputError( _("Turnout path[%d] %d is not a valid track segment"), + FALSE, pc, ps ); + return -1; + } + SetSegInxEP( &pp[0], DYNARR_N(segMap_t,segMap_da,old_inx).indx, old_EP); + } if (pp[0]!=0 && pp[1]!=0 ) { + //Rewrite the Path to point to the nth Track seg using the Map + GetSegInxEP( pp[1], &old_inx, &old_EP ); + if (old_inx<0 || old_inx>= segMap_da.cnt) { + InputError( _("Turnout path[%d] %d is not a valid track segment"), + FALSE, pc, ps ); + return -1; + } + SetSegInxEP( &pp[1], DYNARR_N(segMap_t,segMap_da,old_inx).indx, old_EP); /* check connectivity */ DIST_T d; GetSegInxEP( pp[0], &segInx[0], &segEp[0] ); @@ -219,12 +407,12 @@ EXPORT wIndex_t CheckPaths( FALSE, pc, pp[1] ); return -1; } - d = FindDistance( - GetSegEndPt( &segs[segInx[0]], 1-segEp[0], FALSE, NULL ), - GetSegEndPt( &segs[segInx[1]], segEp[1], FALSE, NULL ) ); + coOrd p0 = GetSegEndPt( &segs[segInx[0]], 1-segEp[0], FALSE, NULL ); + coOrd p1 = GetSegEndPt( &segs[segInx[1]], segEp[1], FALSE, NULL ); + d = FindDistance(p0,p1); if (d > MIN_TURNOUT_SEG_CONNECT_DIST) { - InputError( _("Turnout path[%d] %d-%d not connected: %0.3f"), - FALSE, pc, pp[0], pp[1], d ); + InputError( _("Turnout path[%d] %d-%d not connected: %0.3f P0(%f,%f) P1(%f,%f)"), + FALSE, pc, pp[0], pp[1], d, p0.x, p0.y, p1.x, p1.y ); return -1; } } @@ -246,27 +434,28 @@ static BOOL_T ReadTurnoutParam( return FALSE; DYNARR_RESET( trkEndPt_t, tempEndPts_da ); pathCnt = 0; - if (ReadSegs()) { - CheckPaths( tempSegs_da.cnt, &tempSegs(0), pathPtr ); - to = CreateNewTurnout( scale, title, tempSegs_da.cnt, &tempSegs(0), - pathCnt, pathPtr, tempEndPts_da.cnt, &tempEndPts(0), FALSE ); - if (to == NULL) + if ( !ReadSegs() ) + return FALSE; + CheckPaths( tempSegs_da.cnt, &tempSegs(0), pathPtr ); + to = CreateNewTurnout( scale, title, tempSegs_da.cnt, &tempSegs(0), + pathCnt, pathPtr, tempEndPts_da.cnt, &tempEndPts(0), NULL, FALSE ); + MyFree( title ); + if (to == NULL) + return FALSE; + if (tempSpecial[0] != '\0') { + if (strncmp( tempSpecial, ADJUSTABLE, strlen(ADJUSTABLE) ) == 0) { + to->special = TOadjustable; + if ( !GetArgs( tempSpecial+strlen(ADJUSTABLE), "ff", + &to->u.adjustable.minD, &to->u.adjustable.maxD ) ) + return FALSE; + } else { + InputError(_("Unknown special case"), TRUE); return FALSE; - if (tempSpecial[0] != '\0') { - if (strncmp( tempSpecial, ADJUSTABLE, strlen(ADJUSTABLE) ) == 0) { - to->special = TOadjustable; - GetArgs( tempSpecial+strlen(ADJUSTABLE), "ff", - &to->u.adjustable.minD, &to->u.adjustable.maxD ); - - } else { - InputError(_("Unknown special case"), TRUE); - } - } - if (tempCustom[0] != '\0') { - to->customInfo = MyStrdup( tempCustom ); } } - MyFree( title ); + if (tempCustom[0] != '\0') { + to->customInfo = MyStrdup( tempCustom ); + } return TRUE; } @@ -275,6 +464,7 @@ EXPORT turnoutInfo_t * TurnoutAdd( long mode, SCALEINX_T scale, wList_p list, co { wIndex_t inx; turnoutInfo_t * to, * to1 = NULL; + turnoutInx = 0; for ( inx = 0; inx < turnoutInfo_da.cnt; inx++ ) { to = turnoutInfo(inx); if ( IsParamValid(to->paramFileIndex) && @@ -284,6 +474,10 @@ EXPORT turnoutInfo_t * TurnoutAdd( long mode, SCALEINX_T scale, wList_p list, co ( epCnt <= 0 || epCnt == to->endCnt ) ) { if (to1==NULL) to1 = to; + if ( to == curTurnout ) { + to1 = to; + turnoutInx = wListGetCount( list ); + } FormatCompoundTitle( mode, to->title ); if (message[0] != '\0') { wListAddValue( list, message, NULL, to ); @@ -535,44 +729,10 @@ track_p NewHandLaidTurnout( segs[1].color = wDrawColorBlack; segs[1].u.l.pos[0] = zero; segs[1].u.l.pos[1] = p2; - trk = NewCompound( T_TURNOUT, 0, p0, a0, message, 3, &tempEndPts(0), 22, "Normal\0\1\0\0Reverse\0\2\0\0\0", 2, segs ); + trk = NewCompound( T_TURNOUT, 0, p0, a0, message, 3, &tempEndPts(0), NULL, 22, "Normal\0\1\0\0Reverse\0\2\0\0\0", 2, segs ); xx = GetTrkExtraData(trk); xx->handlaid = TRUE; -#ifdef LATER - trk = NewTrack( 0, T_TURNOUT, 3, - sizeof (*xx) + (3-1)*sizeof curTurnout->segs[0] + 1); - xx = GetTrkExtraData(trk); - xx->orig = p0; - xx->angle = a0; - xx->handlaid = TRUE; - xx->descriptionOff = zero; - xx->descriptionSize = zero; - sprintf( message, "\tHand Laid Turnout, Angle=%0.1f\t", frogA ); - xx->title = MyStrdup( message ); - xx->paths = xx->pathCurr = (PATHPTR_T)"Normal\0\1\0\0Reverse\0\2\0\0\0"; - xx->pathLen = 21; - SetTrkEndPoint( trk, 0, p0, a0 ); - SetTrkEndPoint( trk, 1, p1, a1 ); - SetTrkEndPoint( trk, 2, p2, a2 ); - xx->segCnt = 2; - Rotate( &p1, p0, -a0 ); - p1.x -= p0.x; - p1.y -= p0.y; - xx->segs[0].type = SEG_STRTRK; - xx->segs[0].color = wDrawColorBlack; - xx->segs[0].u.l.pos[0] = zero; - xx->segs[0].u.l.pos[1] = p1; - Rotate( &p2, p0, -a0 ); - p2.x -= p0.x; - p2.y -= p0.y; - xx->segs[1].type = SEG_STRTRK; - xx->segs[1].color = wDrawColorBlack; - xx->segs[1].u.l.pos[0] = zero; - xx->segs[1].u.l.pos[1] = p2; - ComputeBoundingBox( trk ); - SetDescriptionOrig( trk ); -#endif return trk; } @@ -588,7 +748,6 @@ static coOrd MapPathPos( EPINX_T ep ) { trkSeg_p segPtr; - wIndex_t inx; coOrd pos; if ( segInx < 0 ) { @@ -596,15 +755,15 @@ static coOrd MapPathPos( ep = 1-ep; } - for ( inx=0,segPtr=xx->segs; inx<xx->segCnt; inx++,segPtr++ ) { - if ( !IsSegTrack(segPtr) ) continue; - if ( --segInx > 0 ) continue; - pos = GetSegEndPt( segPtr, ep, FALSE, NULL ); - REORIGIN1( pos, xx->angle, xx->orig ); - return pos; + segPtr=xx->segs+(segInx-1); + if (!IsSegTrack(segPtr)) { + fprintf( stderr, "mapPathPos: bad segInx: %d\n", segInx ); + return zero; } - fprintf( stderr, "mapPathPos: bad segInx: %d\n", segInx ); - return zero; + pos = GetSegEndPt( segPtr, ep, FALSE, NULL ); + REORIGIN1( pos, xx->angle, xx->orig ); + return pos; + } @@ -618,21 +777,16 @@ static void DrawTurnout( long widthOptions = 0; DIST_T scale2rail; - if (GetTrkWidth(trk) == 2) - widthOptions = DTS_THICK2; - if (GetTrkWidth(trk) == 3) - widthOptions = DTS_THICK3; + widthOptions = DTS_LEFT|DTS_RIGHT; + scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale; - if ( tieDrawMode!=TIEDRAWMODE_NONE && - d!=&mapD && - (d->options&DC_TIES)!=0 && - d->scale<scale2rail/2 ) - DrawSegsO( d, trk, xx->orig, xx->angle, xx->segs, xx->segCnt, GetTrkGauge(trk), color, widthOptions|DTS_TIES ); DrawSegsO( d, trk, xx->orig, xx->angle, xx->segs, xx->segCnt, GetTrkGauge(trk), color, widthOptions | DTS_NOCENTER ); // no curve center for turnouts + + for (i=0; i<GetTrkEndPtCnt(trk); i++) { DrawEndPt( d, trk, i, color ); } - if ( ((d->funcs->options&wDrawOptTemp)==0) && + if ( (d->options & DC_SIMPLE) == 0 && (labelWhen == 2 || (labelWhen == 1 && (d->options&DC_PRINT))) && labelScale >= d->scale && ( GetTrkBits( trk ) & TB_HIDEDESC ) == 0 ) { @@ -648,11 +802,12 @@ static void DrawTurnout( } -static void ReadTurnout( +static BOOL_T ReadTurnout( char * line ) { - ReadCompound( line+8, T_TURNOUT ); - CheckPaths( tempSegs_da.cnt, &tempSegs(0), pathPtr ); + if ( !ReadCompound( line+8, T_TURNOUT ) ) + return FALSE; + return TRUE; } @@ -668,12 +823,27 @@ static ANGLE_T GetAngleTurnout( if ( ep0 && ep1 ) *ep0 = *ep1 = PickEndPoint( pos, trk ); - for ( segCnt=0; segCnt<xx->segCnt && IsSegTrack(&xx->segs[segCnt]); segCnt++ ); - pos.x -= xx->orig.x; - pos.y -= xx->orig.y; - Rotate( &pos, zero, -xx->angle ); - angle = GetAngleSegs( segCnt, xx->segs, &pos, &segInx, NULL, NULL, NULL, NULL ); - return NormalizeAngle( angle+xx->angle ); + coOrd pos0=pos; + double dd = 10000.0; + int found = -1; + //Cope with tracks not being first + for (segCnt =0; segCnt<xx->segCnt ; segCnt++ ) { + if (IsSegTrack(&xx->segs[segCnt])) { + double d = DistanceSegs( xx->orig, xx->angle, 1, &xx->segs[segCnt], &pos0, NULL ); + if (d<dd) { + dd = d; + found = segCnt; + } + } + pos0 = pos; + } + if (found>=0) { + pos.x -= xx->orig.x; + pos.y -= xx->orig.y; + Rotate( &pos, zero, -xx->angle ); + angle = GetAngleSegs( 1, &xx->segs[found], &pos, &segInx, NULL, NULL, NULL, NULL ); + return NormalizeAngle( angle+xx->angle ); + } else return 0.0; } @@ -843,6 +1013,7 @@ static void SplitTurnoutCheckEndPt( if ( dir < 0 ) segEP = 1-segEP; pos = GetSegEndPt( &segs[segInx], segEP, FALSE, NULL ); dist = FindDistance( pos, epPos ); + LOG( log_splitturnout, 1, ( " SPTChkEp P%d DIR:%d SegInx:%d SegEP:%d POS[%0.3f %0.3f] DIST:%0.3f\n", *path, dir, segInx, segEP, pos.x, pos.y, dist ) ); if ( dist>connectDistance ) return; minDist = trackGauge; @@ -851,6 +1022,7 @@ static void SplitTurnoutCheckEndPt( if ( dir < 0 ) segEP = 1-segEP; pos = splitPos; dist = DistanceSegs( zero, 0.0, 1, &segs[segInx], &pos, NULL ); + LOG( log_splitturnout, 1, ( " - P:%d SegInx:%d SegEP:%d DIST:%0.3f\n", path[0], segInx, segEP, dist ) ); if ( dist < minDist ) { minDist = dist; splitTurnoutPath = path; @@ -861,15 +1033,17 @@ static void SplitTurnoutCheckEndPt( } } - -static BOOL_T SplitTurnout( - track_p trk, - coOrd pos, - EPINX_T ep, - track_p *leftover, - EPINX_T * ep0, - EPINX_T * ep1 ) -{ +EXPORT BOOL_T SplitTurnoutCheck( + track_p trk, + coOrd pos, + EPINX_T ep, + track_p *leftover, + EPINX_T * ep0, + EPINX_T * ep1, + BOOL_T check, + coOrd * outPos, + ANGLE_T * outAngle ) + { struct extraData * xx = GetTrkExtraData( trk ); wIndex_t segInx0, segInx, segCnt; EPINX_T segEP, epCnt, ep2=0, epN; @@ -891,7 +1065,8 @@ static BOOL_T SplitTurnout( trkSeg_t newSeg; if ( (MyGetKeyState()&WKEY_SHIFT) == 0 ) { - ErrorMessage( MSG_CANT_SPLIT_TRK, _("Turnout") ); + if (!check) + ErrorMessage( MSG_CANT_SPLIT_TRK, _("Turnout") ); return FALSE; } @@ -909,6 +1084,7 @@ static BOOL_T SplitTurnout( epPos.y -= xx->orig.y; splitTurnoutPath = NULL; pp = xx->paths; + LOG( log_splitturnout, 1, ( "SplitTurnoutCheck T%d POS[%0.3f %0.3f] EP:%d CHK:%d EPPOS[%0.3f %0.3f]\n", trk?trk->index:0, pos.x, pos.y, ep, check, epPos.x, epPos.y ) ); while ( pp[0] ) { pp += strlen((char *)pp)+1; while ( pp[0] ) { @@ -924,7 +1100,8 @@ static BOOL_T SplitTurnout( } pp++; } - ErrorMessage( _("splitTurnout: can't find segment") ); + if (!check) + ErrorMessage( _("splitTurnout: can't find segment") ); return FALSE; foundSeg: @@ -932,6 +1109,7 @@ foundSeg: * 2a. Check that all other paths thru found segment are the same */ GetSegInxEP( splitTurnoutPath[0], &segInx0, &segEP ); + LOG( log_splitturnout, 1, (" Found Seg: %d SEG:%d EP:%d\n", *splitTurnoutPath, segInx0, segEP ) ); pp = xx->paths; pathCnt = 0; while ( pp[0] ) { @@ -950,7 +1128,8 @@ foundSeg: pp2 += dir; } if ( pp1[0]!='\0' || pp2[0]!='\0' ) { - ErrorMessage( MSG_SPLIT_POS_BTW_MERGEPTS ); + if (!check) + ErrorMessage( MSG_SPLIT_POS_BTW_MERGEPTS ); return FALSE; } } @@ -965,10 +1144,21 @@ foundSeg: * 2b. Check that all paths from ep pass thru segInx0 */ if ( !SplitTurnoutCheckEP( segInx0, epPos, splitTurnoutRoot, -splitTurnoutDir, xx->paths, xx->segs ) ) { - ErrorMessage( MSG_SPLIT_PATH_NOT_UNIQUE ); + if (!check) + ErrorMessage( MSG_SPLIT_PATH_NOT_UNIQUE ); return FALSE; } + if (check) { + segProcDataSplit.getAngle.pos = pos; + SegProc( SEGPROC_GETANGLE, xx->segs+segInx0, &segProcDataSplit ); + *outAngle = NormalizeAngle(segProcDataSplit.getAngle.angle+xx->angle); + *outPos = segProcDataSplit.getAngle.pos; + (*outPos).x += xx->orig.x; + (*outPos).y += xx->orig.y; + Rotate( outPos, xx->orig, xx->angle ); + return TRUE; + } /* * 3. Split the found segment. @@ -994,10 +1184,6 @@ foundSeg: epPos = GetSegEndPt( &segProcDataSplit.split.newSeg[s1], s0, FALSE, &epAngle ); epAngle += 180.0; } -#ifdef LATER - if ( segProcDataSplit.split.length[s1] <= minLength && splitTurnoutPath[1] == '\0' ) - return FALSE; -#endif /* * 4. Map the old segments to new @@ -1027,6 +1213,7 @@ foundSeg: } else { tempSegs(segIndexMap(segInx)-1) = xx->segs[segInx]; } + posCnt++; } } @@ -1084,6 +1271,7 @@ foundSeg: /* * 7. Convert trailing segments to new tracks */ + int trks = 0; path = splitTurnoutPath; if ( segProcDataSplit.split.length[s1] < minLength ) path += splitTurnoutDir; @@ -1108,6 +1296,7 @@ foundSeg: trk2 = segProcDataNewTrack.newTrack.trk; ep2 = 1-epN; } + ++trks; path += splitTurnoutDir; } @@ -1133,6 +1322,16 @@ foundSeg: return TRUE; } +static BOOL_T SplitTurnout( + track_p trk, + coOrd pos, + EPINX_T ep, + track_p *leftover, + EPINX_T * ep0, + EPINX_T * ep1 ) +{ + return SplitTurnoutCheck(trk,pos,ep,leftover,ep0,ep1,FALSE,NULL,NULL); +} static BOOL_T CheckTraverseTurnout( track_p trk, @@ -1332,11 +1531,16 @@ static STATUS_T ModifyTurnout( track_p trk, wAction_t action, coOrd pos ) { struct extraData *xx; static EPINX_T ep; + static wBool_t curved; DIST_T d; xx = GetTrkExtraData(trk); if ( xx->special == TOadjustable ) { switch ( action ) { + case C_START: + ep = -1; + curved = FALSE; + return C_CONTINUE; case C_DOWN: ep = PickUnconnectedEndPoint( pos, trk ); if (ep == -1) @@ -1347,7 +1551,7 @@ static STATUS_T ModifyTurnout( track_p trk, wAction_t action, coOrd pos ) tempSegs(0).u.l.pos[0] = GetTrkEndPos( trk, 1-ep ); tempSegs_da.cnt = 1; InfoMessage( _("Drag to change track length") ); - + return C_CONTINUE; case C_MOVE: d = FindDistance( tempSegs(0).u.l.pos[0], pos ); if ( d < xx->u.adjustable.minD ) @@ -1359,28 +1563,148 @@ static STATUS_T ModifyTurnout( track_p trk, wAction_t action, coOrd pos ) if (action == C_MOVE) InfoMessage( _("Length=%s"), FormatDistance( d ) ); return C_CONTINUE; - case C_UP: d = FindDistance( tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1] ); ChangeAdjustableEndPt( trk, ep, d ); return C_TERMINATE; - default: - ; + return C_CONTINUE; } } - return ExtendStraightFromOrig( trk, action, pos ); + + return ExtendTrackFromOrig(trk, action, pos); } static BOOL_T GetParamsTurnout( int inx, track_p trk, coOrd pos, trackParams_t * params ) { - - - params->type = curveTypeStraight; //TODO should check if last segment is actually straight - if (inx == PARAMS_CORNU || inx == PARAMS_BEZIER) { + struct extraData *xx; + xx = GetTrkExtraData(trk); + params->type = curveTypeStraight; + if (inx == PARAMS_TURNOUT) { + params->len = 0.0; + int epCnt = GetTrkEndPtCnt(trk); + if (epCnt < 3) { + double d = 10000.0; + params->centroid = zero; + //calculate path length from endPt (either to end or to other end) + segProcData_t segProcData; + trkSeg_p seg; + int segInx; + int segEP; + trkSeg_p segPtr; + PATHPTR_T path,pathCurr; + //Find starting seg on path (nearest to end Pt) + for ( path = xx->pathCurr+strlen((char*)xx->pathCurr)+1; path[0] || path[1]; path++ ) { + if ( path[0] == 0 ) + continue; + GetSegInxEP( path[0], &segInx, &segEP ); + segPtr = xx->segs+segInx; + segProcData.distance.pos1 = pos; + SegProc( SEGPROC_DISTANCE, segPtr, &segProcData ); + if ( segProcData.distance.dd < d ) { + d = segProcData.distance.dd; + pathCurr = path; + } + } + GetSegInxEP( pathCurr[0], &segInx, &segEP ); + seg = xx->segs+segInx; + d = 0.0; + //Loop through segs on path from endPt adding + while (pathCurr[0]) { + GetSegInxEP( pathCurr[0], &segInx, &segEP ); + seg = xx->segs+segInx; + SegProc(SEGPROC_LENGTH, seg, &segProcData ); + d += segProcData.length.length; + pathCurr += segEP?1:-1; + } + params->len = d; + } else { + double x, y; + x = 0; y = 0; + for (int i=0;i<epCnt; i++) { + coOrd cpos = GetTrkEndPos(trk,i); + x += cpos.x; + y += cpos.y; + } + params->centroid.x = x/epCnt; + params->centroid.y = y/epCnt; + params->len = FindDistance(params->centroid,pos)*2; //Times two because it will be halved by track.c + } + return TRUE; + } + if ((inx == PARAMS_CORNU) || (inx == PARAMS_EXTEND)) { + params->type = curveTypeStraight; params->arcR = 0.0; params->arcP = zero; + params->ep = PickEndPoint(pos, trk); + params->circleOrHelix = FALSE; + if (params->ep>=0) { + params->angle = GetTrkEndAngle(trk,params->ep); + params->track_angle = params->angle + params->ep?0:180; + } else { + params->angle = params-> track_angle = 0; + return FALSE; + } + /* Use end radii if we have them */ + //if (xx->special == TOcurved) { + // params->type = curveTypeCurve; + // params->arcR = fabs(DYNARR_N(DIST_T,xx->u.curved.radii,params->ep)); + // if (params->arcR != 0.0) + // Translate(¶ms->arcP,pos,params->track_angle-90.0,params->arcR); + // else + // params->type = curveTypeStraight; + // return TRUE; + //} + /* Find the path we are closest to */ + PATHPTR_T pathCurr = 0; + int segInx, subSegInx; + trkSeg_p segPtr; + double d = 10000; + struct extraData * xx = GetTrkExtraData(trk); + /* Get parms from that seg */ + wBool_t back,negative; + coOrd segPos = pos; + Rotate(&segPos,xx->orig,-xx->angle); + segPos.x -= xx->orig.x; + segPos.y -= xx->orig.y; + + params->track_angle = GetAngleSegs( //Find correct subSegment + xx->segCnt,xx->segs, + &segPos, &segInx, &d , &back, &subSegInx, &negative ); + if (segInx ==- 1) return FALSE; + segPtr = xx->segs+segInx; + switch (segPtr->type) { + case SEG_BEZTRK: + if ( negative != back ) params->track_angle = NormalizeAngle(params->track_angle+180); //Bezier is in reverse + segPtr = xx->segs + segInx; + trkSeg_p subSegPtr = (trkSeg_p)segPtr->bezSegs.ptr+subSegInx; + if (subSegPtr->type == SEG_CRVTRK) { + params->type = curveTypeCurve; + params->arcR = fabs(subSegPtr->u.c.radius); + params->arcP = subSegPtr->u.c.center; + params->arcP.x += xx->orig.x; + params->arcP.y += xx->orig.y; + Rotate(¶ms->arcP,xx->orig,xx->angle); + params->arcA0 = subSegPtr->u.c.a0; + params->arcA1 = subSegPtr->u.c.a1; + } + return TRUE; + break; + case SEG_CRVTRK: + params->type = curveTypeCurve; + params->arcR = fabs(segPtr->u.c.radius); + params->arcP = segPtr->u.c.center; + params->arcP.x += xx->orig.x; + params->arcP.y += xx->orig.y; + Rotate(¶ms->arcP,xx->orig,xx->angle); + params->arcA0 = segPtr->u.c.a0; + params->arcA1 = segPtr->u.c.a1; + return TRUE; + break; + } + params->arcR = 0.0; + params->arcP = zero; params->ep = PickEndPoint(pos,trk); //Nearest if (params->ep>=0) { params->angle = GetTrkEndAngle(trk,params->ep); @@ -1391,7 +1715,10 @@ static BOOL_T GetParamsTurnout( int inx, track_p trk, coOrd pos, trackParams_t * } return TRUE; } - params->ep = PickUnconnectedEndPointSilent( pos, trk ); + if ((inx == PARAMS_1ST_JOIN) || (inx == PARAMS_2ND_JOIN)) + params->ep = PickEndPoint(pos, trk); + else + params->ep = PickUnconnectedEndPointSilent( pos, trk ); if (params->ep == -1) return FALSE; params->lineOrig = GetTrkEndPos(trk,params->ep); @@ -1441,15 +1768,11 @@ static BOOL_T QueryTurnout( track_p trk, int query ) case Q_NOT_PLACE_FROGPOINTS: case Q_HAS_DESC: case Q_MODIFY_REDRAW_DONT_UNDRAW_TRACK: - case Q_CAN_EXTEND: return TRUE; case Q_MODIFY_CAN_SPLIT: - if (GetTrkEndPtCnt(trk) <= 2) { // allow splitting of simple track und buffers - return TRUE ; - } - else { - return FALSE; - } + return TRUE; + case Q_IS_TURNOUT: + return TRUE; case Q_CAN_PARALLEL: if( GetTrkEndPtCnt( trk ) == 2 && fabs( GetTrkEndAngle( trk, 0 ) - GetTrkEndAngle( trk, 1 )) == 180.0 ) return TRUE; @@ -1485,7 +1808,7 @@ static void DrawTurnoutPositionIndicator( pos0 = MapPathPos( xx, path[1], 0 ); } else if ( path[1] == 0 ) { pos1 = MapPathPos( xx, path[0], 1 ); - DrawLine( &mainD, pos0, pos1, drawTurnoutPositionWidth, color ); + DrawLine( &tempD, pos0, pos1, drawTurnoutPositionWidth, color ); } } } @@ -1505,7 +1828,6 @@ EXPORT void AdvanceTurnoutPositionIndicator( if ( GetTrkType(trk) != T_TURNOUT ) AbortProg( "nextTurnoutPosition" ); - DrawTurnoutPositionIndicator( trk, wDrawColorWhite ); path = xx->pathCurr; path += strlen((char *)path)+1; while ( path[0] || path[1] ) @@ -1514,7 +1836,6 @@ EXPORT void AdvanceTurnoutPositionIndicator( if ( *path == 0 ) path = xx->paths; xx->pathCurr = path; - DrawTurnoutPositionIndicator( trk, selectedColor ); if ( angleR == NULL || posR == NULL ) return; trvtrk.trk = trk; @@ -1548,9 +1869,11 @@ static BOOL_T MakeParallelTurnout( track_p trk, coOrd pos, DIST_T sep, + DIST_T factor, track_p * newTrk, coOrd * p0R, - coOrd * p1R ) + coOrd * p1R, + BOOL_T track) { ANGLE_T angle = GetTrkEndAngle(trk,1); struct extraData *xx, *yy; @@ -1578,42 +1901,61 @@ static BOOL_T MakeParallelTurnout( */ if( newTrk ) { - endPt = MyMalloc( GetTrkEndPtCnt( trk ) * sizeof( trkEndPt_t )); - endPt[ 0 ].pos = endPts[ 0 ]; - endPt[ 0 ].angle = GetTrkEndAngle( trk, 0 ); - endPt[ 1 ].pos = endPts[ 1 ]; - endPt[ 1 ].angle = GetTrkEndAngle( trk, 1 ); - - yy = GetTrkExtraData(trk); - - *newTrk = NewCompound( T_TURNOUT, 0, endPt[ 0 ].pos, endPt[ 0 ].angle + 90.0, yy->title, 2, endPt, yy->pathLen, (char *)yy->paths, yy->segCnt, yy->segs ); - xx = GetTrkExtraData(*newTrk); - xx->customInfo = yy->customInfo; - - /* if (connection((int)curTurnoutEp).trk) { - CopyAttributes( connection((int)curTurnoutEp).trk, newTrk ); - SetTrkScale( newTrk, curScaleInx ); - } */ - xx->special = yy->special; - xx->u = yy->u; - - SetDescriptionOrig( *newTrk ); - xx->descriptionOff = zero; - xx->descriptionSize = zero; - - SetTrkElev(*newTrk, GetTrkElevMode(trk), GetTrkElev(trk)); - GetTrkEndElev( trk, 0, &option, &d ); - SetTrkEndElev( *newTrk, 0, option, d, NULL ); - GetTrkEndElev( trk, 1, &option, &d ); - SetTrkEndElev( *newTrk, 1, option, d, NULL ); - - MyFree( endPt ); + if (track) { + endPt = MyMalloc( GetTrkEndPtCnt( trk ) * sizeof( trkEndPt_t )); + endPt[ 0 ].pos = endPts[ 0 ]; + endPt[ 0 ].angle = GetTrkEndAngle( trk, 0 ); + endPt[ 1 ].pos = endPts[ 1 ]; + endPt[ 1 ].angle = GetTrkEndAngle( trk, 1 ); + + yy = GetTrkExtraData(trk); + + DIST_T * radii = NULL; + if (yy->special == TOcurved) { + radii = MyMalloc(GetTrkEndPtCnt(trk) * sizeof(DIST_T)); + for (int i=0;i<GetTrkEndPtCnt( trk );i++) { + radii[i] = DYNARR_N(DIST_T,yy->u.curved.radii,i); + } + } + + *newTrk = NewCompound( T_TURNOUT, 0, endPt[ 0 ].pos, endPt[ 0 ].angle + 90.0, yy->title, 2, endPt, radii, yy->pathLen, (char *)yy->paths, yy->segCnt, yy->segs ); + xx = GetTrkExtraData(*newTrk); + xx->customInfo = yy->customInfo; + + /* if (connection((int)curTurnoutEp).trk) { + CopyAttributes( connection((int)curTurnoutEp).trk, newTrk ); + SetTrkScale( newTrk, curScaleInx ); + } */ + xx->special = yy->special; + + xx->u = yy->u; + + SetDescriptionOrig( *newTrk ); + xx->descriptionOff = zero; + xx->descriptionSize = zero; + + SetTrkElev(*newTrk, GetTrkElevMode(trk), GetTrkElev(trk)); + GetTrkEndElev( trk, 0, &option, &d ); + SetTrkEndElev( *newTrk, 0, option, d, NULL ); + GetTrkEndElev( trk, 1, &option, &d ); + SetTrkEndElev( *newTrk, 1, option, d, NULL ); + + MyFree( endPt ); + } else { + tempSegs(0).color = wDrawColorBlack; + tempSegs(0).width = 0; + tempSegs_da.cnt = 1; + tempSegs(0).type = track?SEG_STRTRK:SEG_STRLIN; + tempSegs(0).u.l.pos[0] = endPts[ 0 ]; + tempSegs(0).u.l.pos[1] = endPts[ 1 ]; + *newTrk = MakeDrawFromSeg( zero, 0.0, &tempSegs(0) ); + } } else { /* draw some temporary track while command is in process */ tempSegs(0).color = wDrawColorBlack; tempSegs(0).width = 0; tempSegs_da.cnt = 1; - tempSegs(0).type = SEG_STRTRK; + tempSegs(0).type = track?SEG_STRTRK:SEG_STRLIN; tempSegs(0).u.l.pos[0] = endPts[ 0 ]; tempSegs(0).u.l.pos[1] = endPts[ 1 ]; } @@ -1625,8 +1967,26 @@ static BOOL_T MakeParallelTurnout( return TRUE; } +static wBool_t CompareTurnout( track_cp trk1, track_cp trk2 ) +{ + struct extraData *xx1 = GetTrkExtraData( trk1 ); + struct extraData *xx2 = GetTrkExtraData( trk2 ); + char * cp = message + strlen(message); + REGRESS_CHECK_POS( "Orig", xx1, xx2, orig ) + REGRESS_CHECK_ANGLE( "Angle", xx1, xx2, angle ) + REGRESS_CHECK_INT( "Handlaid", xx1, xx2, handlaid ) + REGRESS_CHECK_INT( "Flipped", xx1, xx2, flipped ) + REGRESS_CHECK_INT( "Ungrouped", xx1, xx2, ungrouped ) + REGRESS_CHECK_INT( "Split", xx1, xx2, split ) + /* desc orig is not stable + REGRESS_CHECK_POS( "DescOrig", xx1, xx2, descriptionOrig ) */ + REGRESS_CHECK_POS( "DescOff", xx1, xx2, descriptionOff ) + REGRESS_CHECK_POS( "DescSize", xx1, xx2, descriptionSize ) + return CompareSegs( xx1->segs, xx1->segCnt, xx1->segs, xx1->segCnt ); +} + static trackCmd_t turnoutCmds = { - N_("TURNOUT "), + "TURNOUT ", DrawTurnout, DistanceCompound, DescribeCompound, @@ -1654,7 +2014,13 @@ static trackCmd_t turnoutCmds = { DrawTurnoutPositionIndicator, AdvanceTurnoutPositionIndicator, CheckTraverseTurnout, - MakeParallelTurnout }; + MakeParallelTurnout, + NULL, + NULL, + NULL, + NULL, + NULL, + CompareTurnout }; #ifdef TURNOUTCMD @@ -1702,7 +2068,7 @@ static void TurnoutChange( long changes ) (changes&CHANGE_PARAMS) == 0 ) ) return; lastScaleName = curScaleName; - curTurnout = NULL; + //curTurnout = NULL; curTurnoutEp = 0; wControlShow( (wControl_p)turnoutListL, FALSE ); wListClear( turnoutListL ); @@ -1710,7 +2076,7 @@ static void TurnoutChange( long changes ) if (turnoutInfo_da.cnt <= 0) return; curTurnout = TurnoutAdd( LABEL_TABBED|LABEL_MANUF|LABEL_PARTNO|LABEL_DESCR, GetLayoutCurScale(), turnoutListL, &maxTurnoutDim, -1 ); - wListSetIndex( turnoutListL, 0 ); + wListSetIndex( turnoutListL, turnoutInx ); wControlShow( (wControl_p)turnoutListL, TRUE ); if (curTurnout == NULL) { wDrawClear( turnoutD.d ); @@ -1727,7 +2093,6 @@ static void TurnoutChange( long changes ) static void RedrawTurnout() { - coOrd p, s; RescaleTurnout(); LOG( log_turnout, 2, ( "SelTurnout(%s)\n", (curTurnout?curTurnout->title:"<NULL>") ) ) @@ -1740,10 +2105,7 @@ LOG( log_turnout, 2, ( "SelTurnout(%s)\n", (curTurnout?curTurnout->title:"<NULL> DrawSegs( &turnoutD, zero, 0.0, curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlack ); curTurnoutEp = 0; - p.x = curTurnout->endPt[0].pos.x - trackGauge; - p.y = curTurnout->endPt[0].pos.y - trackGauge; - s.x = s.y = trackGauge*2.0 /*+ turnoutD.minSize*/; - DrawHilight( &turnoutD, p, s ); + HilightEndPt(); } @@ -1796,7 +2158,9 @@ static void HilightEndPt( void ) p.x = curTurnout->endPt[(int)curTurnoutEp].pos.x - trackGauge; p.y = curTurnout->endPt[(int)curTurnoutEp].pos.y - trackGauge; s.x = s.y = trackGauge*2.0 /*+ turnoutD.minSize*/; - DrawHilight( &turnoutD, p, s ); + wDrawSetTempMode( turnoutD.d, TRUE ); + DrawHilight( &turnoutD, p, s, FALSE ); + wDrawSetTempMode( turnoutD.d, FALSE ); } @@ -1806,7 +2170,6 @@ static void SelTurnoutEndPt( { if (action != C_DOWN) return; - HilightEndPt(); curTurnoutEp = TOpickEndPoint( pos, curTurnout ); HilightEndPt(); LOG( log_turnout, 3, (" selected (action=%d) %ld\n", action, curTurnoutEp ) ) @@ -1831,13 +2194,27 @@ static struct { coOrd rot0, rot1; } Dto; +static dynArr_t vector_da; +#define vector(N) DYNARR_N( vector_t, vector_da, N ) typedef struct { DIST_T off; ANGLE_T angle; EPINX_T ep; + track_p trk; } vector_t; +/* + * PlaceTurnoutTrial + * + * OUT Track - the Track that the Turnout is closest to + * IN/OUT Pos - Position of the Turnout end + * OUT Angle1 - The angle on the Track at the position + * OUT Angle2 - The angle of the Turnout (can be reversed from Angle 2 if the point is to the left) + * OUT Count - The number of connections + * OUT Max - The maximum distance between the ends and the connection points + * OUT Vector - An array of end points positions and offsets + */ static void PlaceTurnoutTrial( track_p *trkR, coOrd *posR, @@ -1856,23 +2233,30 @@ static void PlaceTurnoutTrial( ANGLE_T epAngle; int i, connCnt = 0; DIST_T d, maxD = 0; + coOrd testP = pos; - if ( (*trkR = trk = OnTrack( &pos, FALSE, TRUE )) != NULL && + if (*trkR && (GetTrkDistance(*trkR,&testP)<trackGauge)) { //Have Track, stick with it unless outside bounds + trk = *trkR; + pos = testP; + } else *trkR = trk = OnTrack( &pos, FALSE, TRUE ); + if ( (trk) != NULL && !QueryTrack(trk,Q_CANNOT_PLACE_TURNOUT) && (ep0 = PickEndPoint( pos, trk )) >= 0 && ! ( GetTrkType(trk) == T_TURNOUT && (trk1=GetTrkEndTrk(trk,ep0)) && GetTrkType(trk1) == T_TURNOUT) && - ! GetLayerFrozen(GetTrkLayer(trk)) ) { + ! GetLayerFrozen(GetTrkLayer(trk)) && + ! GetLayerModule(GetTrkLayer(trk))) { epPos = GetTrkEndPos( trk, ep0 ); d = FindDistance( pos, epPos ); if (d <= minLength) pos = epPos; - if ( GetTrkType(trk) == T_TURNOUT ) { + if ( GetTrkType(trk) == T_TURNOUT ) { //Only on the end ep0 = ep1 = PickEndPoint( pos, trk ); angle = GetTrkEndAngle( trk, ep0 ); } else { angle = GetAngleAtPoint( trk, pos, &ep0, &ep1 ); + if (ep0==1) angle = NormalizeAngle(angle+180); //Reverse if curve backwards } angle = NormalizeAngle( angle + 180.0 ); if ( NormalizeAngle( FindAngle( pos, *posR ) - angle ) < 180.0 && ep0 != ep1 ) @@ -1883,18 +2267,21 @@ static void PlaceTurnoutTrial( Rotate( &epPos, zero, angle ); pos.x -= epPos.x; pos.y -= epPos.y; - *posR = pos; + *posR = pos; //The place the Turnout end sits LOG( log_turnout, 3, ( "placeTurnout T%d (%0.3f %0.3f) A%0.3f\n", GetTrkIndex(trk), pos.x, pos.y, angle ) ) /*InfoMessage( "Turnout(%d): Angle=%0.3f", GetTrkIndex(trk), angle );*/ - + track_p ctrk = NULL; + int ccnt = 0; + DIST_T clarge = 100000; for (i=0;i<curTurnout->endCnt;i++) { posI = curTurnout->endPt[i].pos; epPos = AddCoOrd( pos, posI, angle ); epAngle = NormalizeAngle( curTurnout->endPt[i].angle + angle ); conPos = epPos; if ((trk = OnTrack(&conPos, FALSE, TRUE)) != NULL && - !GetLayerFrozen(GetTrkLayer(trk))) { + !GetLayerFrozen(GetTrkLayer(trk)) && + !GetLayerModule(GetTrkLayer(trk))) { v->off = FindDistance( epPos, conPos ); v->angle = FindAngle( epPos, conPos ); if ( GetTrkType(trk) == T_TURNOUT ) { @@ -1902,14 +2289,28 @@ LOG( log_turnout, 3, ( "placeTurnout T%d (%0.3f %0.3f) A%0.3f\n", aa = GetTrkEndAngle( trk, ep0 ); } else { aa = GetAngleAtPoint( trk, conPos, &ep0, &ep1 ); + if (ep0) //Backwards - so reverse + aa = NormalizeAngle(aa+180); } v->ep = i; - aa = NormalizeAngle( aa - epAngle + connectAngle/2.0 ); - if ( IsClose(v->off) && - ( aa<connectAngle || ( aa>180.0 && aa<180.0+connectAngle ) ) && - ! ( GetTrkType(trk) == T_TURNOUT && + aa = fabs(DifferenceBetweenAngles( aa, epAngle )); + if (QueryTrack(trk,Q_IS_CORNU) ) { //Make sure only two conns to each Cornu + int k=0; + v->trk = trk; + for (int j=0; j<i;j++) { + if (vector(j).trk == trk) k++; + } + if (k<2) { //Already two conns to this track + connCnt++; + if (v->off > maxD) + maxD = v->off; + v++; + + } + } else if (( IsClose(v->off) && (aa<connectAngle || aa>180-connectAngle) && + !( GetTrkType(trk) == T_TURNOUT && (trk1=GetTrkEndTrk(trk,ep0)) && - GetTrkType(trk1) == T_TURNOUT ) ) { + GetTrkType(trk1) == T_TURNOUT )) ) { if (v->off > maxD) maxD = v->off; connCnt++; @@ -1927,7 +2328,7 @@ LOG( log_turnout, 3, ( "placeTurnout T%d (%0.3f %0.3f) A%0.3f\n", static void PlaceTurnout( - coOrd pos ) + coOrd pos, track_p trk ) { coOrd p, pos1, pos2; track_p trk1, trk2; @@ -1936,21 +2337,24 @@ static void PlaceTurnout( DIST_T d, maxD1, maxD2, sina; vector_t *V, * maxV; - static dynArr_t vector_da; -#define vector(N) DYNARR_N( vector_t, vector_da, N ) + pos1 = Dto.place = Dto.pos = pos; +LOG( log_turnout, 1, ( "Place Turnout @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) ); if (curTurnoutEp >= (long)curTurnout->endCnt) curTurnoutEp = 0; DYNARR_SET( vector_t, vector_da, curTurnout->endCnt ); + if (trk) trk1 = trk; + else trk1 = NULL; PlaceTurnoutTrial( &trk1, &pos1, &a1, &a2, &connCnt1, &maxD1, &vector(0) ); if (connCnt1 > 0) { - Dto.pos = pos1; - Dto.trk = trk1; - Dto.angle = a1; - if ( (MyGetKeyState()&WKEY_SHIFT)==0 && connCnt1 > 1 && maxD1 >= 0.001 ) { + Dto.pos = pos1; //First track pos +LOG( log_turnout, 1, ( " trial 1 @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) ); + Dto.trk = trk1; //Track + Dto.angle = a1; //Angle of track to put down + if ( ((MyGetKeyState()&WKEY_SHIFT)==0) && (connCnt1 > 1) && (maxD1 >= 0.001) ) { //Adjust if not Shift maxV = &vector(0); - for ( i=1; i<connCnt1; i++ ) { + for ( i=1; i<connCnt1; i++ ) { //Ignore first point V = &vector(i); if ( V->off > maxV->off ) { maxV = V; @@ -1964,9 +2368,11 @@ static void PlaceTurnout( if (NormalizeAngle( maxV->angle - a3) > 180) d = -d; Translate( &pos2, pos, a2, d ); + trk2 = trk1; PlaceTurnoutTrial( &trk2, &pos2, &a2, &a, &connCnt2, &maxD2, &vector(0) ); if ( connCnt2 >= connCnt1 && maxD2 < maxD1 ) { Dto.pos = pos2; +LOG( log_turnout, 1, ( " trial 2 @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) ); Dto.trk = trk2; Dto.angle = a2; maxD1 = maxD2; @@ -1987,6 +2393,7 @@ static void PlaceTurnout( Rotate( &p, zero, Dto.angle ); Dto.pos.x = pos.x - p.x; Dto.pos.y = pos.y - p.y; +LOG( log_turnout, 1, ( " final @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) ); } } @@ -2010,6 +2417,7 @@ static void AddTurnout( void ) #define connection(N) DYNARR_N( junk_t, connection_da, N ) #define leftover(N) DYNARR_N( junk_t, leftover_da, N ) BOOL_T visible; + BOOL_T no_ties; BOOL_T noConnections; coOrd p0, p1; @@ -2020,8 +2428,6 @@ static void AddTurnout( void ) AbortProg( "addTurnout: bad cnt" ); } - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlack ); UndoStart( _("Place New Turnout"), "addTurnout" ); titleLen = strlen( curTurnout->title ); @@ -2041,13 +2447,29 @@ static void AddTurnout( void ) for (i=0;i<curTurnout->endCnt;i++) { AuditTracks( "addTurnout [%d]", i ); connection(i).trk = leftover(i).trk = NULL; + connection(i).ep = -1; + leftover(i).ep = -1; /* connect each endPt ... */ epPos = tempEndPts(i).pos; - if ((trk = OnTrack(&epPos, FALSE, TRUE)) != NULL && + if ((trk = OnTrack(&epPos, FALSE, TRUE)) != NULL && //Adjust epPos onto existing track (!GetLayerFrozen(GetTrkLayer(trk))) && + (!GetLayerModule(GetTrkLayer(trk))) && (!QueryTrack(trk,Q_CANNOT_PLACE_TURNOUT)) ) { LOG( log_turnout, 1, ( "ep[%d] on T%d @(%0.3f %0.3f)\n", i, GetTrkIndex(trk), epPos.x, epPos.y ) ) + DIST_T dd = 10000.0; + int nearest = -1; + for (int j=0;j<curTurnout->endCnt;j++) { + if (j<i && (connection(j).trk == trk)) { + nearest = -1; + goto nextEnd; //Track already chosen in use + } + if (dd>FindDistance(epPos,tempEndPts(j).pos)) { + dd = FindDistance(epPos,tempEndPts(j).pos); + nearest = j; + } + } + if (nearest != i) continue; //Not this one d = FindDistance( tempEndPts(i).pos, epPos ); if ( GetTrkType(trk) == T_TURNOUT ) { ep0 = ep1 = PickEndPoint( epPos, trk ); @@ -2055,15 +2477,14 @@ LOG( log_turnout, 1, ( "ep[%d] on T%d @(%0.3f %0.3f)\n", } else { a = GetAngleAtPoint( trk, epPos, &ep0, &ep1 ); } - aa = NormalizeAngle( a - tempEndPts(i).angle + connectAngle/2.0 ); - if ( IsClose(d) && - ( (ep0!=ep1 && aa<connectAngle) || - ( aa>180.0 && aa<180.0+connectAngle ) ) && - ! ( GetTrkType(trk) == T_TURNOUT && - (trk1=GetTrkEndTrk(trk,ep0)) && - GetTrkType(trk1) == T_TURNOUT ) ) { - /* ... if they are close to a track and line up */ - if (aa<connectAngle) { + aa = fabs(DifferenceBetweenAngles( a , tempEndPts(i).angle)); + if ((QueryTrack(trk,Q_IS_CORNU) && (d<trackGauge*2)) || + (( IsClose(d) && ( ((ep0!=ep1) && (aa<=connectAngle)) || ((aa<=connectAngle) || (aa>180-connectAngle)) ) && + ! ( GetTrkType(trk) == T_TURNOUT && + (trk1=GetTrkEndTrk(trk,ep0)) && + GetTrkType(trk1) == T_TURNOUT )) ) ) { + /* ... if they are close enough to a track and line up */ + if (aa<90) { epx = ep1; epy = ep0; } else { @@ -2071,9 +2492,9 @@ LOG( log_turnout, 1, ( "ep[%d] on T%d @(%0.3f %0.3f)\n", epy = ep1; } LOG( log_turnout, 1, ( " Attach! epx=%d\n", epx ) ) - if ( epx != epy && - (d=FindDistance(GetTrkEndPos(trk,epy), epPos)) < minLength && - (trk1=GetTrkEndTrk(trk,epy)) != NULL ) { + if ( (epx != epy) && + ((d=FindDistance(GetTrkEndPos(trk,epy), epPos)) < minLength) && + ((trk1=GetTrkEndTrk(trk,epy)) != NULL) ) { epx = GetEndPtConnectedToMe( trk1, trk ); trk = trk1; } @@ -2085,22 +2506,21 @@ LOG( log_turnout, 1, ( " Attach! epx=%d\n", epx ) ) connection(i).trk = trk; connection(i).ep = epx; if (leftover(i).trk != NULL) { - leftover(i).ep = PickEndPoint( epPos, leftover(i).trk ); + leftover(i).ep = 1-epx; /* did we already split this track? */ for (j=0;j<i;j++) { - if ( leftover(j).trk == leftover(i).trk ) { - leftover(i).trk = NULL; - break; - } - if ( leftover(j).trk == connection(i).trk ) { - /* yes. Remove the leftover piece */ + if ( connection(i).trk == leftover(j).trk ) { + /* yes. Remove the latest leftover piece */ LOG( log_turnout, 1, ( " deleting leftover T%d\n", GetTrkIndex(leftover(i).trk) ) ) - leftover(j).trk = NULL; AuditTracks( "addTurnout [%d] before delete", i ); + UndrawNewTrack( leftover(i).trk ); DeleteTrack( leftover(i).trk, FALSE ); AuditTracks( "addTurnout [%d] before delete", i ); leftover(i).trk = NULL; + leftover(i).ep = -1; + leftover(j).trk = NULL; //Forget this leftover + leftover(j).ep = -1; break; } } @@ -2108,13 +2528,15 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n", } } } +nextEnd:; } AuditTracks( "addTurnout after loop" ); /* * copy data */ - newTrk = NewCompound( T_TURNOUT, 0, Dto.pos, Dto.angle, curTurnout->title, tempEndPts_da.cnt, &tempEndPts(0), curTurnout->pathLen, (char *)curTurnout->paths, curTurnout->segCnt, curTurnout->segs ); + + newTrk = NewCompound( T_TURNOUT, 0, Dto.pos, Dto.angle, curTurnout->title, tempEndPts_da.cnt, &tempEndPts(0), NULL, curTurnout->pathLen, (char *)curTurnout->paths, curTurnout->segCnt, curTurnout->segs ); xx = GetTrkExtraData(newTrk); xx->customInfo = curTurnout->customInfo; if (connection((int)curTurnoutEp).trk) { @@ -2122,28 +2544,50 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n", SetTrkScale( newTrk, GetLayoutCurScale()); } xx->special = curTurnout->special; + if (xx->special == TOcurved) { + DYNARR_SET(DIST_T,xx->u.curved.radii,curTurnout->endCnt); + for (int i=0;i<curTurnout->endCnt;i++) { + DYNARR_N(DIST_T,xx->u.curved.radii,i) = DYNARR_N(DIST_T,curTurnout->u.curved.radii,i); + } + } xx->u = curTurnout->u; /* Make the connections */ visible = FALSE; + no_ties = FALSE; noConnections = TRUE; AuditTracks( "addTurnout T%d before connection", GetTrkIndex(newTrk) ); for (i=0;i<curTurnout->endCnt;i++) { if ( connection(i).trk != NULL ) { + if (GetTrkEndTrk(connection(i).trk,connection(i).ep)) continue; p0 = GetTrkEndPos( newTrk, i ); p1 = GetTrkEndPos( connection(i).trk, connection(i).ep ); ANGLE_T a0 = GetTrkEndAngle( newTrk, i); ANGLE_T a1 = GetTrkEndAngle( connection(i).trk, connection(i).ep ); - ANGLE_T a = NormalizeAngle(a1-a0+180); + ANGLE_T a = fabs(DifferenceBetweenAngles(a0+180,a1)); d = FindDistance( p0, p1 ); - if ( d < connectDistance ) { + if (QueryTrack(connection(i).trk,Q_IS_CORNU)) { + ANGLE_T a = DifferenceBetweenAngles(FindAngle(p0,p1),a0); + if (IsClose(d) || fabs(a)<=90.0) { + trk1 = connection(i).trk; + ep0 = connection(i).ep; + if (GetTrkEndTrk(trk1,ep0)) continue; + DrawEndPt( &mainD, trk1, ep0, wDrawColorWhite ); + trackParams_t params; + GetTrackParams( PARAMS_EXTEND, newTrk, GetTrkEndPos(newTrk,i), ¶ms); + SetCornuEndPt(trk1, ep0, GetTrkEndPos(newTrk,i), params.arcP, NormalizeAngle(params.angle+180.0), params.arcR); + ConnectTracks(newTrk,i,trk1,ep0); + DrawEndPt( &mainD, trk1, ep0, wDrawColorBlack ); + } + } else if ( d < connectDistance && (a<=connectAngle)) { noConnections = FALSE; trk1 = connection(i).trk; ep0 = connection(i).ep; DrawEndPt( &mainD, trk1, ep0, wDrawColorWhite ); ConnectTracks( newTrk, i, trk1, ep0 ); visible |= GetTrkVisible(trk1); + no_ties |= GetTrkNoTies(trk1); DrawEndPt( &mainD, trk1, ep0, wDrawColorBlack ); } } @@ -2151,10 +2595,8 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n", if (noConnections) visible = TRUE; SetTrkVisible( newTrk, visible); -#ifdef LATER - SetTrkScale( newTrk, curScaleInx ); - ComputeCompoundBoundingBox( newTrk ); -#endif + SetTrkNoTies(newTrk, no_ties); + SetTrkBridge(newTrk, FALSE); AuditTracks( "addTurnout T%d before dealing with leftovers", GetTrkIndex(newTrk) ); /* deal with the leftovers */ @@ -2165,20 +2607,59 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n", coOrd off; DIST_T maxX; track_p lt = leftover(i).trk; - EPINX_T ep, le = leftover(i).ep; - coOrd pos; + if (QueryTrack(lt,Q_IS_CORNU)) { + UndrawNewTrack(lt); + DeleteTrack(lt,TRUE); + leftover(i).trk = NULL; + continue; + } + EPINX_T ep, le = leftover(i).ep, nearest_ep =-1; + coOrd pos, nearest_pos = zero; + ANGLE_T nearest_angle = 0.0; + DIST_T nearest_radius = 0.0; + coOrd nearest_center = zero; + trackParams_t params; maxX = 0.0; + DIST_T dd = 10000.0; a = NormalizeAngle( GetTrkEndAngle(lt,le) + 180.0 ); for (ep=0; ep<curTurnout->endCnt; ep++) { FindPos( &off, NULL, GetTrkEndPos(newTrk,ep), GetTrkEndPos(lt,le), a, 100000.0 ); + pos = GetTrkEndPos(newTrk,ep); + DIST_T d = GetTrkDistance(lt, &pos); + if ((d<dd) && ( d<trackGauge/2)) { + ANGLE_T a = GetTrkEndAngle( lt, le ); + ANGLE_T a2 = fabs(DifferenceBetweenAngles(GetTrkEndAngle(newTrk,ep),a+180)); + if (GetTrkEndTrk(newTrk,ep)==NULL) { //Not if joined already + if (a2<90 && QueryTrack(lt,Q_IS_CORNU)) { //And Cornu in the right direction + GetTrackParams( PARAMS_EXTEND, newTrk, GetTrkEndPos(newTrk,ep), ¶ms); + nearest_pos = GetTrkEndPos(newTrk,ep); + nearest_angle = NormalizeAngle(params.angle+180.0); + nearest_radius = params.arcR; + nearest_center = params.arcP; + nearest_ep = ep; + } + dd = d; + } + } if (off.x > maxX) maxX = off.x; } maxX += trackGauge; pos = Dto.pos; + if (QueryTrack(lt,Q_IS_CORNU)) { + if (nearest_ep >=0) { + SetCornuEndPt(lt, le, nearest_pos, nearest_center, nearest_angle, nearest_radius); + ConnectTracks(newTrk,nearest_ep,lt,le); + } else { + UndrawNewTrack(lt); + DeleteTrack(lt,TRUE); + } + } else { AuditTracks( "addTurnout T%d[%d] before trimming L%d[%d]", GetTrkIndex(newTrk), i, GetTrkIndex(lt), le ); - TrimTrack( lt, le, maxX ); + wBool_t rc = TrimTrack( lt, le, maxX, nearest_pos, nearest_angle, nearest_radius, nearest_center ); AuditTracks( "addTurnout T%d[%d] after trimming L%d[%d]", GetTrkIndex(newTrk), i, GetTrkIndex(lt), le ); + + } } } @@ -2198,17 +2679,59 @@ LOG( log_turnout, 1, ( " deleting leftover T%d\n", static void TurnoutRotate( void * pangle ) { + if (Dto.state == 0) + return; ANGLE_T angle = (ANGLE_T)(long)pangle; - if (Dto.state == 1) - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlack ); - else - Dto.pos = cmdMenuPos; + angle /= 1000.0; + Dto.pos = cmdMenuPos; Rotate( &Dto.pos, cmdMenuPos, angle ); Dto.angle += angle; - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlack ); - Dto.state = 1; + TempRedraw(); // TurnoutRotate +} + +static dynArr_t anchors_da; +#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N) + +void static CreateArrowAnchor(coOrd pos,ANGLE_T a,DIST_T len) { + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).width = 0; + anchors(i).u.l.pos[0] = pos; + Translate(&anchors(i).u.l.pos[1],pos,NormalizeAngle(a+135),len); + anchors(i).color = wDrawColorBlue; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).width = 0; + anchors(i).u.l.pos[0] = pos; + Translate(&anchors(i).u.l.pos[1],pos,NormalizeAngle(a-135),len); + anchors(i).color = wDrawColorBlue; +} + +void static CreateRotateAnchor(coOrd pos) { + DIST_T d = tempD.scale*0.15; + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = SEG_CRVLIN; + anchors(i).width = 0.5; + anchors(i).u.c.center = pos; + anchors(i).u.c.a0 = 180.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).u.c.radius = d*2; + anchors(i).color = wDrawColorAqua; + coOrd head; //Arrows + for (int j=0;j<3;j++) { + Translate(&head,pos,j*120,d*2); + CreateArrowAnchor(head,NormalizeAngle((j*120)+90),d); + } +} + +void static CreateMoveAnchor(coOrd pos) { + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pos,0,TRUE,wDrawColorBlue); + DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); + DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pos,90,TRUE,wDrawColorBlue); } /** @@ -2230,71 +2753,71 @@ EXPORT STATUS_T CmdTurnoutAction( #ifdef NEWROTATE static ANGLE_T origAngle; #endif + switch (action & 0xFF) { case C_START: Dto.state = 0; Dto.trk = NULL; Dto.angle = 0.0; + DYNARR_RESET(trkSeg_t,anchors_da); return C_CONTINUE; + case wActionMove: + DYNARR_RESET(trkSeg_t,anchors_da); + if (Dto.state && (MyGetKeyState()&WKEY_CTRL)) { + CreateRotateAnchor(pos); + } else { + CreateMoveAnchor(pos); + } + return C_CONTINUE; + break; case C_DOWN: + DYNARR_RESET(trkSeg_t,anchors_da); if ( curTurnout == NULL ) return C_CONTINUE; - if (Dto.state == 1) { - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); - } - PlaceTurnout( pos ); + PlaceTurnout( pos, NULL ); Dto.state = 1; - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); + CreateMoveAnchor(pos); return C_CONTINUE; case C_MOVE: + DYNARR_RESET(trkSeg_t,anchors_da); if ( curTurnout == NULL ) return C_CONTINUE; if ( curTurnoutEp >= (long)curTurnout->endCnt ) curTurnoutEp = 0; - if (Dto.state == 1) { - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); - } else { - Dto.state = 1; - } - PlaceTurnout( pos ); - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); + Dto.state = 1; + PlaceTurnout( pos, Dto.trk ); + CreateMoveAnchor(pos); return C_CONTINUE; case C_UP: - InfoMessage( _("Left drag to move, right drag to rotate, press Space or Return to fix track in place or Esc to cancel") ); + DYNARR_RESET(trkSeg_t,anchors_da); + CreateMoveAnchor(pos); + InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") ); return C_CONTINUE; case C_RDOWN: + DYNARR_RESET(trkSeg_t,anchors_da); if ( curTurnout == NULL ) return C_CONTINUE; - if (Dto.state == 1) - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); - else - Dto.pos = pos; + if (Dto.state == 0) { + Dto.pos = pos; // If first, use pos, otherwise use current +LOG( log_turnout, 1, ( "RDOWN @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) ); + } Dto.rot0 = Dto.rot1 = pos; - DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack ); - Dto.state = 1; + CreateRotateAnchor(pos); + Dto.state = 2; origPos = Dto.pos; #ifdef NEWROTATE origAngle = Dto.angle; #else Rotate( &origPos, Dto.rot0, -(Dto.angle + curTurnout->endPt[(int)curTurnoutEp].angle) ); #endif - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); validAngle = FALSE; return C_CONTINUE; case C_RMOVE: + DYNARR_RESET(trkSeg_t,anchors_da); if ( curTurnout == NULL ) return C_CONTINUE; - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); - DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack ); Dto.rot1 = pos; if ( FindDistance(Dto.rot0, Dto.rot1) > 0.1*mainD.scale ) { angle = FindAngle( Dto.rot0, Dto.rot1 ); @@ -2303,6 +2826,7 @@ EXPORT STATUS_T CmdTurnoutAction( validAngle = TRUE; } Dto.pos = origPos; +LOG( log_turnout, 1, ( "RMOVE pre @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) ); #ifdef NEWROTATE angle -= baseAngle; Dto.angle = NormalizeAngle( origAngle + angle ); @@ -2311,36 +2835,33 @@ EXPORT STATUS_T CmdTurnoutAction( Dto.angle = angle - curTurnout->endPt[(int)curTurnoutEp].angle; #endif Rotate( &Dto.pos, Dto.rot0, angle ); +LOG( log_turnout, 1, ( "RMOVE post @ %0.3fx%0.3f\n", Dto.pos.x, Dto.pos.y ) ); } FormatCompoundTitle( listLabels, curTurnout->title ); InfoMessage( _("Angle = %0.3f (%s)"), PutAngle( NormalizeAngle(Dto.angle + 90.0) ), message ); - DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack ); - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); + Dto.state = 2; + CreateRotateAnchor(Dto.rot0); return C_CONTINUE; case C_RUP: + DYNARR_RESET(trkSeg_t,anchors_da); if ( curTurnout == NULL ) return C_CONTINUE; - DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack ); - InfoMessage( _("Left drag to move, right drag to rotate, press Space or Return to fix track in place or Esc to cancel") ); + Dto.state = 1; + CreateMoveAnchor(pos); + InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") ); return C_CONTINUE; case C_LCLICK: + DYNARR_RESET(trkSeg_t,anchors_da); if ( curTurnout == NULL ) return C_CONTINUE; if ( MyGetKeyState() & WKEY_SHIFT ) { - if (Dto.state == 1) - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); angle = curTurnout->endPt[(int)curTurnoutEp].angle; curTurnoutEp++; if (curTurnoutEp >= (long)curTurnout->endCnt) curTurnoutEp = 0; if (Dto.trk == NULL) Dto.angle = NormalizeAngle( Dto.angle + (angle - curTurnout->endPt[(int)curTurnoutEp].angle ) ); - PlaceTurnout( Dto.place ); - if (Dto.state == 1) - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); + PlaceTurnout( Dto.place, Dto.trk ); } else { CmdTurnoutAction( C_DOWN, pos ); CmdTurnoutAction( C_UP, pos ); @@ -2348,15 +2869,19 @@ EXPORT STATUS_T CmdTurnoutAction( return C_CONTINUE; case C_REDRAW: - if (Dto.state) + if (Dto.state) { DrawSegs( &tempD, Dto.pos, Dto.angle, curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); + } + if (anchors_da.cnt>0) { + DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); + } + if (Dto.state == 2) + DrawLine( &tempD, Dto.rot0, Dto.rot1, 0, wDrawColorBlack ); return C_CONTINUE; case C_CANCEL: - if (Dto.state) - DrawSegs( &tempD, Dto.pos, Dto.angle, - curTurnout->segs, curTurnout->segCnt, trackGauge, wDrawColorBlue ); + DYNARR_RESET(trkSeg_t,anchors_da); Dto.state = 0; Dto.trk = NULL; /*wHide( newTurn.reg.win );*/ @@ -2365,11 +2890,16 @@ EXPORT STATUS_T CmdTurnoutAction( case C_TEXT: if ((action>>8) != ' ') return C_CONTINUE; + /*no break*/ case C_OK: + DYNARR_RESET(trkSeg_t,anchors_da); AddTurnout(); + Dto.state=0; + Dto.trk = NULL; return C_TERMINATE; case C_FINISH: + DYNARR_RESET(trkSeg_t,anchors_da); if (Dto.state != 0 && Dto.trk != NULL) CmdTurnoutAction( C_OK, pos ); else @@ -2377,10 +2907,7 @@ EXPORT STATUS_T CmdTurnoutAction( return C_TERMINATE; case C_CMDMENU: - if ( turnoutPopupM == NULL ) { - turnoutPopupM = MenuRegister( "Turnout Rotate" ); - AddRotateMenu( turnoutPopupM, TurnoutRotate ); - } + menuPos = pos; wMenuPopupShow( turnoutPopupM ); return C_CONTINUE; @@ -2403,7 +2930,7 @@ static STATUS_T CmdTurnout( case C_START: if (turnoutW == NULL) { /* turnoutW = ParamCreateDialog( &turnoutPG, MakeWindowTitle("Turnout"), "Ok", , (paramActionCancelProc)Reset, TRUE, NULL, F_RESIZE|F_RECALLSIZE, TurnoutDlgUpdate ); */ - turnoutW = ParamCreateDialog( &turnoutPG, MakeWindowTitle(_("Turnout")), _("Close"), (paramActionOkProc)TurnoutOk, NULL, TRUE, NULL, F_RESIZE|F_RECALLSIZE|PD_F_ALT_CANCELLABEL, TurnoutDlgUpdate ); + turnoutW = ParamCreateDialog( &turnoutPG, MakeWindowTitle(_("Turnout")), _("Close"), (paramActionOkProc)TurnoutOk, wHide, TRUE, NULL, F_RESIZE|F_RECALLSIZE|PD_F_ALT_CANCELLABEL, TurnoutDlgUpdate ); InitNewTurn( turnoutNewM ); } /* ParamDialogOkActive( &turnoutPG, FALSE ); */ @@ -2425,12 +2952,21 @@ static STATUS_T CmdTurnout( ParamGroupRecord( &turnoutPG ); return CmdTurnoutAction( action, pos ); + case wActionMove: + return CmdTurnoutAction( action, pos ); + case C_DOWN: case C_RDOWN: ParamDialogOkActive( &turnoutPG, TRUE ); if (hideTurnoutWindow) wHide( turnoutW ); + if (((action&0xFF) == C_DOWN) && (MyGetKeyState()&WKEY_CTRL)) + return CmdTurnoutAction(C_RDOWN, pos); //Convert CTRL into Right + /*no break*/ case C_MOVE: + if (MyGetKeyState()&WKEY_CTRL) + return CmdTurnoutAction (C_RMOVE, pos); + /*no break*/ case C_RMOVE: return CmdTurnoutAction( action, pos ); @@ -2438,11 +2974,13 @@ static STATUS_T CmdTurnout( case C_RUP: if (hideTurnoutWindow) wShow( turnoutW ); - InfoMessage( _("Left drag to move, right drag to rotate, press Space or Return to fix track in place or Esc to cancel") ); + + InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") ); + if (((action&0xFF) == C_UP) && (MyGetKeyState()&WKEY_CTRL)) + return CmdTurnoutAction (C_RUP, pos); return CmdTurnoutAction( action, pos ); case C_LCLICK: - HilightEndPt(); CmdTurnoutAction( action, pos ); HilightEndPt(); return C_CONTINUE; @@ -2487,7 +3025,7 @@ static char * CmdTurnoutHotBarProc( case HB_SELECT: /* new element is selected */ CmdTurnoutAction( C_FINISH, zero ); /* finish current operation */ curTurnout = to; - DoCommandB( (void*)(intptr_t)turnoutHotBarCmdInx ); /* continue with new turnut / structure */ + DoCommandB( (void*)(intptr_t)turnoutHotBarCmdInx ); /* continue with new turnout / structure */ return NULL; case HB_LISTTITLE: FormatCompoundTitle( listLabels, to->title ); @@ -2517,7 +3055,7 @@ EXPORT void AddHotBarTurnouts( void ) to->segCnt > 0 && CompatibleScale( TRUE, to->scaleInx, GetLayoutCurScale()) ) ) continue; - AddHotBarElement( to->contentsLabel, to->size, to->orig, TRUE, to->barScale, to, CmdTurnoutHotBarProc ); + AddHotBarElement( to->contentsLabel, to->size, to->orig, TRUE, FALSE, to->barScale, to, CmdTurnoutHotBarProc ); } } @@ -2537,31 +3075,61 @@ static STATUS_T CmdTurnoutHotBar( switch (action & 0xFF) { case C_START: - TurnoutChange( CHANGE_PARAMS|CHANGE_SCALE ); + //TurnoutChange( CHANGE_PARAMS|CHANGE_SCALE ); if (curTurnout == NULL) { NoticeMessage2( 0, MSG_TURNOUT_NO_TURNOUT, _("Ok"), NULL ); return C_TERMINATE; } FormatCompoundTitle( listLabels|LABEL_DESCR, curTurnout->title ); InfoMessage( _("Place %s and draw into position"), message ); - ParamLoadControls( &turnoutPG ); - ParamGroupRecord( &turnoutPG ); + wIndex_t listIndex = FindListItemByContext( turnoutListL, curTurnout ); + if ( listIndex > 0 ) + turnoutInx = listIndex; + ParamLoadControls( &turnoutPG ); + ParamGroupRecord( &turnoutPG ); + return CmdTurnoutAction( action, pos ); + + case wActionMove: + return CmdTurnoutAction( action, pos ); + + case C_DOWN: + if (MyGetKeyState()&WKEY_CTRL) { + return CmdTurnoutAction( C_RDOWN, pos ); + } + /*no break*/ + case C_RDOWN: + return CmdTurnoutAction( action, pos ); + + case C_MOVE: + if (MyGetKeyState()&WKEY_CTRL) { + return CmdTurnoutAction( C_RMOVE, pos ); + } + /*no break*/ + case C_RMOVE: return CmdTurnoutAction( action, pos ); case C_UP: + if (MyGetKeyState()&WKEY_CTRL) { + return CmdTurnoutAction( C_RUP, pos ); + } + /*no break*/ case C_RUP: - InfoMessage( _("Left drag to move, right drag to rotate, press Space or Return to fix track in place or Esc to cancel") ); + InfoMessage( _("Left-Drag to place, Ctrl+Left-Drag or Right-Drag to Rotate, Space or Enter to accept, Esc to Cancel") ); return CmdTurnoutAction( action, pos ); + case C_REDRAW: + return CmdTurnoutAction( action, pos ); case C_TEXT: if ((action>>8) != ' ') return C_CONTINUE; + /* no break*/ case C_OK: CmdTurnoutAction( action, pos ); return C_CONTINUE; case C_CANCEL: HotBarCancel(); + /*no break*/ default: return CmdTurnoutAction( action, pos ); } @@ -2573,12 +3141,18 @@ static STATUS_T CmdTurnoutHotBar( EXPORT void InitCmdTurnout( wMenu_p menu ) { - AddMenuButton( menu, CmdTurnout, "cmdTurnout", _("Turnout"), wIconCreatePixMap(turnout_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_CMDMENU|IC_POPUP2, ACCL_TURNOUT, NULL ); - turnoutHotBarCmdInx = AddMenuButton( menu, CmdTurnoutHotBar, "cmdTurnoutHotBar", "", NULL, LEVEL0_50, IC_STICKY|IC_LCLICK|IC_CMDMENU|IC_POPUP2, 0, NULL ); + AddMenuButton( menu, CmdTurnout, "cmdTurnout", _("Predefined Track"), wIconCreatePixMap(turnout_xpm), LEVEL0_50, IC_WANT_MOVE|IC_STICKY|IC_LCLICK|IC_CMDMENU|IC_POPUP2, ACCL_TURNOUT, NULL ); + turnoutHotBarCmdInx = AddMenuButton( menu, CmdTurnoutHotBar, "cmdTurnoutHotBar", "", NULL, LEVEL0_50, IC_WANT_MOVE|IC_STICKY|IC_LCLICK|IC_CMDMENU|IC_POPUP2, 0, NULL ); RegisterChangeNotification( TurnoutChange ); ParamRegister( &turnoutPG ); log_turnout = LogFindIndex( "turnout" ); log_traverseTurnout = LogFindIndex( "traverseTurnout" ); + log_suppressCheckPaths = LogFindIndex( "suppresscheckpaths" ); + log_splitturnout = LogFindIndex( "splitturnout" ); + if ( turnoutPopupM == NULL ) { + turnoutPopupM = MenuRegister( "Turnout Rotate" ); + AddRotateMenu( turnoutPopupM, TurnoutRotate ); + } } #endif @@ -2587,7 +3161,7 @@ EXPORT void InitTrkTurnout( void ) T_TURNOUT = InitObject( &turnoutCmds ); /*InitDebug( "Turnout", &debugTurnout );*/ - AddParam( N_("TURNOUT "), ReadTurnoutParam ); + AddParam( "TURNOUT ", ReadTurnoutParam); } #ifdef TEST |