diff options
Diffstat (limited to 'app/bin/tcurve.c')
-rw-r--r-- | app/bin/tcurve.c | 170 |
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, ¶ms->arcP, ¶ms->arcR); GetCurveAngles( ¶ms->arcA0, ¶ms->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"); } |