diff options
Diffstat (limited to 'app/bin/ccurve.c')
-rw-r--r-- | app/bin/ccurve.c | 241 |
1 files changed, 164 insertions, 77 deletions
diff --git a/app/bin/ccurve.c b/app/bin/ccurve.c index b284669..58bb5c1 100644 --- a/app/bin/ccurve.c +++ b/app/bin/ccurve.c @@ -1,8 +1,5 @@ -/* - * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/ccurve.c,v 1.4 2008-03-06 19:35:04 m_fischer Exp $ - * +/** \file ccurve.c * CURVE - * */ /* XTrkCad - Model Railroad CAD @@ -23,12 +20,25 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "track.h" +#include <math.h> +#include <string.h> + #include "ccurve.h" -#include "cstraigh.h" + #include "cjoin.h" +#include "cstraigh.h" +#include "cundo.h" +#include "custom.h" +#include "fileio.h" #include "i18n.h" +#include "messages.h" +#include "param.h" +#include "param.h" +#include "track.h" +#include "utility.h" +#include "wlib.h" +#include "cbezier.h" /* * STATE INFO @@ -39,12 +49,15 @@ static struct { coOrd pos0; coOrd pos1; curveData_t curveData; + track_p trk; + EPINX_T ep; + BOOL_T down; } Da; static long curveMode; -static void DrawArrowHeads( +EXPORT void DrawArrowHeads( trkSeg_p sp, coOrd pos, ANGLE_T angle, @@ -89,26 +102,34 @@ EXPORT STATUS_T CreateCurve( long mode, curveMessageProc message ) { + track_p t; DIST_T d; - ANGLE_T a; - static coOrd pos0; + ANGLE_T a, angle1, angle2; + static coOrd pos0, p; int inx; switch ( action ) { case C_START: DYNARR_SET( trkSeg_t, tempSegs_da, 8 ); + Da.down = FALSE; //Not got a valid start yet switch ( curveMode ) { case crvCmdFromEP1: - InfoMessage( _("Drag from End-Point in direction of curve") ); + if (track) + message(_("Drag from End-Point in direction of curve - Shift locks to track open end-point") ); + else + message (_("Drag from End-Point in direction of curve") ); break; case crvCmdFromTangent: - InfoMessage( _("Drag from End-Point to Center") ); + if (track) + message(_("Drag from End-Point to Center - Shift locks to track open end-point") ); + else + message(_("Drag from End-Point to Center") ); break; case crvCmdFromCenter: - InfoMessage( _("Drag from Center to End-Point") ); + message(_("Drag from Center to End-Point") ); break; case crvCmdFromChord: - InfoMessage( _("Drag to other end of chord") ); + message(_("Drag from one to other end of chord") ); break; } return C_CONTINUE; @@ -118,14 +139,40 @@ EXPORT STATUS_T CreateCurve( tempSegs(inx).width = 0; } tempSegs_da.cnt = 0; - SnapPos( &pos ); + p = pos; + BOOL_T found = FALSE; + Da.trk = NULL; + if ((mode == crvCmdFromEP1 || mode == crvCmdFromTangent) && track && (MyGetKeyState() & WKEY_SHIFT) != 0) { + if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) { + EPINX_T ep = PickUnconnectedEndPointSilent(p, t); + if (ep != -1) { + Da.trk = t; + Da.ep = ep; + pos = GetTrkEndPos(t, ep); + found = TRUE; + } else { + Da.pos0=pos; + message(_("No unconnected end-point on track - Try again or release Shift and click")); + return C_CONTINUE; + } + } else { + Da.pos0=pos; + message(_("Not on a track - Try again or release Shift and click")); + return C_CONTINUE; + } + Da.down = TRUE; + } + Da.down = TRUE; + if (!found) SnapPos( &pos ); pos0 = pos; + Da.pos0 = pos; switch (mode) { case crvCmdFromEP1: tempSegs(0).type = (track?SEG_STRTRK:SEG_STRLIN); tempSegs(0).color = color; tempSegs(0).width = width; - message( _("Drag to set angle") ); + if (Da.trk) message(_("End Locked: Drag out curve start")); + else message(_("Drag along curve start") ); break; case crvCmdFromTangent: case crvCmdFromCenter: @@ -135,12 +182,14 @@ EXPORT STATUS_T CreateCurve( tempSegs(1).u.c.a0 = 0; tempSegs(1).u.c.a1 = 360; tempSegs(2).type = SEG_STRLIN; - message( mode==crvCmdFromTangent?_("Drag from End-Point to Center"):_("Drag from Center to End-Point") ); + if (Da.trk && mode==crvCmdFromTangent) message(_("End Locked: Drag out to center")); + else + message( mode==crvCmdFromTangent?_("Drag from End-Point to Center"):_("Drag from Center to End-Point") ); break; case crvCmdFromChord: tempSegs(0).type = (track?SEG_STRTRK:SEG_STRLIN); tempSegs(0).color = color; - tempSegs(0).width = width; + tempSegs(0).width = width; message( _("Drag to other end of chord") ); break; } @@ -148,16 +197,34 @@ EXPORT STATUS_T CreateCurve( return C_CONTINUE; case C_MOVE: + if (!Da.down) return C_CONTINUE; + if (Da.trk) { + angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk, Da.ep)); + angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1); + if (mode ==crvCmdFromEP1) { + if (angle2 > 90.0 && angle2 < 270.0) + Translate( &pos, pos0, angle1, -FindDistance( pos0, pos )*cos(D2R(angle2)) ); + else pos = pos0; + } else { + DIST_T dp = -FindDistance(pos0, pos)*sin(D2R(angle2)); + if (angle2 > 180.0) + Translate( &pos, pos0, angle1+90.0, dp ); + else + Translate( &pos, pos0, angle1-90.0, dp ); + } + } else SnapPos(&pos); tempSegs(0).u.l.pos[1] = pos; d = FindDistance( pos0, pos ); a = FindAngle( pos0, pos ); switch ( mode ) { case crvCmdFromEP1: - message( _("Angle=%0.3f"), PutAngle(a) ); + if (Da.trk) message( _("Start Locked: Drag out curve start - Angle=%0.3f"), PutAngle(a)); + else message( _("Drag out curve start - Angle=%0.3f"), PutAngle(a) ); tempSegs_da.cnt = 1; break; case crvCmdFromTangent: - message( _("Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + if (Da.trk) message( _("Tangent Locked: Drag out center - Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); + else message( _("Drag out center - Radius=%s Angle=%0.3f"), FormatDistance(d), PutAngle(a) ); tempSegs(1).u.c.center = pos; DrawArrowHeads( &tempSegs(2), pos0, FindAngle(pos0,pos)+90, TRUE, wDrawColorBlack ); tempSegs_da.cnt = 7; @@ -181,10 +248,30 @@ EXPORT STATUS_T CreateCurve( break; } return C_CONTINUE; - case C_UP: + if (!Da.down) return C_CONTINUE; + if (Da.trk) { + angle1 = NormalizeAngle(GetTrkEndAngle(Da.trk, Da.ep)); + angle2 = NormalizeAngle(FindAngle(pos, pos0)-angle1); + if (mode == crvCmdFromEP1) { + if (angle2 > 90.0 && angle2 < 270.0) { + Translate( &pos, pos0, angle1, -FindDistance( pos0, pos )*cos(D2R(angle2)) ); + Da.pos1 = pos; + } else { + ErrorMessage( MSG_TRK_TOO_SHORT, "Curved ", PutDim(0.0) ); + return C_TERMINATE; + } + } else { + DIST_T dp = -FindDistance(pos0, pos)*sin(D2R(angle2)); + if (angle2 > 180.0) + Translate( &pos, pos0, angle1+90.0, dp ); + else + Translate( &pos, pos0, angle1-90.0, dp ); + Da.pos1 = pos; + } + } switch (mode) { - case crvCmdFromEP1: + case crvCmdFromEP1: DrawArrowHeads( &tempSegs(1), pos, FindAngle(pos,pos0)+90, TRUE, drawColorRed ); tempSegs_da.cnt = 6; break; @@ -221,7 +308,9 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) case C_START: curveMode = (long)commandContext; Da.state = -1; + Da.pos0 = pos; tempSegs_da.cnt = 0; + STATUS_T rcode; return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); case C_TEXT: @@ -232,25 +321,29 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) case C_DOWN: if ( Da.state == -1 ) { - SnapPos( &pos ); + //SnapPos( &pos ); Da.pos0 = pos; Da.state = 0; - return CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); + rcode = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); + if (!Da.down) Da.state = -1; + return rcode; + //Da.pos0 = pos; } else { tempSegs_da.cnt = segCnt; return C_CONTINUE; } case C_MOVE: + if (Da.state<0) return C_CONTINUE; mainD.funcs->options = wDrawOptTemp; DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); if ( Da.state == 0 ) { - SnapPos( &pos ); - Da.pos1 = pos; + Da.pos1 = pos; rc = CreateCurve( action, pos, TRUE, wDrawColorBlack, 0, curveMode, InfoMessage ); } else { - SnapPos( &pos ); - PlotCurve( curveMode, Da.pos0, Da.pos1, pos, &Da.curveData, TRUE ); + // SnapPos( &pos ); + if (Da.trk) PlotCurve( curveMode, Da.pos0, Da.pos1, pos, &Da.curveData, FALSE ); + else PlotCurve( curveMode, Da.pos0, Da.pos1, pos, &Da.curveData, TRUE ); if (Da.curveData.type == curveTypeStraight) { tempSegs(0).type = SEG_STRTRK; tempSegs(0).u.l.pos[0] = Da.pos0; @@ -290,6 +383,7 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) case C_UP: + if (Da.state<0) return C_CONTINUE; mainD.funcs->options = wDrawOptTemp; DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); if (Da.state == 0) { @@ -313,6 +407,10 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) } UndoStart( _("Create Straight Track"), "newCurve - straight" ); t = NewStraightTrack( Da.pos0, Da.curveData.pos1 ); + if (Da.trk) { + EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t); + if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep); + } UndoEnd(); } else if (Da.curveData.type == curveTypeCurve) { if ((d= Da.curveData.curveRadius * Da.curveData.a1 *2.0*M_PI/360.0) <= minLength) { @@ -322,6 +420,10 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) UndoStart( _("Create Curved Track"), "newCurve - curve" ); t = NewCurvedTrack( Da.curveData.curvePos, Da.curveData.curveRadius, Da.curveData.a0, Da.curveData.a1, 0 ); + if (Da.trk) { + EPINX_T ep = PickUnconnectedEndPoint(Da.pos0, t); + if (ep != -1) ConnectTracks(Da.trk, Da.ep, t, ep); + } UndoEnd(); } else { return C_ERROR; @@ -344,6 +446,7 @@ static STATUS_T CmdCurve( wAction_t action, coOrd pos ) DrawSegs( &mainD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); mainD.funcs->options = 0; tempSegs_da.cnt = 0; + Da.trk = NULL; } Da.state = -1; return C_CONTINUE; @@ -381,12 +484,12 @@ static void ComputeHelix( paramGroup_p, int, void * ); static paramFloatRange_t r0_360 = { 0, 360 }; static paramFloatRange_t r0_1000000 = { 0, 1000000 }; static paramIntegerRange_t i1_1000000 = { 1, 1000000 }; -static paramFloatRange_t r1_1000000 = { 1, 1000000 }; +static paramFloatRange_t r1_10000 = { 1, 10000 }; static paramFloatRange_t r0_100= { 0, 100 }; static paramData_t helixPLs[] = { { PD_FLOAT, &helixElev, "elev", PDO_DIM, &r0_1000000, N_("Elevation Difference") }, - { PD_FLOAT, &helixRadius, "radius", PDO_DIM, &r1_1000000, N_("Radius") }, + { PD_FLOAT, &helixRadius, "radius", PDO_DIM, &r1_10000, N_("Radius") }, { PD_LONG, &helixTurns, "turns", 0, &i1_1000000, N_("Turns") }, { PD_FLOAT, &helixAngSep, "angSep", 0, &r0_360, N_("Angular Separation") }, { PD_FLOAT, &helixGrade, "grade", 0, &r0_100, N_("Grade") }, @@ -396,7 +499,7 @@ static paramData_t helixPLs[] = { static paramGroup_t helixPG = { "helix", PGO_PREFMISCGROUP, helixPLs, sizeof helixPLs/sizeof helixPLs[0] }; static paramData_t circleRadiusPLs[] = { - { PD_FLOAT, &circleRadius, "radius", PDO_DIM, &r1_1000000 } }; + { PD_FLOAT, &circleRadius, "radius", PDO_DIM, &r1_10000 } }; static paramGroup_t circleRadiusPG = { "circle", 0, circleRadiusPLs, sizeof circleRadiusPLs/sizeof circleRadiusPLs[0] }; @@ -604,7 +707,19 @@ static STATUS_T CmdCircleCommon( wAction_t action, coOrd pos, BOOL_T helix ) case C_UP: DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); + if (helixRadius > mapD.size.x && helixRadius > mapD.size.y) { + ErrorMessage( MSG_RADIUS_TOO_BIG ); + return C_ERROR; + } + if (circleRadius > mapD.size.x && circleRadius > mapD.size.y) { + ErrorMessage( MSG_RADIUS_TOO_BIG ); + return C_ERROR; + } if ( helix ) { + if (helixRadius > 10000) { + ErrorMessage( MSG_RADIUS_GTR_10000 ); + return C_ERROR; + } UndoStart( _("Create Helix Track"), "newHelix" ); t = NewCurvedTrack( tempSegs(0).u.c.center, helixRadius, 0.0, 0.0, helixTurns ); } else { @@ -612,6 +727,10 @@ static STATUS_T CmdCircleCommon( wAction_t action, coOrd pos, BOOL_T helix ) ErrorMessage( MSG_RADIUS_GTR_0 ); return C_ERROR; } + if ((circleRadius > 100000) || (helixRadius > 10000)) { + ErrorMessage( MSG_RADIUS_GTR_10000 ); + return C_ERROR; + } UndoStart( _("Create Circle Track"), "newCircle" ); t = NewCurvedTrack( tempSegs(0).u.c.center, circleRadius, 0.0, 0.0, 0 ); } @@ -655,56 +774,15 @@ static STATUS_T CmdHelix( wAction_t action, coOrd pos ) return CmdCircleCommon( action, pos, TRUE ); } -#ifdef LATER -static struct { - coOrd pos; - DIST_T radius; - } Dc2; - - -static STATUS_T CmdCircle2( wAction_t action, coOrd pos ) -{ - - switch (action) { - - case C_START: - InfoMessage( _("Place circle center") ); - return C_CONTINUE; - - case C_DOWN: - Dc2.pos = pos; - InfoMessage( _("Drag to set radius") ); - return C_CONTINUE; - - case C_MOVE: - dc2.radius = ConstrainR( FindDistance( Dc2.pos, pos ) ); - InfoMessage( "%s", FormatDistance(dc2.radius) ); - return C_CONTINUE; - - case C_UP: - curCommand = cmdCircle; - InfoMessage( _("Place circle") ); - return C_CONTINUE; - - default: - return C_CONTINUE; - } -} -#endif - - - -#include "bitmaps/helix.xpm" #include "bitmaps/curve1.xpm" #include "bitmaps/curve2.xpm" #include "bitmaps/curve3.xpm" #include "bitmaps/curve4.xpm" +#include "bitmaps/bezier.xpm" #include "bitmaps/circle1.xpm" #include "bitmaps/circle2.xpm" #include "bitmaps/circle3.xpm" - - EXPORT void InitCmdCurve( wMenu_p menu ) { @@ -713,6 +791,7 @@ EXPORT void InitCmdCurve( wMenu_p menu ) AddMenuButton( menu, CmdCurve, "cmdCurveTangent", _("Curve from Tangent"), wIconCreatePixMap( curve2_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE2, (void*)1 ); AddMenuButton( menu, CmdCurve, "cmdCurveCenter", _("Curve from Center"), wIconCreatePixMap( curve3_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE3, (void*)2 ); AddMenuButton( menu, CmdCurve, "cmdCurveChord", _("Curve from Chord"), wIconCreatePixMap( curve4_xpm ), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_CURVE4, (void*)3 ); + AddMenuButton( menu, CmdBezCurve, "cmdBezier", _("Bezier Curve"), wIconCreatePixMap(bezier_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_BEZIER, (void*)bezCmdCreateTrack ); ButtonGroupEnd(); ButtonGroupBegin( _("Circle Track"), "cmdCurveSetCmd", _("Circle Tracks") ); @@ -726,10 +805,18 @@ EXPORT void InitCmdCurve( wMenu_p menu ) } -EXPORT void InitCmdHelix( wMenu_p menu ) -{ - AddMenuButton( menu, CmdHelix, "cmdHelix", _("Helix"), wIconCreatePixMap(helix_xpm), LEVEL0_50, IC_STICKY|IC_POPUP2, ACCL_HELIX, NULL ); - ParamRegister( &helixPG ); - RegisterChangeNotification( ChangeHelixW ); +/** +* Append the helix command to the pulldown menu. The helix doesn't use an icon, so it is only +* available through the pulldown +* +* \param varname1 IN pulldown menu +* \return +*/ +void InitCmdHelix(wMenu_p menu) +{ + AddMenuButton(menu, CmdHelix, "cmdHelix", _("Helix"), NULL, LEVEL0_50, + IC_STICKY|IC_POPUP2, ACCL_HELIX, NULL); + ParamRegister(&helixPG); + RegisterChangeNotification(ChangeHelixW); } |