summaryrefslogtreecommitdiff
path: root/app/bin/tcurve.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/tcurve.c')
-rw-r--r--app/bin/tcurve.c170
1 files changed, 125 insertions, 45 deletions
diff --git a/app/bin/tcurve.c b/app/bin/tcurve.c
index 7e9fc90..7233ebf 100644
--- a/app/bin/tcurve.c
+++ b/app/bin/tcurve.c
@@ -1,8 +1,5 @@
-/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/tcurve.c,v 1.3 2009-06-15 19:29:57 m_fischer Exp $
- *
+/** \file tcurve.c
* CURVE
- *
*/
/* XTrkCad - Model Railroad CAD
@@ -23,11 +20,20 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-#include "track.h"
+#include <assert.h>
+#include <math.h>
+
#include "ccurve.h"
-#include "cstraigh.h"
#include "cjoin.h"
+#include "cstraigh.h"
+#include "cundo.h"
+#include "fileio.h"
#include "i18n.h"
+#include "layout.h"
+#include "messages.h"
+#include "param.h"
+#include "track.h"
+#include "utility.h"
static TRKTYP_T T_CURVE = -1;
@@ -43,6 +49,7 @@ struct extraData {
#define xcircle extraData->circle
static int log_curve = 0;
+static int log_curveSegs = 0;
static DIST_T GetLengthCurve( track_p );
@@ -261,26 +268,28 @@ STATUS_T CurveDescriptionMove(
coOrd pos )
{
struct extraData *xx = GetTrkExtraData(trk);
- static coOrd p0;
+ static coOrd p0,p1;
+ static BOOL_T editMode;
wDrawColor color;
ANGLE_T a, a0, a1;
DIST_T d;
+ p0 = xx->pos;
+
switch (action) {
case C_DOWN:
case C_MOVE:
case C_UP:
+ editMode = TRUE;
color = GetTrkColor( trk, &mainD );
- DrawCurveDescription( trk, &tempD, color );
if ( xx->helixTurns > 0 ) {
- if (action != C_DOWN)
- DrawLine( &tempD, xx->pos, p0, 0, wDrawColorBlack );
xx->descriptionOff.x = (pos.x-xx->pos.x);
xx->descriptionOff.y = (pos.y-xx->pos.y);
- p0 = pos;
+ p1 = pos;
if (action != C_UP)
- DrawLine( &tempD, xx->pos, p0, 0, wDrawColorBlack );
+ DrawLine( &tempD, p0, p1, 0, wDrawColorBlack );
} else {
+ p1 = pos;
GetCurveAngles( &a0, &a1, trk );
if ( a1 < 1 ) a1 = 1.0;
a = FindAngle( xx->pos, pos );
@@ -301,14 +310,18 @@ STATUS_T CurveDescriptionMove(
if ( d < 0.1 )
d = 0.1;
xx->descriptionOff.y = d * 2.0 - 1.0;
+ GetCurveAngles( &a0, &a1, trk );
+ a = a0 + (0.5 * a1);
+ PointOnCircle( &p0, xx->pos, xx->radius/2, a );
}
- DrawCurveDescription( trk, &tempD, color );
- MainRedraw();
+ if (action == C_UP) editMode = FALSE;
+ MainRedraw();
+ MapRedraw();
return action==C_UP?C_TERMINATE:C_CONTINUE;
case C_REDRAW:
- if ( xx->helixTurns > 0 ) {
- DrawLine( &tempD, xx->pos, p0, 0, wDrawColorBlack );
+ if (editMode) {
+ DrawLine( &tempD, p1, p0, 0, wDrawColorBlack );
}
break;
@@ -335,15 +348,15 @@ static struct {
ANGLE_T angle;
FLOAT_T grade;
descPivot_t pivot;
- LAYER_T layerNumber;
+ unsigned int layerNumber;
} crvData;
typedef enum { E0, Z0, E1, Z1, CE, RA, TU, SE, LN, AL, A1, A2, GR, PV, LY } crvDesc_e;
static descData_t crvDesc[] = {
-/*E0*/ { DESC_POS, N_("End Pt 1: X"), &crvData.endPt[0] },
+/*E0*/ { DESC_POS, N_("End Pt 1: X,Y"), &crvData.endPt[0] },
/*Z0*/ { DESC_DIM, N_("Z"), &crvData.elev[0] },
-/*E1*/ { DESC_POS, N_("End Pt 2: X"), &crvData.endPt[1] },
+/*E1*/ { DESC_POS, N_("End Pt 2: X,Y"), &crvData.endPt[1] },
/*Z1*/ { DESC_DIM, N_("Z"), &crvData.elev[1] },
-/*CE*/ { DESC_POS, N_("Center: X"), &crvData.center },
+/*CE*/ { DESC_POS, N_("Center: X,Y"), &crvData.center },
/*RA*/ { DESC_DIM, N_("Radius"), &crvData.radius },
/*TU*/ { DESC_LONG, N_("Turns"), &crvData.turns },
/*SE*/ { DESC_DIM, N_("Separation"), &crvData.separation },
@@ -380,6 +393,10 @@ static void UpdateCurve( track_p trk, int inx, descData_p descUpd, BOOL_T final
ErrorMessage( MSG_RADIUS_GTR_0 );
crvData.radius = xx0.radius;
crvDesc[RA].mode |= DESC_CHANGE;
+ } else if (crvData.radius > 10000) {
+ ErrorMessage( MSG_RADIUS_GTR_10000 );
+ crvData.radius = xx0.radius;
+ crvDesc[RA].mode |= DESC_CHANGE;
} else {
if ( crvData.pivot == DESC_PIVOT_FIRST || GetTrkEndTrk(trk,0) ) {
Translate( &xx0.pos, xx0.pos, a0, xx0.radius-crvData.radius );
@@ -1164,6 +1181,10 @@ static BOOL_T GetParamsCurve( int inx, track_p trk, coOrd pos, trackParams_t * p
params->type = curveTypeCurve;
GetTrkCurveCenter( trk, &params->arcP, &params->arcR);
GetCurveAngles( &params->arcA0, &params->arcA1, trk );
+ ANGLE_T angle1 = FindAngle(params->arcP,pos);
+
+ params->track_angle = NormalizeAngle(FindAngle(params->arcP,pos)+90);
+
if ( easeR > 0.0 && params->arcR < easeR ) {
ErrorMessage( MSG_RADIUS_LSS_EASE_MIN,
FormatDistance( params->arcR ), FormatDistance( easeR ) );
@@ -1184,12 +1205,20 @@ static BOOL_T GetParamsCurve( int inx, track_p trk, coOrd pos, trackParams_t * p
params->arcA1 = 360.0;
}
} else {
- if ( IsCurveCircle( trk ) )
+ params->circleOrHelix = FALSE;
+ if ( IsCurveCircle( trk ) ) {
params->ep = PickArcEndPt( params->arcP, /*Dj.inp[0].*/pos, pos );
- else
- params->ep = PickUnconnectedEndPoint( pos, trk );
+ params->angle = params->track_angle;
+ params->circleOrHelix = TRUE;
+ return TRUE;
+ } else if (inx == PARAMS_CORNU ) {
+ params->ep = PickEndPoint(pos, trk);
+ } else {
+ params->ep = PickUnconnectedEndPointSilent( pos, trk );
+ }
if (params->ep == -1)
return FALSE;
+ params->angle = GetTrkEndAngle(trk,params->ep); ;
}
return TRUE;
}
@@ -1224,11 +1253,27 @@ static BOOL_T QueryCurve( track_p trk, int query )
case Q_FLIP_ENDPTS:
case Q_ISTRACK:
case Q_HAS_DESC:
+ case Q_CORNU_CAN_MODIFY:
+ case Q_MODIFY_CAN_SPLIT:
return TRUE;
+ break;
case Q_EXCEPTION:
- return xx->radius < minTrackRadius;
+ return xx->radius < GetLayoutMinTrackRadius() - EPSILON;
+ break;
case Q_NOT_PLACE_FROGPOINTS:
return IsCurveCircle( trk );
+ break;
+ //case Q_CAN_EXTEND:
+ // if (xx->helixTurns > 0) return FALSE;
+ // return TRUE;
+ // break;
+ case Q_CANNOT_PLACE_TURNOUT:
+ return (xx->helixTurns > 0);
+ break;
+ case Q_HAS_VARIABLE_ENDPOINTS:
+ if ((xx->helixTurns >0) || xx->circle) return TRUE;
+ return FALSE;
+ break;
default:
return FALSE;
}
@@ -1337,38 +1382,61 @@ EXPORT void CurveSegProc(
case SEGPROC_TRAVERSE1:
a1 = FindAngle( segPtr->u.c.center, data->traverse1.pos );
- a1 += (segPtr->u.c.radius>0?90.0:-90.0);
- a2 = NormalizeAngle( data->traverse1.angle+a1 );
- data->traverse1.backwards = (a2 < 270 && a2 > 90 );
+ a1 = NormalizeAngle(a1+90); // ClockWise angle
+ // work out within this segment which way we are going
+ a2 = NormalizeAngle( a1 - data->traverse1.angle );
+ data->traverse1.backwards = ((a2 < 270) && (a2 > 90 ));
+ //Find angular distance from end opposite to direction of travel
a2 = FindAngle( segPtr->u.c.center, data->traverse1.pos );
- if ( data->traverse1.backwards == (segPtr->u.c.radius<0) ) {
- a2 = NormalizeAngle( a2-segPtr->u.c.a0 );
+ //A segment may be fractionally too short - limit to angles within segment!
+ int res = AngleInRange(a2,segPtr->u.c.a0,segPtr->u.c.a1);
+ if (res == 1 ) {
+LOG( log_curveSegs, 1, ("CrvSegsAngle miss A%0.3f S%0.3f E%0.3f R%d B%d \n",a2,segPtr->u.c.a0,segPtr->u.c.a1,res,data->traverse1.backwards))
+ a2 = segPtr->u.c.a0;
+ } else if (res == -1) {
+LOG( log_curveSegs, 1, ("CrvSegsAngle miss A%0.3f S%0.3f E%0.3f R%d B%d \n",a2,segPtr->u.c.a0,segPtr->u.c.a1,res,data->traverse1.backwards))
+ a2 = segPtr->u.c.a1+segPtr->u.c.a0;
+ }
+ //Fix issue of angles passing through zero -
+ if ( !data->traverse1.backwards ) {
+ a2 = NormalizeAngle(DifferenceBetweenAngles(segPtr->u.c.a0,a2));
} else {
- a2 = NormalizeAngle( segPtr->u.c.a0+segPtr->u.c.a1-a2 );
+ a2 = NormalizeAngle(DifferenceBetweenAngles(a2,segPtr->u.c.a0+segPtr->u.c.a1));
}
- data->traverse1.dist = a2/360.0*2*M_PI*fabs(segPtr->u.c.radius);
+
+ //Make sure backwards means going towards EP0
+ if (segPtr->u.c.radius<0) data->traverse1.backwards = !data->traverse1.backwards;
+ data->traverse1.dist = a2/360.0*2*M_PI*fabs(segPtr->u.c.radius); //Distance from end in direction of travel
+ data->traverse1.reverse_seg = ((segPtr->u.c.a0>=90) && (segPtr->u.c.a0<270));
+ data->traverse1.negative = (segPtr->u.c.radius < 0);
+ data->traverse1.segs_backwards = FALSE;
+ data->traverse1.BezSegInx = 0;
+LOG( log_curveSegs, 2, (" CrvSegs D=%0.3f A%0.3f B%d \n",data->traverse1.dist,data->traverse1.backwards))
break;
case SEGPROC_TRAVERSE2:
circum = 2*M_PI*segPtr->u.c.radius;
if ( circum < 0 )
circum = - circum;
- d = segPtr->u.c.a1/360.0*circum;
+ d = (segPtr->u.c.a1*circum)/360;
if ( d > data->traverse2.dist ) {
- a2 = (data->traverse2.dist)/circum*360.0;
- if ( data->traverse2.segDir == (segPtr->u.c.radius<0) ) {
- a2 = NormalizeAngle( segPtr->u.c.a0+a2 );
- a1 = a2+90;
- } else {
- a2 = NormalizeAngle( segPtr->u.c.a0+segPtr->u.c.a1-a2 );
- a1 = a2-90;
- }
- PointOnCircle( &data->traverse2.pos, segPtr->u.c.center, fabs(segPtr->u.c.radius), a2 );
+ a2 = (data->traverse2.dist*360.0)/circum;
data->traverse2.dist = 0;
- data->traverse2.angle = a1;
} else {
+ a2 = segPtr->u.c.a1;
data->traverse2.dist -= d;
}
+ if (segPtr->u.c.radius<0) data->traverse2.segDir = !data->traverse2.segDir;
+ if ( !data->traverse2.segDir ) {
+ a2 = NormalizeAngle( segPtr->u.c.a0+a2 );
+ a1 = NormalizeAngle(a2+90);
+ } else {
+ a2 = NormalizeAngle( segPtr->u.c.a0+segPtr->u.c.a1-a2 );
+ a1 = NormalizeAngle(a2-90);
+ }
+ PointOnCircle( &data->traverse2.pos, segPtr->u.c.center, fabs(segPtr->u.c.radius), a2 );
+ data->traverse2.angle = a1;
+
break;
case SEGPROC_DRAWROADBEDSIDE:
@@ -1429,8 +1497,14 @@ EXPORT void CurveSegProc(
data->split.newSeg[s1].u.c.a1 -= a2;
break;
+
case SEGPROC_GETANGLE:
- data->getAngle.angle = NormalizeAngle( FindAngle( data->getAngle.pos, segPtr->u.c.center ) + 90 );
+ data->getAngle.angle = NormalizeAngle( FindAngle( segPtr->u.c.center, data->getAngle.pos ) + 90 );
+ data->getAngle.negative_radius = segPtr->u.c.radius<0;
+ data->getAngle.radius = fabs(segPtr->u.c.radius);
+ data->getAngle.center = segPtr->u.c.center;
+ data->getAngle.backwards = segPtr->u.c.a0>=90 && segPtr->u.c.a0<270;
+ if (data->getAngle.backwards) data->getAngle.angle = NormalizeAngle(data->getAngle.angle+180);
break;
}
}
@@ -1457,13 +1531,14 @@ EXPORT void PlotCurve(
coOrd posx;
switch ( mode ) {
+ case crvCmdFromCornu:
case crvCmdFromEP1:
angle = FindAngle( pos0, pos1 );
d0 = FindDistance( pos0, pos2 )/2.0;
a0 = FindAngle( pos0, pos2 );
a1 = NormalizeAngle( a0 - angle );
LOG( log_curve, 3, ( "P1 = [%0.3f %0.3f] D=%0.3f A0=%0.3f A1=%0.3f\n", pos2.x, pos2.y, d0, a0, a1 ) )
- if (fabs(d0*sin(D2R(a1))) < (4.0/75.0)*mainD.scale) {
+ if ((fabs(d0*sin(D2R(a1))) < (4.0/75.0)*mainD.scale) & (mode == crvCmdFromEP1)) {
LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*mainD.scale ) )
curveData->pos1.x = pos0.x + d0*2.0*sin(D2R(angle));
curveData->pos1.y = pos0.y + d0*2.0*cos(D2R(angle));
@@ -1485,7 +1560,7 @@ LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*ma
else
curveData->curveRadius = d0/sin(D2R(-a1));
}
- if (curveData->curveRadius > 1000) {
+ if (curveData->curveRadius > 1000 && mode == crvCmdFromEP1) {
LOG( log_curve, 3, ( "Straight %0.3f > 1000\n", curveData->curveRadius ) )
curveData->pos1.x = pos0.x + d0*2.0*sin(D2R(angle));
curveData->pos1.y = pos0.y + d0*2.0*cos(D2R(angle));
@@ -1498,9 +1573,11 @@ LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*ma
if (a1 > 0.0) {
curveData->a0 = NormalizeAngle( a2-180 );
curveData->a1 = a1 * 2.0;
+ curveData->negative = FALSE;
} else {
curveData->a1 = (-a1) * 2.0;
curveData->a0 = NormalizeAngle( a2-180-curveData->a1 );
+ curveData->negative = TRUE;
}
curveData->type = curveTypeCurve;
}
@@ -1551,9 +1628,11 @@ LOG( log_curve, 3, ( "Straight: %0.3f < %0.3f\n", d0*sin(D2R(a1)), (4.0/75.0)*ma
if ( r > 0 ) {
curveData->a0 = a0;
curveData->a1 = NormalizeAngle(a1-a0);
+ curveData->negative = FALSE;
} else {
curveData->a0 = a1;
curveData->a1 = NormalizeAngle(a0-a1);
+ curveData->negative = TRUE;
}
curveData->type = curveTypeCurve;
break;
@@ -1584,4 +1663,5 @@ EXPORT void InitTrkCurve( void )
{
T_CURVE = InitObject( &curveCmds );
log_curve = LogFindIndex( "curve" );
+ log_curveSegs = LogFindIndex( "curveSegs");
}