summaryrefslogtreecommitdiff
path: root/app/bin/ccurve.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/ccurve.c')
-rw-r--r--app/bin/ccurve.c241
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);
}