summaryrefslogtreecommitdiff
path: root/app/bin/tstraigh.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/tstraigh.c')
-rw-r--r--app/bin/tstraigh.c806
1 files changed, 806 insertions, 0 deletions
diff --git a/app/bin/tstraigh.c b/app/bin/tstraigh.c
new file mode 100644
index 0000000..0f5f273
--- /dev/null
+++ b/app/bin/tstraigh.c
@@ -0,0 +1,806 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/tstraigh.c,v 1.2 2008-01-20 23:29:15 mni77 Exp $
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "track.h"
+#include "cstraigh.h"
+#include "i18n.h"
+
+/*******************************************************************************
+ *
+ * STRAIGHT
+ *
+ */
+
+static TRKTYP_T T_STRAIGHT = -1;
+
+
+/****************************************
+ *
+ * UTILITIES
+ *
+ */
+
+
+void AdjustStraightEndPt( track_p t, EPINX_T inx, coOrd pos )
+{
+ if (GetTrkType(t) != T_STRAIGHT) {
+ AbortProg( "AdjustLIneEndPt( %d, %d ) not on STRAIGHT %d\n",
+ GetTrkIndex(t), inx, GetTrkType(t) );
+ return;
+ }
+ UndoModify( t );
+#ifdef VERBOSE
+lprintf("adjustStraightEndPt T%d[%d] p=[%0.3f %0.3f]\n",
+ GetTrkIndex(t), inx, pos.x, pos.y );
+#endif
+ SetTrkEndPoint( t, inx, pos, GetTrkEndAngle(t,inx));
+ ComputeBoundingBox( t );
+ CheckTrackLength( t );
+}
+
+/****************************************
+ *
+ * GENERIC FUNCTIONS
+ *
+ */
+
+static struct {
+ coOrd endPt[2];
+ DIST_T elev[2];
+ FLOAT_T length;
+ ANGLE_T angle;
+ FLOAT_T grade;
+ descPivot_t pivot;
+ LAYER_T layerNumber;
+ } strData;
+typedef enum { E0, Z0, E1, Z1, LN, AN, GR, PV, LY } strDesc_e;
+static descData_t strDesc[] = {
+/*E0*/ { DESC_POS, N_("End Pt 1: X"), &strData.endPt[0] },
+/*Z0*/ { DESC_DIM, N_("Z"), &strData.elev[0] },
+/*E1*/ { DESC_POS, N_("End Pt 2: X"), &strData.endPt[1] },
+/*Z1*/ { DESC_DIM, N_("Z"), &strData.elev[1] },
+/*LN*/ { DESC_DIM, N_("Length"), &strData.length },
+/*AN*/ { DESC_ANGLE, N_("Angle"), &strData.angle },
+/*GR*/ { DESC_FLOAT, N_("Grade"), &strData.grade },
+/*PV*/ { DESC_PIVOT, N_("Pivot"), &strData.pivot },
+/*LY*/ { DESC_LAYER, N_("Layer"), &strData.layerNumber },
+ { DESC_NULL } };
+
+
+
+EXPORT BOOL_T UpdateDescStraight(
+ int inx,
+ int e0,
+ int e1,
+ int ln,
+ int an,
+ descData_p desc,
+ long pivot )
+{
+ coOrd mid;
+ if ( inx == e0 || inx == e1 ) {
+ *(DIST_T*)desc[ln].valueP = FindDistance( *(coOrd*)desc[e0].valueP, *(coOrd*)desc[e1].valueP );
+ *(ANGLE_T*)desc[an].valueP = FindAngle( *(coOrd*)desc[e0].valueP, *(coOrd*)desc[e1].valueP );
+ if ( inx == e0 )
+ desc[e1].mode |= DESC_CHANGE;
+ else
+ desc[e0].mode |= DESC_CHANGE;
+ desc[ln].mode |= DESC_CHANGE;
+ desc[an].mode |= DESC_CHANGE;
+ } else if ( inx == ln || inx == an ) {
+ if ( inx == ln && *(DIST_T*)desc[ln].valueP <= minLength ) {
+ ErrorMessage( MSG_OBJECT_TOO_SHORT );
+ *(DIST_T*)desc[ln].valueP = FindDistance( *(coOrd*)desc[e0].valueP, *(coOrd*)desc[e1].valueP );
+ desc[ln].mode |= DESC_CHANGE;
+ return FALSE;
+ }
+ switch (pivot) {
+ case DESC_PIVOT_FIRST:
+ Translate( (coOrd*)desc[e1].valueP, *(coOrd*)desc[e0].valueP, *(ANGLE_T*)desc[an].valueP, *(DIST_T*)desc[ln].valueP );
+ desc[e1].mode |= DESC_CHANGE;
+ break;
+ case DESC_PIVOT_SECOND:
+ Translate( (coOrd*)desc[e0].valueP, *(coOrd*)desc[e1].valueP, *(ANGLE_T*)desc[an].valueP+180.0, *(DIST_T*)desc[ln].valueP );
+ desc[e0].mode |= DESC_CHANGE;
+ break;
+ case DESC_PIVOT_MID:
+ mid.x = (((coOrd*)desc[e0].valueP)->x+((coOrd*)desc[e1].valueP)->x)/2.0;
+ mid.y = (((coOrd*)desc[e0].valueP)->y+((coOrd*)desc[e1].valueP)->y)/2.0;
+ Translate( (coOrd*)desc[e0].valueP, mid, *(ANGLE_T*)desc[an].valueP+180.0, *(DIST_T*)desc[ln].valueP/2.0 );
+ Translate( (coOrd*)desc[e1].valueP, mid, *(ANGLE_T*)desc[an].valueP, *(DIST_T*)desc[ln].valueP/2.0 );
+ desc[e0].mode |= DESC_CHANGE;
+ desc[e1].mode |= DESC_CHANGE;
+ break;
+ default:
+ break;
+ }
+ } else {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+static void UpdateStraight( track_p trk, int inx, descData_p descUpd, BOOL_T final )
+{
+ EPINX_T ep;
+ switch ( inx ) {
+ case E0:
+ case E1:
+ case LN:
+ case AN:
+ if ( ! UpdateDescStraight( inx, E0, E1, LN, AN, strDesc, strData.pivot ) )
+ return;
+ break;
+ case Z0:
+ case Z1:
+ ep = (inx==Z0?0:1);
+ UpdateTrkEndElev( trk, ep, GetTrkEndElevUnmaskedMode(trk,ep), strData.elev[ep], NULL );
+ ComputeElev( trk, 1-ep, FALSE, &strData.elev[1-ep], NULL );
+ if ( strData.length > minLength )
+ strData.grade = fabs( (strData.elev[0]-strData.elev[1])/strData.length )*100.0;
+ else
+ strData.grade = 0.0;
+ strDesc[GR].mode |= DESC_CHANGE;
+ strDesc[inx==Z0?Z1:Z0].mode |= DESC_CHANGE;
+ /*return;*/
+ break;
+#ifdef LATER
+ update = UpdateDescStraight( 0, &strDesc[E0], &strDesc[E1], &strDesc[LN], &strDesc[AN], strData.pivot );
+ break;
+ case E1:
+ update = UpdateDescStraight( 1, &strDesc[E0], &strDesc[E1], &strDesc[LN], &strDesc[AN], strData.pivot );
+ break;
+ case E1:
+ strData.length = FindDistance( strData.endPt[0], strData.endPt[1] );
+ strData.angle = FindAngle( strData.endPt[0], strData.endPt[1] );
+ strDesc[1-inx].mode |= DESC_CHANGE;
+ strDesc[LN].mode |= DESC_CHANGE;
+ strDesc[AN].mode |= DESC_CHANGE;
+ break;
+ case LN:
+ if ( strData.length < minLength ) {
+ ErrorMessage( );
+ strData.length = FindDistance( strData.endPt[0], strData.endPt[1] );
+ strDesc[LN].mode |= DESC_CHANGE;
+ break;
+ }
+ case AN:
+ switch (strData.pivot) {
+ case DESC_PIVOT_FIRST:
+ Translate( &strData.endPt[1], strData.endPt[0], strData.angle, strData.length );
+ strDesc[E1].mode |= DESC_CHANGE;
+ break;
+ case DESC_PIVOT_SECOND:
+ Translate( &strData.endPt[0], strData.endPt[1], strData.angle+180.0, strData.length );
+ strDesc[E0].mode |= DESC_CHANGE;
+ break;
+ case DESC_PIVOT_MID:
+ mid.x = (strData.endPt[0].x+strData.endPt[1].x)/2.0;
+ mid.y = (strData.endPt[0].y+strData.endPt[1].y)/2.0;
+ Translate( &strData.endPt[0], mid, strData.angle+180.0, strData.length/2.0 );
+ Translate( &strData.endPt[1], mid, strData.angle, strData.length/2.0 );
+ strDesc[E0].mode |= DESC_CHANGE;
+ strDesc[E1].mode |= DESC_CHANGE;
+ break;
+ default:
+ break;
+ }
+ break;
+#endif
+ case LY:
+ SetTrkLayer( trk, strData.layerNumber);
+ break;
+ default:
+ return;
+ }
+ UndrawNewTrack( trk );
+ if ( GetTrkEndTrk(trk,0) == NULL )
+ SetTrkEndPoint( trk, 0, strData.endPt[0], NormalizeAngle(strData.angle+180.0) );
+ if ( GetTrkEndTrk(trk,1) == NULL )
+ SetTrkEndPoint( trk, 1, strData.endPt[1], strData.angle );
+ ComputeBoundingBox( trk );
+ DrawNewTrack( trk );
+}
+
+static void DescribeStraight( track_p trk, char * str, CSIZE_T len )
+{
+ int fix0, fix1;
+ sprintf( str, _("Straight Track(%d): Layer=%d Length=%s EP=[%0.3f,%0.3f A%0.3f] [%0.3f,%0.3f A%0.3f]"), GetTrkIndex(trk),
+ GetTrkLayer(trk)+1,
+ FormatDistance(FindDistance( GetTrkEndPos(trk,0), GetTrkEndPos(trk,1) )),
+ GetTrkEndPosXY(trk,0), GetTrkEndAngle(trk,0),
+ GetTrkEndPosXY(trk,1), GetTrkEndAngle(trk,1) );
+ fix0 = GetTrkEndTrk(trk,0)!=NULL;
+ fix1 = GetTrkEndTrk(trk,1)!=NULL;
+ strData.endPt[0] = GetTrkEndPos(trk,0);
+ strData.endPt[1] = GetTrkEndPos(trk,1);
+ ComputeElev( trk, 0, FALSE, &strData.elev[0], NULL );
+ ComputeElev( trk, 1, FALSE, &strData.elev[1], NULL );
+ strData.length = FindDistance( strData.endPt[0], strData.endPt[1] );
+ strData.layerNumber = GetTrkLayer(trk);
+ if ( strData.length > minLength )
+ strData.grade = fabs( (strData.elev[0]-strData.elev[1])/strData.length )*100.0;
+ else
+ strData.grade = 0.0;
+ strData.angle = FindAngle( strData.endPt[0], strData.endPt[1] );
+ strDesc[E0].mode =
+ strDesc[E1].mode = (fix0|fix1)?DESC_RO:0;
+ strDesc[Z0].mode = (EndPtIsDefinedElev(trk,0)?0:DESC_RO)|DESC_NOREDRAW;
+ strDesc[Z1].mode = (EndPtIsDefinedElev(trk,1)?0:DESC_RO)|DESC_NOREDRAW;
+ strDesc[GR].mode = DESC_RO;
+ strDesc[LN].mode = (fix0&fix1)?DESC_RO:0;
+ strDesc[AN].mode = (fix0|fix1)?DESC_RO:0;
+ strDesc[PV].mode = (fix0|fix1)?DESC_IGNORE:0;
+ strDesc[LY].mode = DESC_NOREDRAW;
+ strData.pivot = (fix0&fix1)?DESC_PIVOT_NONE:
+ fix0?DESC_PIVOT_FIRST:
+ fix1?DESC_PIVOT_SECOND:
+ DESC_PIVOT_MID;
+ DoDescribe( _("Straight Track"), trk, strDesc, UpdateStraight );
+}
+
+static DIST_T DistanceStraight( track_p t, coOrd * p )
+{
+ return LineDistance( p, GetTrkEndPos(t,0), GetTrkEndPos(t,1) );
+}
+
+static void DrawStraight( track_p t, drawCmd_p d, wDrawColor color )
+{
+ long widthOptions = DTS_LEFT|DTS_RIGHT|DTS_TIES;
+ if (GetTrkWidth(t) == 2)
+ widthOptions |= DTS_THICK2;
+ if (GetTrkWidth(t) == 3)
+ widthOptions |= DTS_THICK3;
+ DrawStraightTrack( d, GetTrkEndPos(t,0), GetTrkEndPos(t,1),
+ GetTrkEndAngle(t,0),
+ t, GetTrkGauge(t), color, widthOptions );
+ if ( (d->funcs->options & wDrawOptTemp) == 0 && (d->options & DC_QUICK) == 0 ) {
+ DrawEndPt( d, t, 0, color );
+ DrawEndPt( d, t, 1, color );
+ }
+}
+
+static void DeleteStraight( track_p t )
+{
+}
+
+static BOOL_T WriteStraight( track_p t, FILE * f )
+{
+ BOOL_T rc = TRUE;
+ rc &= fprintf(f, "STRAIGHT %d %d %ld 0 0 %s %d\n",
+ GetTrkIndex(t), GetTrkLayer(t), (long)GetTrkWidth(t),
+ GetTrkScaleName(t), GetTrkVisible(t) )>0;
+ rc &= WriteEndPt( f, t, 0 );
+ rc &= WriteEndPt( f, t, 1 );
+ rc &= fprintf(f, "\tEND\n" )>0;
+ return rc;
+}
+
+static void ReadStraight( char * line )
+{
+ track_p trk;
+ wIndex_t index;
+ BOOL_T visible;
+ char scale[10];
+ wIndex_t layer;
+ long options;
+
+ if ( !GetArgs( line+8, paramVersion<3?"dXZsd":"dLl00sd", &index, &layer, &options, scale, &visible ) )
+ return;
+ trk = NewTrack( index, T_STRAIGHT, 0, 0 );
+ SetTrkScale( trk, LookupScale(scale) );
+ SetTrkVisible(trk, visible);
+ SetTrkLayer(trk, layer);
+ SetTrkWidth( trk, (int)(options&3) );
+ ReadSegs();
+ SetEndPts( trk, 2 );
+ ComputeBoundingBox( trk );
+}
+
+static void MoveStraight( track_p trk, coOrd orig )
+{
+ ComputeBoundingBox( trk );
+}
+
+static void RotateStraight( track_p trk, coOrd orig, ANGLE_T angle )
+{
+ ComputeBoundingBox( trk );
+}
+
+static void RescaleStraight( track_p trk, FLOAT_T ratio )
+{
+}
+
+static int AuditStraight( track_p trk, char * msg )
+{
+ if (FindDistance( GetTrkEndPos(trk,0), GetTrkEndPos(trk,1) ) < 0.01) {
+ sprintf( msg, "T%d: short track\n", GetTrkIndex(trk) );
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+static ANGLE_T GetAngleStraight( track_p trk, coOrd pos, EPINX_T *ep0, EPINX_T *ep1 )
+{
+ if ( ep0 ) *ep0 = 0;
+ if ( ep1 ) *ep1 = 1;
+ return GetTrkEndAngle( trk, 0 );
+}
+
+
+static BOOL_T SplitStraight( track_p trk, coOrd pos, EPINX_T ep, track_p *leftover, EPINX_T * ep0, EPINX_T * ep1 )
+{
+ track_p trk1;
+
+ trk1 = NewStraightTrack( GetTrkEndPos(trk,ep), pos );
+ AdjustStraightEndPt( trk, ep, pos );
+ *leftover = trk1;
+ *ep0 = 1;
+ *ep1 = 0;
+ return TRUE;
+}
+
+
+static BOOL_T TraverseStraight( traverseTrack_p trvTrk, DIST_T * distR )
+{
+ coOrd pos[2];
+ ANGLE_T angle0, angle;
+ DIST_T dist;
+ track_p trk = trvTrk->trk;
+ EPINX_T ep;
+
+ pos[0] = GetTrkEndPos(trk,0);
+ pos[1] = GetTrkEndPos(trk,1);
+ angle0 = FindAngle( pos[0], pos[1] );
+ angle = NormalizeAngle( angle0-trvTrk->angle );
+ trvTrk->angle = angle0;
+ if ( angle < 270 && angle > 90 ) {
+ ep = 0;
+ trvTrk->angle = NormalizeAngle( trvTrk->angle + 180.0 );
+ } else {
+ ep = 1;
+ }
+ dist = FindDistance( trvTrk->pos, pos[ep] );
+ if ( dist > *distR ) {
+ Translate( &trvTrk->pos, pos[ep], NormalizeAngle(trvTrk->angle+180.0), dist-*distR );
+ *distR = 0;
+ } else {
+ trvTrk->pos = pos[ep];
+ *distR -= dist;
+ trvTrk->trk = GetTrkEndTrk( trk, ep );
+ }
+ return TRUE;
+}
+
+
+static BOOL_T EnumerateStraight( track_p trk )
+{
+ DIST_T d;
+ if (trk != NULL) {
+ d = FindDistance( GetTrkEndPos( trk, 0 ), GetTrkEndPos( trk, 1 ) );
+ ScaleLengthIncrement( GetTrkScale(trk), d );
+ }
+ return TRUE;
+}
+
+static BOOL_T TrimStraight( track_p trk, EPINX_T ep, DIST_T dist )
+{
+ DIST_T d;
+ ANGLE_T a;
+ coOrd p1, pos;
+ a = NormalizeAngle( GetTrkEndAngle(trk,ep) + 180.0 );
+ Translate( &pos, GetTrkEndPos(trk,ep), a, dist );
+ p1 = GetTrkEndPos( trk, 1-ep );
+ d = FindDistance( pos, p1 );
+ if (dist < FindDistance( GetTrkEndPos(trk,0), GetTrkEndPos(trk,1) ) &&
+ d > minLength ) {
+ UndrawNewTrack( trk );
+ AdjustStraightEndPt( trk, ep, pos );
+ DrawNewTrack( trk );
+ } else
+ DeleteTrack( trk, FALSE );
+ return TRUE;
+}
+
+
+BOOL_T ExtendStraightToJoin(
+ track_p trk0,
+ EPINX_T ep0,
+ track_p trk1,
+ EPINX_T ep1 )
+{
+ coOrd off;
+ ANGLE_T a;
+ track_p trk0x, trk1x, trk2;
+ EPINX_T ep0x=-1, ep1x=-1;
+ coOrd pos0, pos1;
+ ANGLE_T a0, a1, aa;
+
+ a0 = GetTrkEndAngle( trk0, ep0 );
+ a1 = GetTrkEndAngle( trk1, ep1 );
+ a = NormalizeAngle( a0 - a1 + 180.0 + connectAngle/2.0 );
+ pos0 = GetTrkEndPos( trk0, (GetTrkType(trk0) == T_STRAIGHT)?1-ep0:ep0 );
+ off = pos1 = GetTrkEndPos( trk1, (GetTrkType(trk1) == T_STRAIGHT)?1-ep1:ep1 );
+ Rotate( &off, pos0, -a0 );
+ off.x -= pos0.x;
+
+ if ( a >= connectAngle ||
+ !IsClose( fabs(off.x) ) ||
+ off.y-pos0.y <= connectDistance ) {
+ return FALSE;
+ }
+
+ if ( GetTrkType(trk0) != T_STRAIGHT &&
+ GetTrkType(trk1) != T_STRAIGHT ) {
+ aa = FindAngle( pos0, pos1 );
+ aa = NormalizeAngle( aa-a0+connectAngle/2.0);
+ if (aa > connectAngle)
+ return FALSE;
+ }
+ UndoStart( _("Extending Straight Track"), "ExtendStraightToJoin( T%d[%d] T%d[%d] )", GetTrkIndex(trk0), ep0, GetTrkIndex(trk1), ep1 );
+ UndoModify( trk0 );
+ UndoModify( trk1 );
+ trk2 = trk0x = trk1x = NULL;
+ if ( GetTrkType(trk0) == T_STRAIGHT ) {
+ pos0 = GetTrkEndPos( trk0, 1-ep0 );
+ trk0x = GetTrkEndTrk( trk0, 1-ep0 );
+ if (trk0x) {
+ ep0x = GetEndPtConnectedToMe( trk0x, trk0 );
+ DisconnectTracks( trk0, 1-ep0, trk0x, ep0x );
+ }
+ trk2 = trk0;
+ UndrawNewTrack( trk2 );
+ } else {
+ trk0x = trk0;
+ ep0x = ep0;
+ DrawEndPt( &mainD, trk0, ep0, wDrawColorWhite );
+ }
+ if ( GetTrkType(trk1) == T_STRAIGHT ) {
+ pos1 = GetTrkEndPos( trk1, 1-ep1 );
+ trk1x = GetTrkEndTrk( trk1, 1-ep1 );
+ if (trk1x) {
+ ep1x = GetEndPtConnectedToMe( trk1x, trk1 );
+ DisconnectTracks( trk1, 1-ep1, trk1x, ep1x );
+ }
+ if (trk2) {
+ DeleteTrack( trk1, TRUE );
+ } else {
+ trk2 = trk1;
+ UndrawNewTrack( trk2 );
+ }
+ } else {
+ trk1x = trk1;
+ ep1x = ep1;
+ DrawEndPt( &mainD, trk1, ep1, wDrawColorWhite );
+ }
+
+ if (trk2) {
+ SetTrkEndPoint( trk2, 0, pos0, NormalizeAngle(a0+180.0) );
+ SetTrkEndPoint( trk2, 1, pos1, NormalizeAngle(a1+180.0) );
+ ComputeBoundingBox( trk2 );
+ } else {
+ trk2 = NewStraightTrack( pos0, pos1 );
+ }
+ if (trk0x) {
+ ConnectTracks( trk2, 0, trk0x, ep0x );
+ }
+ if (trk1x) {
+ ConnectTracks( trk2, 1, trk1x, ep1x );
+ }
+ DrawNewTrack( trk2 );
+
+ return TRUE;
+}
+
+
+static STATUS_T ModifyStraight( track_p trk, wAction_t action, coOrd pos )
+{
+ static EPINX_T ep;
+ static BOOL_T valid;
+ DIST_T d;
+
+ switch ( action ) {
+ case C_DOWN:
+ ep = PickUnconnectedEndPoint( pos, trk );
+ if (ep == -1)
+ return C_ERROR;
+ UndrawNewTrack( trk );
+ tempSegs(0).type = SEG_STRTRK;
+ tempSegs(0).width = 0;
+ tempSegs(0).u.l.pos[0] = GetTrkEndPos( trk, 1-ep );
+ tempSegs_da.cnt = 1;
+ InfoMessage( _("Drag to change track length") );
+
+ case C_MOVE:
+ d = FindDistance( tempSegs(0).u.l.pos[0], pos );
+ valid = TRUE;
+ if ( d <= minLength ) {
+ if (action == C_MOVE)
+ ErrorMessage( MSG_TRK_TOO_SHORT, _("Straight "), PutDim(fabs(minLength-d)) );
+ valid = FALSE;
+ return C_CONTINUE;
+ }
+ Translate( &tempSegs(0).u.l.pos[1], tempSegs(0).u.l.pos[0], GetTrkEndAngle( trk, ep ), d );
+ tempSegs_da.cnt = 1;
+ if (action == C_MOVE)
+ InfoMessage( _("Straight: Length=%s Angle=%0.3f"),
+ FormatDistance( d ), PutAngle( GetTrkEndAngle( trk, ep ) ) );
+ MainRedraw();
+ return C_CONTINUE;
+
+ case C_UP:
+ if (valid)
+ AdjustStraightEndPt( trk, ep, tempSegs(0).u.l.pos[1] );
+ tempSegs_da.cnt = 0;
+ DrawNewTrack( trk );
+ MainRedraw();
+ return C_TERMINATE;
+
+ default:
+ ;
+ }
+ return C_ERROR;
+}
+
+
+static DIST_T GetLengthStraight( track_p trk )
+{
+ return FindDistance( GetTrkEndPos(trk,0), GetTrkEndPos(trk,1) );
+}
+
+
+static BOOL_T GetParamsStraight( int inx, track_p trk, coOrd pos, trackParams_t * params )
+{
+ params->type = curveTypeStraight;
+ if ( inx == PARAMS_PARALLEL ) {
+ params->ep = 0;
+ } else {
+ params->ep = PickUnconnectedEndPoint( pos, trk );
+ if (params->ep == -1)
+ return FALSE;
+ }
+ params->lineOrig = GetTrkEndPos(trk,1-params->ep);
+ params->lineEnd = GetTrkEndPos(trk,params->ep);
+ params->len = FindDistance( params->lineOrig, params->lineEnd );
+ params->angle = GetTrkEndAngle(trk,params->ep);
+ params->arcR = 0.0;
+ return TRUE;
+}
+
+
+static BOOL_T MoveEndPtStraight( track_p *trk, EPINX_T *ep, coOrd pos, DIST_T d0 )
+{
+ if ( NormalizeAngle( FindAngle( GetTrkEndPos(*trk,1-*ep), pos ) -
+ GetTrkEndAngle(*trk,*ep) + 0.5 ) > 1.0 ) {
+ ErrorMessage( MSG_MOVED_BEYOND_END_TRK );
+ return FALSE;
+ }
+ Translate( &pos, pos, GetTrkEndAngle(*trk,*ep)+180, d0 );
+ AdjustStraightEndPt( *trk, *ep, pos );
+ return TRUE;
+}
+
+
+static BOOL_T QueryStraight( track_p trk, int query )
+{
+ switch ( query ) {
+ case Q_CAN_PARALLEL:
+ case Q_CAN_MODIFYRADIUS:
+ case Q_CAN_GROUP:
+ case Q_ISTRACK:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+
+static void FlipStraight(
+ track_p trk,
+ coOrd orig,
+ ANGLE_T angle )
+{
+ ComputeBoundingBox( trk );
+}
+
+
+static BOOL_T MakeParallelStraight(
+ track_p trk,
+ coOrd pos,
+ DIST_T sep,
+ track_p * newTrkR,
+ coOrd * p0R,
+ coOrd * p1R )
+{
+ ANGLE_T angle = GetTrkEndAngle(trk,1);
+ coOrd p0, p1;
+ if ( NormalizeAngle( FindAngle( GetTrkEndPos(trk,0), pos ) - GetTrkEndAngle(trk,1) ) < 180.0 )
+ angle += 90;
+ else
+ angle -= 90;
+ Translate( &p0, GetTrkEndPos(trk,0), angle, sep );
+ Translate( &p1, GetTrkEndPos(trk,1), angle, sep );
+ if ( newTrkR ) {
+ *newTrkR = NewStraightTrack( p0, p1 );
+ } else {
+ tempSegs(0).color = wDrawColorBlack;
+ tempSegs(0).width = 0;
+ tempSegs_da.cnt = 1;
+ tempSegs(0).type = SEG_STRTRK;
+ tempSegs(0).u.l.pos[0] = p0;
+ tempSegs(0).u.l.pos[1] = p1;
+ }
+ if ( p0R ) *p0R = p0;
+ if ( p1R ) *p1R = p1;
+ return TRUE;
+}
+
+
+static trackCmd_t straightCmds = {
+ "STRAIGHT",
+ DrawStraight,
+ DistanceStraight,
+ DescribeStraight,
+ DeleteStraight,
+ WriteStraight,
+ ReadStraight,
+ MoveStraight,
+ RotateStraight,
+ RescaleStraight,
+ AuditStraight,
+ GetAngleStraight,
+ SplitStraight,
+ TraverseStraight,
+ EnumerateStraight,
+ NULL, /* redraw */
+ TrimStraight,
+ ExtendStraightToJoin,
+ ModifyStraight,
+ GetLengthStraight,
+ GetParamsStraight,
+ MoveEndPtStraight,
+ QueryStraight,
+ NULL, /* ungroup */
+ FlipStraight,
+ NULL,
+ NULL,
+ NULL,
+ MakeParallelStraight };
+
+
+EXPORT void StraightSegProc(
+ segProc_e cmd,
+ trkSeg_p segPtr,
+ segProcData_p data )
+{
+ ANGLE_T a0, a1, a2;
+ DIST_T d, d0, d1;
+ coOrd p0, p1;
+
+ switch( cmd ) {
+
+ case SEGPROC_TRAVERSE1:
+ a1 = FindAngle( segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ a2 = NormalizeAngle( data->traverse1.angle+a1 );
+ data->traverse1.backwards = (a2 < 270 && a2 > 90 );
+ data->traverse1.dist = FindDistance( segPtr->u.l.pos[data->traverse1.backwards?1:0], data->traverse1.pos );
+ break;
+
+ case SEGPROC_TRAVERSE2:
+ d = FindDistance( segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ if ( d >= data->traverse2.dist ) {
+ a1 = FindAngle( segPtr->u.l.pos[data->traverse2.segDir], segPtr->u.l.pos[1-data->traverse2.segDir] );
+ Translate( &data->traverse2.pos, segPtr->u.l.pos[data->traverse2.segDir], a1, data->traverse2.dist );
+ data->traverse2.dist = 0;
+ data->traverse2.angle = a1;
+ } else {
+ data->traverse2.dist -= d;
+ }
+ break;
+
+ case SEGPROC_DRAWROADBEDSIDE:
+ d0 = FindDistance( segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ a0 = FindAngle( segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ d1 = d0*data->drawRoadbedSide.first/32.0;
+ Translate( &p0, segPtr->u.l.pos[0], a0, d1 );
+ Translate( &p0, p0, a0+data->drawRoadbedSide.side, data->drawRoadbedSide.roadbedWidth/2.0 );
+ d1 = d0*data->drawRoadbedSide.last/32.0;
+ Translate( &p1, segPtr->u.l.pos[0], a0, d1 );
+ Translate( &p1, p1, a0+data->drawRoadbedSide.side, data->drawRoadbedSide.roadbedWidth/2.0 );
+ REORIGIN1( p0, data->drawRoadbedSide.angle, data->drawRoadbedSide.orig );
+ REORIGIN1( p1, data->drawRoadbedSide.angle, data->drawRoadbedSide.orig );
+ DrawLine( data->drawRoadbedSide.d, p0, p1, data->drawRoadbedSide.rbw, data->drawRoadbedSide.color );
+ break;
+
+ case SEGPROC_DISTANCE:
+ data->distance.dd = LineDistance( &data->distance.pos1, segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ break;
+
+ case SEGPROC_FLIP:
+ p0 = segPtr->u.l.pos[0];
+ segPtr->u.l.pos[0] = segPtr->u.l.pos[1];
+ segPtr->u.l.pos[1] = p0;
+ break;
+
+ case SEGPROC_NEWTRACK:
+ data->newTrack.trk = NewStraightTrack( segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ data->newTrack.ep[0] = 0;
+ data->newTrack.ep[1] = 1;
+ break;
+
+ case SEGPROC_LENGTH:
+ data->length.length = FindDistance( segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ break;
+
+ case SEGPROC_SPLIT:
+ d = FindDistance( segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ data->split.length[0] = FindDistance( segPtr->u.l.pos[0], data->split.pos );
+ if ( data->split.length[0] <= d ) {
+ data->split.length[1] = d-data->split.length[0];
+ } else {
+ data->split.length[0] = d;
+ data->split.length[1] = 0.0;
+ }
+ Translate( &p0, segPtr->u.l.pos[0], FindAngle( segPtr->u.l.pos[0], segPtr->u.l.pos[1] ), data->split.length[0] );
+ data->split.newSeg[0] = *segPtr;
+ data->split.newSeg[1] = *segPtr;
+ data->split.newSeg[0].u.l.pos[1] = data->split.newSeg[1].u.l.pos[0] = p0;
+ break;
+
+ case SEGPROC_GETANGLE:
+ data->getAngle.angle = FindAngle( segPtr->u.l.pos[0], segPtr->u.l.pos[1] );
+ break;
+ }
+}
+
+
+/****************************************
+ *
+ * GRAPHICS EDITING
+ *
+ */
+
+
+track_p NewStraightTrack( coOrd p0, coOrd p1 )
+{
+ track_p t;
+ ANGLE_T a;
+ t = NewTrack( 0, T_STRAIGHT, 2, 0 );
+ SetTrkScale( t, curScaleInx );
+ a = FindAngle( p1, p0 );
+ SetTrkEndPoint( t, 0, p0, a );
+ SetTrkEndPoint( t, 1, p1, NormalizeAngle( a+180.0 ) );
+ ComputeBoundingBox( t );
+ CheckTrackLength( t );
+ return t;
+}
+
+
+
+
+void InitTrkStraight( void )
+{
+ T_STRAIGHT = InitObject( &straightCmds );
+}