summaryrefslogtreecommitdiff
path: root/app/bin/cturnout.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2020-08-24 21:26:53 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2020-08-24 21:26:53 +0200
commitdf247efec654e512242e4f4f1b0212034f9e01fe (patch)
tree25c02e16957f3aa613af30c140fd8e8a3d52fda6 /app/bin/cturnout.c
parentd0b6a8a4ec298024f14f704f9e40a6f9d324ccf3 (diff)
parenta5ade52caa489cf0a713e0f02b764000d203140e (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.c1186
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(&params->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(&params->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(&params->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), &params);
+ 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), &params);
+ 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