summaryrefslogtreecommitdiff
path: root/app/bin/ccornu.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2020-08-08 11:53:00 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2020-08-08 11:53:00 +0200
commitb623f5953691b2a0614e6f1f4def86bdbb9a4113 (patch)
tree18102bd36f7e22eb2ba2b9f880e4cb29346f4cb8 /app/bin/ccornu.c
parent359b557176b9bb2ff1aed2082641eed39c358d0d (diff)
New upstream version 5.2.0Beta2.1upstream/5.2.0Beta2.1
Diffstat (limited to 'app/bin/ccornu.c')
-rw-r--r--app/bin/ccornu.c2515
1 files changed, 2143 insertions, 372 deletions
diff --git a/app/bin/ccornu.c b/app/bin/ccornu.c
index 9bdb0d0..fd51755 100644
--- a/app/bin/ccornu.c
+++ b/app/bin/ccornu.c
@@ -1,3 +1,7 @@
+
+
+
+
/** \file ccornu.c
* Cornu Command. Draw or modify a Cornu Easement Track.
*/
@@ -71,6 +75,7 @@
#include "ccurve.h"
#include "ccornu.h"
#include "tcornu.h"
+#include "tbezier.h"
#include "cstraigh.h"
#include "drawgeom.h"
#include "cjoin.h"
@@ -83,12 +88,24 @@
#include "cundo.h"
#include "messages.h"
#include "cselect.h"
+#include "fileio.h"
+
+#include <stdint.h>
extern drawCmd_t tempD;
extern TRKTYP_T T_BEZIER;
extern TRKTYP_T T_CORNU;
-
+typedef struct {
+ coOrd end_center;
+ coOrd end_curve;
+ DIST_T mid_disp;
+ BOOL_T end_valid;
+ BOOL_T angle_selected;
+ BOOL_T radius_selected;
+ BOOL_T last_selected;
+ ANGLE_T arc_angle;
+} endHandle;
/*
* STATE INFO
@@ -101,11 +118,18 @@ enum Cornu_States { NONE,
POINT_PICKED,
TRACK_SELECTED };
+typedef enum {CORNU_MODIFY, CORNU_CREATE} cornuCmdType_e;
+
+
static struct {
enum Cornu_States state;
coOrd pos[2];
- int selectPoint;
- wDrawColor color;
+ int number_of_points;
+ int selectEndPoint;
+ int selectMidPoint;
+ int selectEndHandle;
+ int prevSelected;
+ int prevEndPoint;
DIST_T width;
track_p trk[2];
EPINX_T ep[2];
@@ -119,9 +143,9 @@ static struct {
BOOL_T extend[2];
trkSeg_t extendSeg[2];
- trkSeg_t ep1Segs[2];
+ trkSeg_t ep1Segs[11];
int ep1Segs_da_cnt;
- trkSeg_t ep2Segs[2];
+ trkSeg_t ep2Segs[11];
int ep2Segs_da_cnt;
dynArr_t crvSegs_da;
int crvSegs_da_cnt;
@@ -132,9 +156,143 @@ static struct {
BOOL_T circleorHelix[2];
DIST_T trackGauge;
+ int cmdType;
+
+ dynArr_t midSegs;
+
+ dynArr_t mid_points;
+ dynArr_t tracks;
+ BOOL_T ends[2];
+
+ endHandle endHandle[2];
+
bezctx * bezc;
+
+ cornuCmdType_e commandType;
+
} Da;
+static trkSeg_p curCornu;
+static wIndex_t cornuHotBarCmdInx;
+
+static struct {
+ trkSeg_t st;
+ trkSeg_t back;
+ trkSeg_t txt;
+ int count;
+} hotB;
+
+
+static char * CmdCornuHotBarProc(
+ hotBarProc_e op,
+ void * data,
+ drawCmd_p d,
+ coOrd * origP )
+{
+ trkSeg_p trkseg = &hotB.st;
+ switch ( op ) {
+ case HB_SELECT:
+ CmdCornu( C_CANCEL, zero );
+ curCornu = trkseg;
+ DoCommandB( (void*)(intptr_t)cornuHotBarCmdInx );
+ return NULL;
+ case HB_LISTTITLE:
+ sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale()));
+ return message;
+ case HB_BARTITLE:
+ sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale()));
+ return message;
+ case HB_FULLTITLE:
+ sprintf(message,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale()));
+ return message;
+ case HB_DRAW:
+ DrawSegs( d, *origP, 0.0, trkseg, hotB.count, trackGauge, wDrawColorBlack );
+ return NULL;
+ }
+ return NULL;
+}
+
+static pts_t pts[4];
+
+
+EXPORT void AddHotBarCornu( void )
+{
+ hotB.st.type = SEG_STRTRK;
+ hotB.st.color = wDrawColorBlack;
+ hotB.st.u.l.pos[0] = zero;
+ DIST_T ratio = 75.0/curScaleRatio;
+ Translate(&hotB.st.u.l.pos[1],zero,45.0,15.0*ratio);
+ hotB.st.u.l.angle = 45.0;
+
+ pts[0].pt_type = wPolyLineStraight;
+ pts[0].pt.x = 1.0*ratio;
+ pts[0].pt.y = 5.0*ratio;
+ pts[1].pt_type = wPolyLineStraight;
+ pts[1].pt.x = 1.0*ratio;
+ pts[1].pt.y = 8.0*ratio;
+ pts[2].pt_type = wPolyLineStraight;
+ pts[2].pt.x = 13.0*ratio;
+ pts[2].pt.y = 8.0*ratio;
+ pts[3].pt_type = wPolyLineStraight;
+ pts[3].pt.x = 13.0*ratio;
+ pts[3].pt.y = 5.0*ratio;
+
+ hotB.back.type = SEG_FILPOLY;
+ hotB.back.color = wDrawColorWhite;
+ hotB.back.u.p.orig.x = 0.0;
+ hotB.back.u.p.orig.y = 0.0;
+ hotB.back.u.p.cnt = 4;
+ hotB.back.u.p.angle = 0.0;
+ hotB.back.u.p.polyType = RECTANGLE;
+ hotB.back.u.p.pts = &pts[0];
+
+ hotB.txt.type = SEG_TEXT;
+ hotB.txt.color = wDrawColorBlack;
+ hotB.txt.u.t.pos.x = 1.0*ratio;
+ hotB.txt.u.t.pos.y = 5.0*ratio;
+ hotB.txt.u.t.boxed = TRUE;
+ hotB.txt.u.t.string = MyStrdup(_(" FLEX "));
+ hotB.txt.u.t.fontP = NULL;
+ hotB.txt.u.t.fontSize = 160.0*ratio;
+ hotB.txt.u.t.angle = 0.0;
+
+ char * label = MyMalloc(256);
+ sprintf(label,_("%s FlexTrack"),GetScaleName(GetLayoutCurScale()));
+ coOrd end;
+ end = hotB.st.u.l.pos[1];
+ //end.x = 21.25;
+ //end.y = 21.25;
+ hotB.count = 3;
+ //hotB.st.u.l.pos[1] = end;
+ AddHotBarElement( label, end, zero, TRUE, TRUE, curBarScale>0?curBarScale:-1, &hotB, CmdCornuHotBarProc );
+}
+
+int createMidPoint(dynArr_t * ap,
+ coOrd pos0, //end on curve
+ BOOL_T point_selected,
+ BOOL_T point_selectable,
+ BOOL_T track_modifyable
+ )
+{
+ DIST_T d, w;
+ d = tempD.scale*0.25;
+ w = tempD.scale/tempD.dpi; /*double width*/
+
+ DYNARR_APPEND(trkSeg_t,*ap,1);
+
+ trkSeg_p sp = &DYNARR_LAST(trkSeg_t,*ap);
+
+ sp->u.c.center = pos0;
+ sp->u.c.a0 = 0.0;
+ sp->u.c.a1 = 360.0;
+ sp->u.c.radius = d/2;
+ sp->type = point_selected?SEG_FILCRCL:SEG_CRVLIN;
+ sp->width = w;
+ sp->color = drawColorBlack;
+
+ return 1;
+
+}
/**
@@ -146,35 +304,208 @@ int createEndPoint(
coOrd pos0, //end on curve
BOOL_T point_selected,
BOOL_T point_selectable,
- BOOL_T track_modifyable
+ BOOL_T track_modifyable,
+ BOOL_T track_present,
+ ANGLE_T angle,
+ DIST_T radius,
+ coOrd centert,
+ endHandle * endHandle
)
{
DIST_T d, w;
+ int num =0;
d = tempD.scale*0.25;
w = tempD.scale/tempD.dpi; /*double width*/
+ num = 1;
+ if (point_selectable) {
+ sp[1].u.c.center = pos0;
+ sp[1].u.c.a0 = 0.0;
+ sp[1].u.c.a1 = 360.0;
+ sp[1].u.c.radius = d/2;
+ sp[1].type = SEG_CRVLIN;
+ sp[1].width = w;
+ sp[1].color = point_selected?drawColorBlue:drawColorRed;
+ num = 2;
+ }
sp[0].u.c.center = pos0;
sp[0].u.c.a0 = 0.0;
sp[0].u.c.a1 = 360.0;
sp[0].width = w;
sp[0].u.c.radius = d/4;
- sp[0].color = (point_selected>=0)?drawColorRed:drawColorBlack;
+ sp[0].color = point_selected?drawColorBlue:drawColorRed;
if (track_modifyable)
sp[0].type = SEG_CRVLIN;
else
sp[0].type = SEG_FILCRCL;
- if (point_selectable) {
- sp[1].u.c.center = pos0;
- sp[1].u.c.a0 = 0.0;
- sp[1].u.c.a1 = 360.0;
- sp[1].u.c.radius = d/2;
- sp[1].type = SEG_CRVLIN;
- sp[1].width = w;
- sp[1].color = drawColorRed;
- return 2;
+ if (!track_present && endHandle ) {
+ endHandle->end_center = zero;
+ endHandle->end_curve = zero;
+ endHandle->end_valid = TRUE;
+ endHandle->mid_disp = 0.0;
+ DIST_T end_length = 20*trackGauge;
+ Translate(&endHandle->end_curve,pos0,angle,end_length);
+ Translate(&endHandle->end_center,pos0,angle,end_length/2);
+ if (radius>0.0) {
+ ANGLE_T a1 = R2D(end_length/radius);
+ if (DifferenceBetweenAngles(angle,FindAngle(centert,pos0))>0.0) {
+ a1 = -a1;
+ }
+ PointOnCircle( &endHandle->end_curve, centert,radius,NormalizeAngle(FindAngle(centert,pos0)+a1));
+ PointOnCircle( &endHandle->end_center,centert,radius,NormalizeAngle(FindAngle(centert,pos0)+(a1/2.0)));
+ coOrd cm;
+ cm = endHandle->end_center;
+ ANGLE_T a = FindAngle(endHandle->end_curve,pos0);
+ Rotate(&cm,endHandle->end_curve,-a );
+ endHandle->mid_disp = cm.x-endHandle->end_curve.x;
+ curveData_t curveData;
+ PlotCurve(crvCmdFromCenter,pos0,endHandle->end_center, endHandle->end_curve, &curveData, FALSE);
+ if (curveData.type == curveTypeStraight) {
+ coOrd pos_line[2];
+ Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2);
+ Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2);
+ sp[num].type = SEG_STRLIN;
+ sp[num].width = w;
+ sp[num].u.l.pos[0] = pos_line[0];
+ sp[num].u.l.pos[1] = pos_line[1];
+ sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed;
+ num++;
+ Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2);
+ Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2);
+ sp[num].type = SEG_STRLIN;
+ sp[num].width = w;
+ sp[num].u.l.pos[0] = pos_line[0];
+ sp[num].u.l.pos[1] = pos_line[1];
+ sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed;
+ num++;
+ pos_line[0]= pos0;
+ Translate(&pos_line[1],pos0,-FindAngle(pos0,endHandle->end_curve),end_length);
+ sp[num].type = SEG_STRLIN;
+ sp[num].width = w;
+ sp[num].u.l.pos[0] = pos_line[0];
+ sp[num].u.l.pos[1] = pos_line[1];
+ sp[num].color = drawColorRed;
+ num++;
+ } else {
+ DIST_T pos_rad;
+ pos_rad = radius+trackGauge/2;
+ sp[num].type = SEG_CRVLIN;
+ sp[num].width = w;
+ sp[num].u.c.center = centert;
+ sp[num].u.c.radius = pos_rad;
+ ANGLE_T an0 = FindAngle(centert,pos0);
+ ANGLE_T an1 = FindAngle(centert,endHandle->end_curve);
+ if (DifferenceBetweenAngles(an0,an1)>0) {
+ sp[num].u.c.a1 = DifferenceBetweenAngles(an0,an1);
+ sp[num].u.c.a0 = an0;
+ } else {
+ sp[num].u.c.a1 = -DifferenceBetweenAngles(an0,an1);
+ sp[num].u.c.a0 = an1;
+ }
+ endHandle->arc_angle = sp[num].u.c.a1;
+ sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed;
+ num++;
+ pos_rad = radius-trackGauge/2;
+ sp[num].type = SEG_CRVLIN;
+ sp[num].width = w;
+ sp[num].u.c.center = centert;
+ sp[num].u.c.radius = pos_rad;
+ sp[num].u.c.a1 = sp[num-1].u.c.a1;
+ sp[num].u.c.a0 = sp[num-1].u.c.a0;
+ sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed;
+ num++;
+ }
+ } else {
+ coOrd pos_line[2];
+ Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2);
+ Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)+90,trackGauge/2);
+ sp[num].type = SEG_STRLIN;
+ sp[num].width = w;
+ sp[num].u.l.pos[0] = pos_line[0];
+ sp[num].u.l.pos[1] = pos_line[1];
+ sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed;
+ num++;
+ Translate(&pos_line[0],pos0,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2);
+ Translate(&pos_line[1],endHandle->end_curve,FindAngle(pos0,endHandle->end_curve)-90,trackGauge/2);
+ sp[num].type = SEG_STRLIN;
+ sp[num].width = w;
+ sp[num].u.l.pos[0] = pos_line[0];
+ sp[num].u.l.pos[1] = pos_line[1];
+ sp[num].color = (endHandle->last_selected||endHandle->radius_selected)?drawColorBlue:drawColorRed;
+ num++;
+
+ }
+ coOrd pos_line[2];
+ pos_line[0]= pos0;
+ Translate(&pos_line[1],pos0,angle+180,end_length);
+ sp[num].type = SEG_STRLIN;
+ sp[num].width = w;
+ sp[num].u.l.pos[0] = pos_line[0];
+ sp[num].u.l.pos[1] = pos_line[1];
+ sp[num].color = drawColorRed;
+ num++;
+ sp[num].type = SEG_CRVLIN;
+ sp[num].u.c.center = endHandle->end_curve;
+ sp[num].u.c.a0 = 0.0;
+ sp[num].u.c.a1 = 360.0;
+ sp[num].width = w;
+ sp[num].u.c.radius = d/4;
+ sp[num].color = endHandle->angle_selected?drawColorBlue:drawColorRed;
+ num++;
+ if (radius<=0.0)
+ DrawArrowHeads(&sp[num],endHandle->end_center,angle+90.0,TRUE,endHandle->radius_selected?drawColorBlue:drawColorRed);
+ else
+ DrawArrowHeads(&sp[num],endHandle->end_center,FindAngle(centert,endHandle->end_center),TRUE,endHandle->radius_selected?drawColorBlue:drawColorRed);
+ num=num+5;
+ } else if (endHandle) {
+ endHandle->end_valid=FALSE;
}
- return 1;
+ return num;
+}
+
+static dynArr_t anchors_da;
+#define anchors(N) DYNARR_N(trkSeg_t,anchors_da,N)
+
+static void CreateCornuEndAnchor(coOrd p, wBool_t lock) {
+ DIST_T d = tempD.scale*0.15;
+
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.c.center = p;
+ anchors(i).u.c.radius = d/2;
+ anchors(i).u.c.a0 = 0.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).width = 0;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ i = anchors_da.cnt-1;
+ anchors(i).type = SEG_CRVLIN;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.c.center = p;
+ anchors(i).u.c.radius = d;
+ anchors(i).u.c.a0 = 0.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).width = 0;
+
+}
+
+static void CreateCornuExtendAnchor(coOrd p, ANGLE_T a, wBool_t selected) {
+ DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5);
+ DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),p,a,FALSE,wDrawColorBlue);
}
+static void CreateCornuAnchor(coOrd p, wBool_t open) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,anchors_da,1);
+ int i = anchors_da.cnt-1;
+ anchors(i).type = open?SEG_CRVLIN:SEG_FILCRCL;
+ anchors(i).color = wDrawColorBlue;
+ anchors(i).u.c.center = p;
+ anchors(i).u.c.radius = d/2;
+ anchors(i).u.c.a0 = 0.0;
+ anchors(i).u.c.a1 = 360.0;
+ anchors(i).width = 0;
+}
/*
* Add element to DYNARR pointed to by caller from segment handed in
@@ -182,7 +513,6 @@ int createEndPoint(
void addSegCornu(dynArr_t * const array_p, trkSeg_p seg) {
trkSeg_p s;
-
DYNARR_APPEND(trkSeg_t, * array_p, 10); //Adds 1 to cnt
s = &DYNARR_N(trkSeg_t,* array_p,array_p->cnt-1);
s->type = seg->type;
@@ -206,20 +536,105 @@ void addSegCornu(dynArr_t * const array_p, trkSeg_p seg) {
s->u = seg->u;
}
}
-EXPORT void SetKnots(spiro_cp knots[6], coOrd posk[6]) {
- for (int i = 0; i < 6; i++) {
+EXPORT void SetKnots(spiro_cp knots[], coOrd posk[], char type[], int count) {
+ for (int i = 0; i < count; i++) {
knots[i].x = posk[i].x;
knots[i].y = posk[i].y;
+ knots[i].ty = type[i];
+ }
+}
+
+typedef struct {
+ coOrd pos;
+ char ty;
+} points_t;
+
+// Take in extra points within Cornu
+// G2 (position only k1'' = k2'' = 0); Also Cornu <-> Cornu
+// G4 (position only - splitable for Cornu - a G4 point) k1''= k2''
+
+BOOL_T CallCornuM(dynArr_t extra_points, BOOL_T end[2], coOrd pos[2], cornuParm_t * cp, dynArr_t * array_p, BOOL_T spots) {
+ array_p->cnt = 0;
+ //Create LH knots
+ //Find remote end point of track, create start knot
+ int ends[2];
+ ends[0] = (end[0]?2:0); ends[1] = (end[0]?3:1)+extra_points.cnt;
+ spiro_cp * knots;
+ coOrd * posk;
+ char * type;
+ posk = MyMalloc((6+extra_points.cnt)*sizeof(coOrd));
+ knots = MyMalloc((6+extra_points.cnt)*sizeof(spiro_cp));
+ type = MyMalloc((6+extra_points.cnt)*sizeof(char));
+ BOOL_T back;
+ ANGLE_T angle1;
+
+ if (Da.bezc) free(Da.bezc);
+
+ Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots,tempD.scale*0.15/4);
+
+ coOrd pos0 = pos[0];
+
+ if (end[0]) {
+ type[0] = SPIRO_OPEN_CONTOUR;
+ type[1] = SPIRO_G2;
+ type[2] = SPIRO_RIGHT;
+ if (cp->radius[0] == 0.0) {
+ Translate(&posk[0],pos0,cp->angle[0],10);
+ Translate(&posk[1],pos0,cp->angle[0],5);
+ } else {
+ angle1 = FindAngle(cp->center[0],pos[0]);
+ if (NormalizeAngle(angle1 - cp->angle[0])<180) back = TRUE;
+ else back = FALSE;
+ posk[0] = pos[0];
+ Rotate(&posk[0],cp->center[0],(back)?-10:10);
+ posk[1] = pos[0];
+ Rotate(&posk[1],cp->center[0],(back)?-5:5);
+ }
+ posk[2] = pos[0];
+ } else {
+ type[0] = SPIRO_OPEN_CONTOUR;
+ posk[0] = pos[0];
+ }
+
+ for (int i=0;i<extra_points.cnt;i++) {
+ posk[(end[0]?3:1)+i] = DYNARR_N(coOrd,extra_points,i);
+ type[(end[0]?3:1)+i] = SPIRO_G4;
+ }
+
+ posk[(end[0]?3:1)+extra_points.cnt] = pos[1];
+ coOrd pos1 = pos[1];
+
+ if (end[1]) {
+ type[(end[0]?3:1)+extra_points.cnt] = SPIRO_LEFT;
+ type[(end[0]?3:1)+extra_points.cnt+1] = SPIRO_G2;
+ type[(end[0]?3:1)+extra_points.cnt+2] = SPIRO_END_OPEN_CONTOUR;
+ if (cp->radius[1] == 0.0) {
+ Translate(&posk[(end[0]?3:1)+extra_points.cnt+1],pos1,cp->angle[1],5);
+ Translate(&posk[(end[0]?3:1)+extra_points.cnt+2],pos1,cp->angle[1],10);
+ } else {
+ angle1 = FindAngle(cp->center[1],pos[1]);
+ if (NormalizeAngle(angle1 - cp->angle[1])>180) back = TRUE;
+ else back = FALSE;
+ posk[(end[0]?3:1)+extra_points.cnt+1] = pos[1];
+ Rotate(&posk[(end[0]?3:1)+extra_points.cnt+1],cp->center[1],(back)?5:-5);
+ posk[(end[0]?3:1)+extra_points.cnt+2] = pos[1];
+ Rotate(&posk[(end[0]?3:1)+extra_points.cnt+2],cp->center[1],(back)?10:-10);
+ }
+ } else {
+ type[(end[0]?3:1)+extra_points.cnt] = SPIRO_END_OPEN_CONTOUR;
}
- knots[0].ty = SPIRO_OPEN_CONTOUR;
- knots[1].ty = SPIRO_G2;
- knots[2].ty = SPIRO_RIGHT;
- knots[3].ty = SPIRO_LEFT;
- knots[4].ty = SPIRO_G2;
- knots[5].ty = SPIRO_END_OPEN_CONTOUR;
+ SetKnots(knots, posk, type, ((end[0]?3:1)+(end[1]?3:1)+extra_points.cnt));
+ TaggedSpiroCPsToBezier(knots,Da.bezc);
+ MyFree(posk);
+ MyFree(knots);
+ MyFree(type);
+ if (!bezctx_xtrkcad_close(Da.bezc)) {
+ return FALSE;
+ }
+ return TRUE;
}
-BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p, BOOL_T spots) {
+EXPORT BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p, BOOL_T spots) {
array_p->cnt = 0;
//Create LH knots
//Find remote end point of track, create start knot
@@ -227,14 +642,17 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius
ends[0] = 2; ends[1] = 3;
spiro_cp knots[6];
coOrd posk[6];
+ char type[6];
BOOL_T back;
ANGLE_T angle1;
if (Da.bezc) free(Da.bezc);
- Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots);
+ Da.bezc = new_bezctx_xtrkcad(array_p,ends,spots,tempD.scale*0.15/4);
coOrd pos0 = pos[0];
+ type[0] = SPIRO_OPEN_CONTOUR;
+
if (radius[0] == 0.0) {
Translate(&posk[0],pos0,angle[0],10);
@@ -248,9 +666,12 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius
posk[1] = pos[0];
Rotate(&posk[1],center[0],(back)?-5:5);
}
+ type[1] = SPIRO_G2;
posk[2] = pos[0];
+ type[2] = SPIRO_RIGHT;
posk[3] = pos[1];
+ type[3] = SPIRO_LEFT;
coOrd pos1 = pos[1];
@@ -266,7 +687,10 @@ BOOL_T CallCornu0(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius
posk[5] = pos[1];
Rotate(&posk[5],center[1],(back)?10:-10);
}
- SetKnots(knots,posk);
+ type[4] = SPIRO_G2;
+ type[5] = SPIRO_END_OPEN_CONTOUR;
+
+ SetKnots(knots, posk, type, 6);
TaggedSpiroCPsToBezier(knots,Da.bezc);
if (!bezctx_xtrkcad_close(Da.bezc)) {
return FALSE;
@@ -290,19 +714,19 @@ BOOL_T CallCornu(coOrd pos[2], track_p trk[2], EPINX_T ep[2], dynArr_t * array_p
if (Da.circleorHelix[i]) { //Helix/Circle only
cp->radius[i] = params.arcR;
cp->center[i] = params.arcP;
- cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
+ if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
} else if (params.type == curveTypeStraight) {
cp->angle[i] = NormalizeAngle(angle+180); //Because end always backwards
cp->radius[i] = 0.0;
} else if ((params.type == curveTypeCornu || params.type == curveTypeBezier) && params.arcR == 0.0 ) {
cp->radius[i] = 0.0;
- cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); //Use point not end
+ if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0)); //Use point not end
} else if (params.type == curveTypeCurve) {
- cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
+ if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
cp->radius[i] = params.arcR;
cp->center[i] = params.arcP;
} else if ((params.type == curveTypeCornu || params.type == curveTypeBezier) && params.arcR != 0.0 ){
- cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
+ if (ep && ep[i]>=0) cp->angle[i] = NormalizeAngle(params.track_angle+(ep[i]?180:0));
cp->radius[i] = params.arcR;
cp->center[i] = params.arcP;
} else {
@@ -317,6 +741,7 @@ BOOL_T CallCornu(coOrd pos[2], track_p trk[2], EPINX_T ep[2], dynArr_t * array_p
}
+
/*
* Draw Cornu while editing it. It consists of up to five elements - the ends, the curve and one or two End Points.
*
@@ -333,30 +758,26 @@ EXPORT void DrawCornuCurve(
trkSeg_p second_trk,
trkSeg_p extend1_trk,
trkSeg_p extend2_trk,
+ trkSeg_p mids,
+ int midSegs_cnt,
wDrawColor color
) {
- long oldDrawOptions = tempD.funcs->options;
- tempD.funcs->options = wDrawOptTemp;
- long oldOptions = tempD.options;
- tempD.options = DC_TICKS;
- tempD.orig = mainD.orig;
- tempD.angle = mainD.angle;
if (first_trk)
DrawSegs( &tempD, zero, 0.0, first_trk, 1, Da.trackGauge, drawColorBlack );
- if (crvSegs_cnt && curveSegs)
+ if (crvSegs_cnt>0 && curveSegs)
DrawSegs( &tempD, zero, 0.0, curveSegs, crvSegs_cnt, Da.trackGauge, color );
if (second_trk)
DrawSegs( &tempD, zero, 0.0, second_trk, 1, Da.trackGauge, drawColorBlack );
- if (ep1Segs_cnt && point1)
+ if (ep1Segs_cnt>0 && point1)
DrawSegs( &tempD, zero, 0.0, point1, ep1Segs_cnt, Da.trackGauge, drawColorBlack );
- if (ep2Segs_cnt && point2)
+ if (ep2Segs_cnt>0 && point2)
DrawSegs( &tempD, zero, 0.0, point2, ep2Segs_cnt, Da.trackGauge, drawColorBlack );
+ if (midSegs_cnt>0 && mids)
+ DrawSegs( &tempD, zero, 0.0, mids, midSegs_cnt, Da.trackGauge, drawColorBlack );
if (extend1_trk)
DrawSegs( &tempD, zero, 0.0, extend1_trk, 1, Da.trackGauge, drawColorBlack);
if (extend2_trk)
DrawSegs( &tempD, zero, 0.0, extend2_trk, 1, Da.trackGauge, drawColorBlack);
- tempD.funcs->options = oldDrawOptions;
- tempD.options = oldOptions;
}
@@ -373,35 +794,53 @@ void DrawTempCornu() {
&Da.trk2Seg,
Da.extend[0]?&Da.extendSeg[0]:NULL,
Da.extend[1]?&Da.extendSeg[1]:NULL,
- Da.minRadius<(GetLayoutMinTrackRadius()-EPSILON)?drawColorRed:drawColorBlack);
+ (trkSeg_t *)Da.midSegs.ptr,Da.midSegs.cnt,
+ fabs(Da.minRadius)<(GetLayoutMinTrackRadius()-EPSILON)?exceptionColor:normalColor);
}
-void CreateBothEnds(int selectPoint) {
+void CreateBothEnds(int selectEndPoint, int selectMidPoint, int selectEndHandle, int lastSelected ) {
BOOL_T selectable[2],modifyable[2];
selectable[0] = !Da.trk[0] || (
Da.trk[0] && !QueryTrack(Da.trk[0],Q_IS_CORNU) && !QueryTrack(Da.trk[0],Q_CAN_MODIFY_CONTROL_POINTS));
modifyable[0] = !Da.trk[0] || (
Da.trk[0] && QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY));
selectable[1] = !Da.trk[1] || (
- Da.trk[1] && !QueryTrack(Da.trk[1],Q_IS_CORNU) && !QueryTrack(Da.trk[0],Q_CAN_MODIFY_CONTROL_POINTS));
+ Da.trk[1] && !QueryTrack(Da.trk[1],Q_IS_CORNU) && !QueryTrack(Da.trk[1],Q_CAN_MODIFY_CONTROL_POINTS));
modifyable[1] = !Da.trk[1] || (
Da.trk[1] && QueryTrack(Da.trk[1],Q_CORNU_CAN_MODIFY));
- if (selectPoint == -1) {
- Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0]);
- Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1]);
- } else if (selectPoint == 0 || selectPoint == 1) {
- Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],selectPoint == 0,selectable[0],modifyable[0]);
- Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],selectPoint == 1,selectable[1],modifyable[1]);
+
+ Da.endHandle[0].angle_selected = (selectEndHandle==1)?TRUE:FALSE;
+ Da.endHandle[0].radius_selected = (selectEndHandle==0)?TRUE:FALSE;
+ Da.endHandle[1].angle_selected = (selectEndHandle==3)?TRUE:FALSE;
+ Da.endHandle[1].radius_selected = (selectEndHandle==2)?TRUE:FALSE;
+ Da.endHandle[0].last_selected = lastSelected==0?TRUE:FALSE;
+ Da.endHandle[1].last_selected = lastSelected==1?TRUE:FALSE;
+ if (selectEndPoint == -1) {
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0],Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],Da.extend[0]?NULL:&Da.endHandle[0]);
+ Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1],Da.trk[1]!=NULL,Da.angle[1],Da.radius[1],Da.center[1],Da.extend[1]?NULL:&Da.endHandle[1]);
} else {
- Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,selectable[0],modifyable[0]);
- Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],FALSE,selectable[1],modifyable[1]);
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],selectEndPoint == 0,selectable[0],modifyable[0],Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],Da.extend[0]?NULL:&Da.endHandle[0]);
+ Da.ep2Segs_da_cnt = createEndPoint(Da.ep2Segs, Da.pos[1],selectEndPoint == 1,selectable[1],modifyable[1],Da.trk[1]!=NULL,Da.angle[1],Da.radius[1],Da.center[1],Da.extend[1]?NULL:&Da.endHandle[1]);
}
+ Da.endHandle[0].end_valid = !Da.extend[0];
+ Da.endHandle[1].end_valid = !Da.extend[1];
+ DYNARR_RESET(trkSeg_t,Da.midSegs);
+ for (int i=0;i<Da.mid_points.cnt;i++) {
+ createMidPoint(&Da.midSegs, DYNARR_N(coOrd,Da.mid_points,i),selectMidPoint == i,TRUE, TRUE );
+ }
+ if (Da.radius[0] >=0.0) Da.ends[0] = TRUE;
+ else Da.ends[0] = FALSE;
+ if (Da.radius[1] >=0.0) Da.ends[1] = TRUE;
+ else Da.ends[1] = FALSE;
}
-BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track_end) {
+BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track_end, wBool_t extend) {
trackParams_t trackParams;
- if (!GetTrackParams(PARAMS_CORNU, t, pos, &trackParams)) return FALSE;
+ coOrd pos1;
+ if ((track_end>=0) && extend) pos1 = GetTrkEndPos(t,track_end);
+ else pos1 = pos;
+ if (!GetTrackParams(PARAMS_CORNU, t, pos1, &trackParams)) return FALSE;
Da.radius[end] = 0.0;
Da.center[end] = zero;
Da.circleorHelix[end] = FALSE;
@@ -415,7 +854,8 @@ BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track
Da.circleorHelix[end] = TRUE;
Da.angle[end] = trackParams.track_angle; //For Now
} else {
- Da.angle[end] = NormalizeAngle(trackParams.track_angle + (track_end?180:0));
+ Da.angle[end] = NormalizeAngle(GetTrkEndAngle(t,track_end)+180);
+ //Da.angle[end] = NormalizeAngle(trackParams.track_angle + (track_end?180:0));
}
} else if (trackParams.type == curveTypeBezier) {
Da.angle[end] = NormalizeAngle(trackParams.track_angle+(track_end?180:0));
@@ -430,12 +870,12 @@ BOOL_T GetConnectedTrackParms(track_p t, const coOrd pos, int end, EPINX_T track
}
} else if (trackParams.type == curveTypeCornu) {
int ep = trackParams.ep;
- Da.angle[end] = NormalizeAngle(trackParams.cornuAngle[ep]+(track_end?180:0));
+ Da.angle[end] = NormalizeAngle(trackParams.cornuAngle[ep]+180);
Da.radius[end] = trackParams.cornuRadius[ep];
Da.pos[end] = trackParams.cornuEnd[ep];
Da.center[end] = trackParams.cornuCenter[ep];
} else if (trackParams.type == curveTypeStraight) {
- if (Da.ep[end]>=0)
+ if (trackParams.ep>=0)
Da.angle[end] = NormalizeAngle(GetTrkEndAngle(t,track_end)+180); //Ignore params.angle because it gives from nearest end
else {
Da.angle[end] = NormalizeAngle(trackParams.angle+180); //Turntable
@@ -483,11 +923,106 @@ void SetUpCornuParms(cornuParm_t * cp) {
cp->radius[1] = Da.radius[1];
}
+track_p CreateCornuFromPoints(coOrd pos[2],BOOL_T track_end[2]) {
+ coOrd center[2];
+ DIST_T radius[2];
+ ANGLE_T angle[2];
+ BOOL_T back, neg;
+ cornuParm_t new;
+ int inx,subinx;
+ coOrd pos_temp[2];
+
+ for (int i=0;i<2;i++) {
+ pos_temp[i] = pos[i];
+
+ if (!track_end[i] || (Da.radius[i]==-1.0)) {
+
+ angle[i] = GetAngleSegs(Da.crvSegs_da.cnt,(trkSeg_t *)(Da.crvSegs_da.ptr),&pos_temp[i],&inx,NULL,&back,&subinx,&neg);
+
+ trkSeg_p segPtr = &DYNARR_N(trkSeg_t, Da.crvSegs_da, inx);
+
+ if (segPtr->type == SEG_BEZTRK)
+ segPtr = &DYNARR_N(trkSeg_t, segPtr->bezSegs, subinx);
+
+ if (i==0) {
+ if (neg==back) angle[i] = NormalizeAngle(angle[i]+180);
+ } else {
+ if (!(neg==back)) angle[i] = NormalizeAngle(angle[i]+180);
+ }
+
+ if (segPtr->type == SEG_STRTRK) {
+ radius[i] = 0.0;
+ center[i] = zero;
+ } else if (segPtr->type == SEG_CRVTRK) {
+ center[i] = segPtr->u.c.center;
+ radius[i] = fabs(segPtr->u.c.radius);
+ }
+ } else {
+ pos[i] = Da.pos[i];
+ radius[i] = Da.radius[i];
+ center[i] = Da.center[i];
+ angle[i] = Da.angle[i];
+ neg = FALSE;
+ back = FALSE;
+ }
+ }
+ new.pos[0] = pos[0];
+ new.pos[1] = pos[1];
+ new.angle[0] = angle[0];
+ new.angle[1] = angle[1];
+ new.center[0] = center[0];
+ new.center[1] = center[1];
+ new.radius[0] = radius[0];
+ new.radius[1] = radius[1];
+
+ track_p trk1 = NewCornuTrack(new.pos,new.center,new.angle,new.radius,NULL,0);
+ if (trk1==NULL) {
+ wBeep();
+ InfoMessage(_("Cornu Create Failed for p1[%0.3f,%0.3f] p2[%0.3f,%0.3f], c1[%0.3f,%0.3f] c2[%0.3f,%0.3f], a1=%0.3f a2=%0.3f, r1=%s r2=%s"),
+ new.pos[0].x,new.pos[0].y,
+ new.pos[1].x,new.pos[1].y,
+ new.center[0].x,new.center[0].y,
+ new.center[1].x,new.center[1].y,
+ new.angle[0],new.angle[1],
+ FormatDistance(new.radius[0]),FormatDistance(new.radius[1]));
+ UndoEnd();
+ return NULL;
+ }
+ return trk1;
+}
+
struct extraData {
cornuData_t cornuData;
};
+ANGLE_T GetOpenAngle(coOrd pos[2],ANGLE_T angle[2],int moved) {
+ ANGLE_T a = FindAngle(pos[1-moved],pos[moved]);
+ ANGLE_T diff = (180+a)-angle[1-moved]; //Difference between input and line
+ return a+diff; //Change to line plus this at the other end
+}
+
+static struct {
+ ANGLE_T angle;
+ DIST_T radius;
+
+} cornuModCmdContext;
+
+static BOOL_T infoSubst = FALSE;
+
+static paramFloatRange_t r10000_10000 = {-10000, 10000};
+static paramFloatRange_t r0_360 = { 0, 360, 80 };
+
+static paramData_t cornuModPLs[] = {
+
+#define cornuModEndAnglePD (cornuModPLs[0])
+#define cornuModEndAngle 0
+ { PD_FLOAT, &cornuModCmdContext.angle, "End Angle", PDO_NORECORD|BO_ENTER, &r0_360, N_("End Angle") },
+#define cornuModEndRadiusPD (cornuModPLs[1])
+#define cornuModEndRadius 1
+ { PD_FLOAT, &cornuModCmdContext.radius, "End Radius", PDO_DIM|PDO_NORECORD|BO_ENTER, &r10000_10000, N_("End Radius") },
+};
+static paramGroup_t cornuModPG = { "cornuMod", 0, cornuModPLs, sizeof cornuModPLs/sizeof cornuModPLs[0] };
/*
* AdjustCornuCurve
@@ -509,221 +1044,535 @@ EXPORT STATUS_T AdjustCornuCurve(
track_p t;
DIST_T d;
ANGLE_T a, a2;
- DIST_T dd;
EPINX_T ep;
cornuParm_t cp;
+ wControl_p controls[5]; //Always needs a NULL last entry
+ char * labels[4];
+
+ Da.cmdType = (long)commandContext;
+
if (Da.state != PICK_POINT && Da.state != POINT_PICKED && Da.state != TRACK_SELECTED) return C_CONTINUE;
switch ( action & 0xFF) {
case C_START:
- Da.selectPoint = -1;
- Da.extend[0] = FALSE;
- Da.extend[1] = FALSE;
- CreateBothEnds(Da.selectPoint);
- Da.crvSegs_da.cnt = 0;
- SetUpCornuParms(&cp);
- if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
- else Da.crvSegs_da_cnt = 0;
- Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
- InfoMessage( _("Select End-Point") );
- DrawTempCornu();
- return C_CONTINUE;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ infoSubst = FALSE;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ Da.selectEndHandle = -1;
+ Da.prevSelected = -1;
+ Da.prevEndPoint = -1;
+ Da.extend[0] = FALSE;
+ Da.extend[1] = FALSE;
+ CreateBothEnds(Da.selectEndPoint, Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
+ Da.crvSegs_da.cnt = 0;
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
+ InfoMessage( _("Select Point, or Add Point") );
+ TempRedraw(); // AdjustCornuCurve C_START
+ return C_CONTINUE;
+
+ case C_UPDATE:
+ if (Da.state != PICK_POINT && Da.prevSelected>-1) return C_CONTINUE;
+ int sel = Da.prevSelected;
+ if (Da.trk[sel]) return C_CONTINUE; //Track Here - should never happen
+ Da.radius[sel] = fabs(cornuModCmdContext.radius);
+ Da.angle[sel] = cornuModCmdContext.angle;
+ if (cornuModCmdContext.radius!=0)
+ Translate(&Da.center[sel],Da.pos[sel],Da.angle[sel]+90,cornuModCmdContext.radius);
+ CreateBothEnds(Da.prevSelected,-1,-1,Da.prevSelected);
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
+ return C_CONTINUE;
+ break;
+
+ case wActionMove:
+ if (Da.state == NONE || Da.state == PICK_POINT) {
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ for(int i=0;i<2;i++) {
+ if (IsClose(FindDistance(pos,Da.pos[i]))) {
+ if (((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) {
+ CreateCornuExtendAnchor(Da.pos[i], Da.angle[i], FALSE);
+ return C_CONTINUE;
+ } else {
+ CreateCornuAnchor(Da.pos[i], FALSE);
+ return C_CONTINUE;
+ }
+ }
+ }
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
+ Da.selectEndPoint = -1;
+ for (int i=0;i<Da.mid_points.cnt;i++) {
+ d = FindDistance(DYNARR_N(coOrd,Da.mid_points,i),pos);
+ if (IsClose(d)) {
+ CreateCornuAnchor(DYNARR_N(coOrd,Da.mid_points,i),FALSE);
+ return C_CONTINUE;
+ }
+ }
+ for (int i=0;i<2;i++) {
+ if (Da.endHandle[i].end_valid == FALSE) continue;
+ d = FindDistance(Da.endHandle[i].end_center,pos);
+ if (IsClose(d)) {
+ CreateCornuAnchor(Da.endHandle[i].end_center, FALSE);
+ return C_CONTINUE;
+ }
+ }
+ for (int i=0;i<2;i++) {
+ if (Da.endHandle[i].end_valid == FALSE) continue;
+ d = FindDistance(Da.endHandle[i].end_curve,pos);
+ if (IsClose(d)) {
+ CreateCornuAnchor(Da.endHandle[i].end_curve, FALSE);
+ return C_CONTINUE;
+ }
+ }
+ coOrd temp_pos = pos;
+ if (IsClose(DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,NULL))) {
+ CreateCornuAnchor(temp_pos, TRUE);
+ }
+ }
+ return C_CONTINUE;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (Da.state != PICK_POINT) return C_CONTINUE;
- dd = 10000.0;
- Da.selectPoint = -1;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ Da.selectEndHandle = -1;
+ Da.prevSelected = -1;
+ if (infoSubst) {
+ InfoSubstituteControls( NULL, NULL );
+ infoSubst = FALSE;
+ }
for (int i=0;i<2;i++) {
d = FindDistance(Da.pos[i],pos);
- if (d < dd) {
- dd = d;
- Da.selectPoint = i;
+ if (IsClose(d)) {
+ Da.selectEndPoint = i;
+ CreateCornuAnchor(Da.pos[i],FALSE);
+ break;
}
}
- if (!IsClose(dd) ) Da.selectPoint = -1;
- if (Da.selectPoint == -1) {
+ if (Da.selectEndPoint == -1) {
+ for (int i=0;i<Da.mid_points.cnt;i++) {
+ d = FindDistance(DYNARR_N(coOrd,Da.mid_points,i),pos);
+ if (IsClose(d)) {
+ Da.selectMidPoint = i;
+ Da.selectEndPoint = -1;
+ CreateCornuAnchor(DYNARR_N(coOrd,Da.mid_points,i),FALSE);
+ break;
+ }
+ }
+ if (Da.selectMidPoint == -1 ) {
+ for (int i=0;i<2;i++) {
+ if (Da.endHandle[i].end_valid == FALSE) continue;
+ d = FindDistance(Da.endHandle[i].end_center,pos);
+ if (IsClose(d)) {
+ Da.selectEndHandle = i*2;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ CreateCornuAnchor(Da.endHandle[i].end_center,i);
+ break;
+ }
+ }
+ if (Da.selectEndHandle == -1) {
+ for (int i=0;i<2;i++) {
+ if (Da.endHandle[i].end_valid == FALSE) continue;
+ d = FindDistance(Da.endHandle[i].end_curve,pos);
+ if (IsClose(d)) {
+ Da.selectEndHandle = 1+i*2;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ CreateCornuAnchor(Da.endHandle[i].end_curve,i);
+ break;
+ }
+ }
+ }
+ }
+ } else { //We picked an end point
+ if (!Da.trk[Da.selectEndPoint] && ((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) { //With Shift no track -> Extend
+ Da.extend[Da.selectEndPoint] = TRUE; //Adding to end Point
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ CreateCornuExtendAnchor(Da.pos[Da.selectEndPoint], Da.angle[Da.selectEndPoint], FALSE);
+ }
+ }
+ if (Da.selectMidPoint ==-1 && Da.selectEndPoint ==-1 && Da.selectEndHandle ==-1) {
+ coOrd temp_pos = pos;
+ wIndex_t index;
+ if (IsClose(DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&index))) {
+ //Add Point between two other points
+ //Find closest two points along Track
+ int closest = -1;
+ wIndex_t pIndex, nIndex;
+ temp_pos = Da.pos[0];
+ DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&pIndex);
+ if (Da.mid_points.cnt>0) {
+ for (int i=0;i<Da.mid_points.cnt;i++) {
+ temp_pos = DYNARR_N(coOrd ,Da.mid_points,i);
+ DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&nIndex);
+ if (((pIndex<=index) && (nIndex>=index))) {
+ closest = i;
+ break;
+ }
+ pIndex = nIndex;
+ }
+ temp_pos = Da.pos[1];
+ DistanceSegs(zero,0.0,Da.crvSegs_da.cnt,(trkSeg_p)Da.crvSegs_da.ptr,&temp_pos,&nIndex);
+ if (index == nIndex) closest = Da.mid_points.cnt;
+ if (closest == -1)
+ closest = Da.mid_points.cnt;
+ } else closest = 0;
+ DYNARR_APPEND(coOrd,Da.mid_points,1);
+ for (int i=Da.mid_points.cnt-1;i>closest;i--) {
+ DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd ,Da.mid_points,i-1);
+ }
+ DYNARR_N(coOrd,Da.mid_points,closest) = pos;
+ Da.selectMidPoint = closest;
+ Da.number_of_points++;
+ CreateCornuAnchor(pos,FALSE);
+ InfoMessage("Pin Point Added");
+ } else {
+ wBeep();
+ InfoMessage("Add Point Is Not on Track");
+ return C_CONTINUE;
+ }
+ }
+ if (Da.selectEndPoint == -1 && Da.selectMidPoint == -1 && Da.selectEndHandle ==-1) {
wBeep();
- InfoMessage( _("Not close enough to end point, reselect") );
+ InfoMessage( _("Not close enough to track or point, reselect") );
return C_CONTINUE;
} else {
- pos = Da.pos[Da.selectPoint];
+ if (Da.selectEndPoint >=0 ) {
+ pos = Da.pos[Da.selectEndPoint];
+ if (Da.extend[Da.selectEndPoint])
+ InfoMessage( _("Drag out end of Cornu"));
+ else if (Da.trk[Da.selectEndPoint]) {
+ InfoMessage( _("Drag along end of track"));
+ } else
+ InfoMessage( _("Drag to move"));
+ } else if (Da.selectMidPoint >=0 ) {
+ pos = DYNARR_N(coOrd,Da.mid_points,Da.selectMidPoint);
+ InfoMessage( _("Drag point to new location, Delete to remove"));
+ } else {
+ if (Da.selectEndHandle%2 == 0) {
+ pos = Da.endHandle[Da.selectEndHandle/2].end_center;
+ InfoMessage( _("Drag to change end radius"));
+ } else {
+ pos = Da.endHandle[Da.selectEndHandle/2].end_curve;
+ InfoMessage( _("Drag to change end angle"));
+ }
+ }
Da.state = POINT_PICKED;
- InfoMessage( _("Drag point %d to new location and release it"),Da.selectPoint+1 );
}
- DrawTempCornu(); //wipe out
- CreateBothEnds(Da.selectPoint);
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
SetUpCornuParms(&cp);
- if (CallCornu(Da.pos, Da.trk,Da.ep, &Da.crvSegs_da, &cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
else Da.crvSegs_da_cnt = 0;
Da.minRadius = CornuMinRadius(Da.pos, Da.crvSegs_da);
- DrawTempCornu();
return C_CONTINUE;
case C_MOVE:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if (Da.state != POINT_PICKED) {
- InfoMessage(_("Pick any circle to adjust it by dragging - Enter to accept, Esc to cancel"));
+ InfoMessage(_("Pick any circle to adjust or add - Enter to accept, Esc to cancel"));
return C_CONTINUE;
}
- //If locked, reset pos to be on line from other track
- int sel = Da.selectPoint;
- coOrd pos2 = pos;
- BOOL_T inside = FALSE;
- if (Da.trk[sel]) { //There is a track
- if (OnTrack(&pos,FALSE,TRUE) == Da.trk[sel]) { //And the pos is on it
- inside = TRUE;
- if (!QueryTrack(Da.trk[Da.selectPoint],Q_CORNU_CAN_MODIFY)) { //Turnouts
- InfoMessage(_("Track can't be split"));
- if (Da.ep[sel]>=0) //Ignore if turntable
- pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ if (Da.selectEndPoint >= 0) {
+ //If locked, reset pos to be on line from other track
+ int sel = Da.selectEndPoint;
+ coOrd pos2 = pos;
+ BOOL_T inside = FALSE;
+ if (Da.trk[sel]) { //Track
+ if (OnTrack(&pos,FALSE,TRUE) == Da.trk[sel]) { //And the pos is on it
+ inside = TRUE;
+ if (!QueryTrack(Da.trk[Da.selectEndPoint],Q_CORNU_CAN_MODIFY)) { //Turnouts
+ InfoMessage(_("Track can't be split"));
+ inside = FALSE;
+ if (Da.ep[sel]>=0) { //If not turntable
+ Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ } else {
+ if (QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)){ //Turntable
+ trackParams_t tp;
+ if (!GetTrackParams(PARAMS_CORNU, Da.trk[sel], pos, &tp)) return C_CONTINUE;
+ ANGLE_T a = tp.angle;
+ Translate(&pos,tp.ttcenter,a,tp.ttradius);
+ Da.angle[sel] = NormalizeAngle(a+180);
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ } else return C_CONTINUE;
+ }
+ }
+ } else {
+ pos = pos2; //Put Back to original position as outside track
}
- } else {
- pos = pos2; //Put Back to original position as outside track
- }
- // Stop the user extending right through the other track
- if (Da.ep[sel]>=0 && QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY)) { //For non-turnouts
- if ((!QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)) // But Not Helix or Circle
- && (!QueryTrack(Da.trk[sel],Q_HAS_VARIABLE_ENDPOINTS))) { // Not a Turntable
- DIST_T ab = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]));
- DIST_T ac = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),pos);
- DIST_T cb = FindDistance(GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]), pos);
- if (cb<minLength) {
- InfoMessage(_("Too close to other end of selected Track"));
- return C_CONTINUE;
+ if (!inside) {
+ if (Da.ep[sel]>=0) { //Track defined end point
+ ANGLE_T diff = NormalizeAngle(GetTrkEndAngle(Da.trk[sel],Da.ep[sel])-FindAngle(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),pos));
+ if (diff>90.0 && diff<270.0) { //The point is not on track but outside cone of end angle+/-90
+ Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
+ return C_CONTINUE;
+ }
+ } else { //Not an end point
+ if (QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)){ //Turntable
+ trackParams_t tp;
+ if (!GetTrackParams(PARAMS_CORNU, Da.trk[sel], pos, &tp)) return C_CONTINUE;
+ ANGLE_T a = tp.angle;
+ coOrd edge;
+ Translate(&edge,tp.ttcenter,a,tp.ttradius);
+ ANGLE_T da = DifferenceBetweenAngles(FindAngle(edge,pos),a);
+ DIST_T d = fabs(FindDistance(edge,pos)*cos(R2D(da)));
+ Translate(&pos,edge,a,d);
+ Da.angle[sel] = NormalizeAngle(a+180);
+ Da.pos[sel] = pos;
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
+ Da.extendSeg[sel].type = SEG_STRTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ Da.extendSeg[sel].u.l.pos[1-sel] = pos;
+ Da.extendSeg[sel].u.l.pos[sel] = edge;
+ Da.extend[sel] = TRUE;
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ return C_CONTINUE; //Stop moving end point
+ } else return C_CONTINUE;
+ }
}
- if ((ac>=cb) && (ac>=ab)) { //Closer to far end and as long as the track
- pos = GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]); //Make other end of track
+ // Stop the user extending right through the other track
+ if (Da.ep[sel]>=0 && QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY)) { //For non-turnouts
+ if ((!QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS)) // Not Turntable - may not be needed
+ && (!QueryTrack(Da.trk[sel],Q_HAS_VARIABLE_ENDPOINTS))) { // Not Helix or a Circle
+ DIST_T ab = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]));
+ DIST_T ac = FindDistance(GetTrkEndPos(Da.trk[sel],Da.ep[sel]),pos);
+ DIST_T cb = FindDistance(GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]),pos);
+ if (cb<minLength) {
+ InfoMessage(_("Too close to other end of selected Track"));
+ return C_CONTINUE;
+ }
+ if ((ac>=cb) && (ac>=ab)) { //Closer to far end and as long as the track
+ pos = GetTrkEndPos(Da.trk[sel],1-Da.ep[sel]); //Make other end of track
+ }
+ }
+ } else if (Da.ep[sel]>=0 && inside) { //Has a point and inside track
+ InfoMessage(_("Can't move end inside a turnout")); //Turnouts are stuck to end-point
+ Da.pos[sel] = pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
+ return C_CONTINUE;
}
}
- }
- }
- DrawTempCornu(); //wipe out old
- Da.extend[sel] = FALSE;
- if(!Da.trk[sel]) { //Cornu with no ends
- struct extraData *xx = GetTrkExtraData(Da.selectTrack);
- Da.pos[sel] = xx->cornuData.pos[sel]; //Re-Copy parms from old trk
- Da.radius[sel] = xx->cornuData.r[sel];
- Da.angle[sel] = xx->cornuData.a[sel];
- Da.center[sel] = xx->cornuData.c[sel];
- if (Da.radius[sel] == 0) { //Straight
- Da.extendSeg[sel].type = SEG_STRTRK;
- Da.extendSeg[sel].width = 0;
- Da.extendSeg[sel].color = wDrawColorBlack;
- Da.extendSeg[sel].u.l.pos[1-sel] = Da.pos[sel];
- d = FindDistance( Da.extendSeg[sel].u.l.pos[1-sel], pos );
- a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel]));
- if (cos(D2R(a))<=0) {
- Translate( &Da.extendSeg[sel].u.l.pos[sel],
- Da.extendSeg[sel].u.l.pos[1-sel],
- Da.angle[sel], - d * cos(D2R(a)));
- pos = Da.extendSeg[sel].u.l.pos[1-sel];
- Da.extend[sel] = TRUE;
- }
- } else { //Curve
- Da.extendSeg[sel].type = SEG_CRVTRK;
- Da.extendSeg[sel].width = 0;
- Da.extendSeg[sel].color = wDrawColorBlack;
- Da.extendSeg[sel].u.c.center = Da.center[sel];
- Da.extendSeg[sel].u.c.radius = Da.radius[sel];
- a = FindAngle( Da.center[sel], pos );
- PointOnCircle( &pos, Da.center[sel], Da.radius[sel], a );
- a2 = FindAngle(Da.center[sel],Da.pos[sel]);
- if (((Da.angle[sel] < 180) && (a2>90 && a2<270)) ||
- ((Da.angle[sel] > 180) && (a2<90 || a2>270))) {
- Da.extendSeg[sel].u.c.a0 = a;
- Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a);
+ if(!Da.trk[sel]) { //Cornu with no end
+ if (((MyGetKeyState() & WKEY_SHIFT) != 0) && Da.selectTrack) { //Extend end locked
+ SetUpCornuParms(&cp);
+ CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,FALSE);
+ struct extraData *xx = GetTrkExtraData(Da.selectTrack);
+ if (Da.radius[sel] == 0) { //Straight
+ Da.extendSeg[sel].type = SEG_STRTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ Da.extendSeg[sel].u.l.pos[1-sel] = Da.pos[sel];
+ d = FindDistance( Da.extendSeg[sel].u.l.pos[1-sel], pos );
+ a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel]));
+ if (cos(D2R(a))<=0) {
+ Translate( &Da.extendSeg[sel].u.l.pos[sel],
+ Da.extendSeg[sel].u.l.pos[1-sel],
+ Da.angle[sel], - d * cos(D2R(a)));
+ pos = Da.extendSeg[sel].u.l.pos[sel];
+ Da.extend[sel] = TRUE;
+ } else Da.extend[sel] = FALSE;
+ } else { //Curve
+ Da.extendSeg[sel].type = SEG_CRVTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ Da.extendSeg[sel].u.c.center = Da.center[sel];
+ Da.extendSeg[sel].u.c.radius = Da.radius[sel];
+ a = FindAngle( Da.center[sel], pos );
+ PointOnCircle( &pos, Da.extendSeg[sel].u.c.center, Da.radius[sel], a );
+ a2 = FindAngle(Da.extendSeg[sel].u.c.center,Da.pos[sel]);
+ if (((Da.angle[sel] < 180) && (a2>90 && a2<270)) ||
+ ((Da.angle[sel] > 180) && (a2<90 || a2>270))) {
+ Da.extendSeg[sel].u.c.a0 = a;
+ Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a);
+ } else {
+ Da.extendSeg[sel].u.c.a0 = a2;
+ Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2);
+ }
+ if (Da.extendSeg[sel].u.c.a1 == 0 || Da.extendSeg[sel].u.c.a1 >180 )
+ Da.extend[sel] = FALSE;
+ else
+ Da.extend[sel] = TRUE;
+ }
} else {
- Da.extendSeg[sel].u.c.a0 = a2;
- Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2);
- }
- if (Da.extendSeg[sel].u.c.a1 == 0 || Da.extendSeg[sel].u.c.a1 >180 )
Da.extend[sel] = FALSE;
- else
- Da.extend[sel] = TRUE;
- }
- if (Da.extend[sel] == FALSE) { // Not extending - so trim along our own Cornu
- GetCornuParmsNear(Da.selectTrack, sel, &pos, &Da.center[sel], &Da.angle[sel], &Da.radius[sel] );
- Da.pos[sel] = pos;
- }
- } else { //Cornu with ends
- if (inside) Da.pos[sel] = pos;
- if (!GetConnectedTrackParms(Da.trk[sel],pos,sel,Da.ep[sel])) {
- DrawTempCornu();
- wBeep();
- return C_CONTINUE; //Stop drawing
- }
- CorrectHelixAngles();
- if (!inside) { //Extend the track
- if (Da.trackType[sel] == curveTypeStraight) { //Extend with a straight
- Da.extendSeg[sel].type = SEG_STRTRK;
- Da.extendSeg[sel].width = 0;
- Da.extendSeg[sel].color = wDrawColorBlack;
- if (Da.ep[sel]>=0) {
- Da.extendSeg[sel].u.l.pos[0] = GetTrkEndPos( Da.trk[sel], Da.ep[sel] );
- a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,GetTrkEndPos(Da.trk[sel],Da.ep[sel])));
- } else { //Turntable when unconnected
- Da.extendSeg[sel].u.l.pos[0] = Da.pos[sel];
- a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel]));
+ coOrd offset; //Just move end (no shift)
+ offset.x = pos.x-Da.pos[sel].x;
+ offset.y = pos.y-Da.pos[sel].y;
+ Da.pos[sel] = pos;
+ if (Da.radius[sel] >0.0) {
+ Da.center[sel].x += offset.x;
+ Da.center[sel].y += offset.y;
}
- // Remove any extend in opposite direction for Turntable/Turnouts
- if ((QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS) && Da.ep[sel]>=0)
- && (!QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY))
- && (a>90 && a<270)) {
- Da.extend[sel] = FALSE; //Turntable with point and extension is other side of well
- Da.pos[sel] = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
- } else {
- Da.extend[sel] = TRUE;
- d = FindDistance( Da.extendSeg[sel].u.l.pos[0], pos );
- Translate( &Da.extendSeg[sel].u.l.pos[1],
- Da.extendSeg[sel].u.l.pos[0],
- Da.angle[sel], -d * cos(D2R(a)));
- Da.pos[sel] = pos = Da.extendSeg[sel].u.l.pos[1];
+ if (Da.selectTrack) { //We have track
+ if (!Da.trk[sel] && ((t = OnTrackIgnore(&pos,FALSE,TRUE,Da.selectTrack))!= NULL) ) {
+ if ((ep = PickUnconnectedEndPointSilent(pos,t))>=0) {
+ pos = GetTrkEndPos(t,ep);
+ if (IsClose(FindDistance(pos,pos)/2)) {
+ CreateCornuEndAnchor(pos,FALSE);
+ }
+ }
+ }
+ } else { //Not yet a track
+ coOrd p = pos;
+ Da.angle[sel] = GetOpenAngle(Da.pos,Da.angle,sel);
+ if ((t = OnTrack(&p,FALSE,TRUE)) !=NULL ) {
+ if ((ep = PickUnconnectedEndPointSilent(pos,t))>=0) {
+ p = GetTrkEndPos(t,ep);
+ if (IsClose(FindDistance(p,pos)/2)) {
+ CreateCornuEndAnchor(p,FALSE);
+ }
+ }
+ }
}
- } else if (Da.trackType[sel] == curveTypeCurve) { //Extend with temp curve
- Da.extendSeg[sel].type = SEG_CRVTRK;
- Da.extendSeg[sel].width = 0;
- Da.extendSeg[sel].color = wDrawColorBlack;
- Da.extendSeg[sel].u.c.center = Da.center[sel];
- Da.extendSeg[sel].u.c.radius = Da.radius[sel];
- a = FindAngle( Da.center[sel], pos );
- PointOnCircle( &pos, Da.center[sel], Da.radius[sel], a );
- a2 = FindAngle(Da.center[sel],GetTrkEndPos(Da.trk[sel],Da.ep[sel]));
- if ((Da.angle[sel] < 180 && (a2>90 && a2 <270)) ||
- (Da.angle[sel] > 180 && (a2<90 || a2 >270))) {
- Da.extendSeg[sel].u.c.a0 = a2;
- Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2);
- } else {
- Da.extendSeg[sel].u.c.a0 = a;
- Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a);
+ }
+ } else { //Cornu with ends
+ if (inside) Da.pos[sel] = pos;
+ if (!GetConnectedTrackParms(Da.trk[sel],pos,sel,Da.ep[sel],inside?FALSE:TRUE)) {
+ wBeep();
+ return C_CONTINUE; //Stop drawing
+ }
+ CorrectHelixAngles();
+ if (!inside) { //Extend the track
+ if (Da.trackType[sel] == curveTypeStraight) { //Extend with a straight
+ Da.extendSeg[sel].type = SEG_STRTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ if (Da.ep[sel]>=0) {
+ Da.extendSeg[sel].u.l.pos[0] = GetTrkEndPos( Da.trk[sel], Da.ep[sel] );
+ a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,GetTrkEndPos(Da.trk[sel],Da.ep[sel])));
+ } else { //Turntable when unconnected
+ Da.extendSeg[sel].u.l.pos[0] = Da.pos[sel];
+ a = NormalizeAngle(Da.angle[sel]-FindAngle(pos,Da.pos[sel]));
+ }
+ // Remove any extend in opposite direction for Turntable/Turnouts
+ if ((QueryTrack(Da.trk[sel],Q_CAN_ADD_ENDPOINTS) && Da.ep[sel]>=0)
+ && (!QueryTrack(Da.trk[sel],Q_CORNU_CAN_MODIFY))
+ && (a>90 && a<270)) {
+ Da.extend[sel] = FALSE; //Turntable with point and extension is other side of well
+ Da.pos[sel] = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ } else {
+ Da.extend[sel] = TRUE;
+ d = FindDistance( Da.extendSeg[sel].u.l.pos[0], pos );
+ Translate( &Da.extendSeg[sel].u.l.pos[1],
+ Da.extendSeg[sel].u.l.pos[0],
+ Da.angle[sel], -d * cos(D2R(a)));
+ Da.pos[sel] = pos = Da.extendSeg[sel].u.l.pos[1];
+ }
+ } else if (Da.trackType[sel] == curveTypeCurve) { //Extend with temp curve
+ Da.extendSeg[sel].type = SEG_CRVTRK;
+ Da.extendSeg[sel].width = 0;
+ Da.extendSeg[sel].color = wDrawColorBlack;
+ Da.extendSeg[sel].u.c.center = Da.center[sel];
+ Da.extendSeg[sel].u.c.radius = Da.radius[sel];
+ a = FindAngle( Da.center[sel], pos );
+ PointOnCircle( &pos, Da.center[sel], Da.radius[sel], a );
+ a2 = FindAngle(Da.center[sel],GetTrkEndPos(Da.trk[sel],Da.ep[sel]));
+ if ((Da.angle[sel] < 180 && (a2>90 && a2 <270)) ||
+ (Da.angle[sel] > 180 && (a2<90 || a2 >270))) {
+ Da.extendSeg[sel].u.c.a0 = a2;
+ Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a-a2);
+ } else {
+ Da.extendSeg[sel].u.c.a0 = a;
+ Da.extendSeg[sel].u.c.a1 = NormalizeAngle(a2-a);
+ }
+ if (Da.extendSeg[sel].u.c.a1 == 0.0 || Da.extendSeg[sel].u.c.a1 >180
+ || (Da.extendSeg[sel].u.c.a0 >= Da.arcA0[sel] && Da.extendSeg[sel].u.c.a0 < Da.arcA0[sel]+Da.arcA1[sel]
+ && Da.extendSeg[sel].u.c.a0 + Da.extendSeg[sel].u.c.a1 <= Da.arcA0[sel] + Da.arcA1[sel])
+ ) {
+ Da.extend[sel] = FALSE;
+ Da.pos[sel] = pos;
+ } else {
+ Da.extend[sel] = TRUE;
+ Da.pos[sel] = pos;
+ }
+
+ } else { //Bezier and Cornu that we are joining TO can't extend
+ wBeep();
+ InfoMessage(_("Can't extend connected Bezier or Cornu"));
+ pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
+ return C_CONTINUE;
}
- if (Da.extendSeg[sel].u.c.a1 == 0.0 || Da.extendSeg[sel].u.c.a1 >180
- || (Da.extendSeg[sel].u.c.a0 >= Da.arcA0[sel] && Da.extendSeg[sel].u.c.a0 < Da.arcA0[sel]+Da.arcA1[sel]
- && Da.extendSeg[sel].u.c.a0 + Da.extendSeg[sel].u.c.a1 <= Da.arcA0[sel] + Da.arcA1[sel])
- ) {
- Da.extend[sel] = FALSE;
- Da.pos[sel] = pos;
- } else {
- Da.extend[sel] = TRUE;
- Da.pos[sel] = pos;
+ } else Da.pos[sel] = pos;
+ }
+ } else if (Da.selectMidPoint >=0){
+ DYNARR_N(coOrd,Da.mid_points,Da.selectMidPoint) = pos;
+ } else if (Da.selectEndHandle >=0) { //Cornu has no end, so has handles
+ int end = Da.selectEndHandle/2;
+ if (Da.selectEndHandle%2 == 0) { //Radius
+ coOrd p0 = Da.pos[end]; //Start
+ coOrd p1 = Da.endHandle[end].end_curve; //End
+ ANGLE_T a0 = FindAngle( p1, p0 );
+ DIST_T d0 = FindDistance( p0, p1 )/2.0; //Distance to Middle of Chord
+ coOrd pos2 = pos; //New pos
+ Rotate( &pos2, p1, -a0 );
+ pos2.x -= p1.x; //Deflection at right angles to Chord
+ DIST_T r = 1000.0;
+ if ( fabs(pos2.x) >= 0.01 ) { //Not zero
+ double d2 = sqrt( d0*d0 + pos2.x*pos2.x )/2.0;
+ r = d2*d2*2.0/pos2.x;
+ if ( fabs(r) > 1000.0 ) { //Limit Radius
+ r = 0.0;
+ //r = ((r > 0) ? 1 : -1 ) *1000.0;
}
-
- } else { //Bezier and Cornu that we are joining TO can't extend
- DrawTempCornu(); //put back
- wBeep();
- InfoMessage(_("Can't extend connected Bezier or Cornu"));
- pos = GetTrkEndPos(Da.trk[sel],Da.ep[sel]);
- return C_CONTINUE;
+ } else {
+ r = 0.0;
+ //r = ((r > 0) ? 1 : -1 ) *1000.0;
}
+ coOrd posx; //Middle of chord
+ posx.x = (p1.x-p0.x)/2.0 + p0.x;
+ posx.y = (p1.y-p0.y)/2.0 + p0.y;
+ a0 -= 90.0;
+ if (r<0) { //Negative radius means other side
+ coOrd pt = p0;
+ p0 = p1;
+ p1 = pt;
+ a0 += 180.0;
+ }
+ coOrd pc;
+ if (r == 0.0) {
+ Da.center[end] = zero;
+ Da.radius[end] = 0.0;
+ Da.angle[end] = FindAngle(Da.pos[end],Da.endHandle[end].end_curve);
+ } else {
+ Translate( &pc, posx, a0, fabs(r) - fabs(pos2.x) ); //Move Radius less Deflection to get to center
+ Da.center[end] = pc;
+ if (DifferenceBetweenAngles(FindAngle(Da.center[end],Da.pos[end]),FindAngle(Da.center[end],Da.endHandle[end].end_curve))>0.0)
+ Da.angle[end] = NormalizeAngle(FindAngle(Da.center[end],Da.pos[end])+90.0);
+ else
+ Da.angle[end] = NormalizeAngle(FindAngle(Da.center[end],Da.pos[end])-90.0);
+ Da.radius[end] = fabs(r);
+ }
+ } else {
+ Da.angle[end] = FindAngle(Da.pos[end],pos);
+ Da.radius[end] = 0.0;
+ Translate(&Da.center[end],Da.pos[end],NormalizeAngle(Da.angle[end]+90.0),Da.radius[end]);
}
}
-
- CreateBothEnds(Da.selectPoint);
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
SetUpCornuParms(&cp); //In case we want to use these because the ends are not on the track
-
- if (CallCornu(Da.pos, Da.trk, Da.ep, &Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
else Da.crvSegs_da_cnt = 0;
+ for (int i=0;i<2;i++) {
+ if (Da.trk[i] || Da.ends[i]) continue;
+ coOrd p = Da.pos[i];
+ Da.angle[i] = NormalizeAngle((i?0:180)+GetAngleSegs( Da.crvSegs_da_cnt, Da.crvSegs_da.ptr, &p, NULL, NULL, NULL, NULL, NULL));
+ Da.radius[i] = 0.0;
+ }
Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
DIST_T rin = Da.radius[0];
InfoMessage( _("Cornu : Min Radius=%s MaxRateofCurveChange/Scale=%s Length=%s Winding Arc=%s"),
@@ -731,25 +1580,121 @@ EXPORT STATUS_T AdjustCornuCurve(
FormatFloat(CornuMaxRateofChangeofCurvature(Da.pos,Da.crvSegs_da,&rin)*GetScaleRatio(GetLayoutCurScale())),
FormatDistance(CornuLength(Da.pos,Da.crvSegs_da)),
FormatDistance(CornuTotalWindingArc(Da.pos,Da.crvSegs_da)));
- DrawTempCornu();
return C_CONTINUE;
case C_UP:
- if (Da.state != POINT_PICKED) return C_CONTINUE;
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (Da.state != POINT_PICKED) {
+ Da.state = PICK_POINT;
+ return C_CONTINUE;
+ }
ep = 0;
- DrawTempCornu(); //wipe out
- Da.selectPoint = -1;
- CreateBothEnds(Da.selectPoint);
+ if (Da.selectMidPoint!=-1) Da.prevSelected = Da.selectMidPoint;
+ else if (Da.selectEndPoint!=-1) {
+ if (!Da.trk[Da.selectEndPoint] &&
+ (t=OnTrack(&pos,FALSE,TRUE)) != NULL && t != Da.selectTrack ) {
+ EPINX_T ep = PickUnconnectedEndPoint(pos,t);
+ if (ep>=0) {
+ if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where
+ if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) {
+ InfoMessage(_("Helix Already Connected"));
+ return C_CONTINUE;
+ }
+ ep = -1; //Not a real ep yet
+ } else ep = PickUnconnectedEndPointSilent(pos, t); //EP
+ if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) {
+ ep=-1; //Don't attach to Turntable
+ trackParams_t tp;
+ if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE;
+ ANGLE_T a = tp.angle;
+ Translate(&pos,tp.ttcenter,a,tp.ttradius);
+ }
+ if ( ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle
+ wBeep();
+ InfoMessage(_("No Valid end point on that track"));
+ return C_CONTINUE;
+ }
+ if (GetTrkScale(t) != (char)GetLayoutCurScale()) {
+ wBeep();
+ InfoMessage(_("Track is different scale"));
+ return C_CONTINUE;
+ }
+ }
+ if (ep>=0 && t) { //Real end point, real track
+ Da.trk[Da.selectEndPoint] = t;
+ Da.ep[Da.selectEndPoint] = ep; // Note: -1 for Turntable or Circle
+ pos = GetTrkEndPos(t,ep);
+ Da.pos[Da.selectEndPoint] = pos;
+ if (!GetConnectedTrackParms(t,pos,Da.selectEndPoint,ep,FALSE)) return C_CONTINUE;
+ }
+ } else {
+ cornuModCmdContext.angle = NormalizeAngle(Da.angle[Da.selectEndPoint]);
+ cornuModCmdContext.radius = Da.radius[Da.selectEndPoint];
+ if (DifferenceBetweenAngles(FindAngle(Da.center[Da.selectEndPoint],Da.pos[Da.selectEndPoint]),Da.angle[Da.selectEndPoint])<0.0)
+ cornuModCmdContext.radius = -cornuModCmdContext.radius;
+ controls[0] = cornuModEndRadiusPD.control;
+ controls[1] = cornuModEndAnglePD.control;
+ controls[2] = NULL;
+ labels[0] = N_("End Radius");
+ labels[1] = N_("End Angle");
+ ParamLoadControls( &cornuModPG );
+ InfoSubstituteControls( controls, labels );
+ cornuModEndRadiusPD.option &= ~PDO_NORECORD;
+ cornuModEndAnglePD.option &= ~PDO_NORECORD;
+ infoSubst = TRUE;
+ Da.prevSelected = Da.selectEndPoint;
+ Da.selectEndHandle = -1;
+ }
+ } else if (Da.selectEndHandle!=-1) {
+ Da.prevSelected = Da.selectEndHandle>2?1:0;
+ cornuModCmdContext.angle = NormalizeAngle(Da.angle[Da.prevSelected]);
+ cornuModCmdContext.radius = Da.radius[Da.prevSelected];
+ if (DifferenceBetweenAngles(FindAngle(Da.center[Da.prevSelected],Da.pos[Da.prevSelected]),Da.angle[Da.prevSelected])<0.0)
+ cornuModCmdContext.radius = -cornuModCmdContext.radius;
+ controls[0] = cornuModEndRadiusPD.control;
+ controls[1] = cornuModEndAnglePD.control;
+ controls[2] = NULL;
+ labels[0] = N_("End Radius");
+ labels[1] = N_("End Angle");
+ ParamLoadControls( &cornuModPG );
+ InfoSubstituteControls( controls, labels );
+ cornuModEndRadiusPD.option &= ~PDO_NORECORD;
+ cornuModEndAnglePD.option &= ~PDO_NORECORD;
+ infoSubst = TRUE;
+ Da.selectEndHandle = -1;
+ }
+ Da.selectEndPoint = -1; Da.selectMidPoint = -1;
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
SetUpCornuParms(&cp);
- if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da,&cp)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
else Da.crvSegs_da_cnt = 0;
Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
- InfoMessage(_("Pick on point to adjust it along track - Enter to confirm, ESC to abort"));
- DrawTempCornu();
+ InfoMessage(_("Pick on point to adjust it along track - Delete to remove, Enter to confirm, ESC to abort"));
Da.state = PICK_POINT;
return C_CONTINUE;
+ case C_TEXT:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ //Delete or backspace deletes last selected index
+ if (action>>8 == 127 || action>>8 == 8) {
+ if ((Da.state == PICK_POINT) && Da.prevSelected !=-1) {
+ for (int i=Da.prevSelected;i<Da.mid_points.cnt;i++) {
+ DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i+1);
+ }
+ Da.mid_points.cnt--;
+ }
+ Da.prevSelected = -1;
+ CreateBothEnds(Da.selectEndPoint,Da.selectMidPoint,Da.selectEndHandle,Da.prevSelected);
+ cornuParm_t cp;
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ return C_CONTINUE;
+ }
+ return C_CONTINUE;
+
case C_OK: //C_OK is not called by Modify.
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( Da.state == PICK_POINT ) {
Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
if (CornuTotalWindingArc(Da.pos,Da.crvSegs_da)>4*360) {
@@ -762,63 +1707,109 @@ EXPORT STATUS_T AdjustCornuCurve(
return C_CONTINUE;
}
for (int i=0;i<2;i++) {
- if (!(QueryTrack(Da.trk[i],Q_CAN_ADD_ENDPOINTS))) { // Not Turntable
+ if (Da.trk[i] && !(QueryTrack(Da.trk[i],Q_CAN_ADD_ENDPOINTS))) { // Not Turntable
if (FindDistance(Da.pos[i],GetTrkEndPos(Da.trk[i],1-Da.ep[i])) < minLength) {
wBeep();
- InfoMessage(_("Cornu end %d too close to other end of connect track - reposition it"),i+1);
+ InfoMessage(_("Cornu point %d too close to other end of connect track - reposition it"),i+1);
return C_CONTINUE;
}
}
}
-
- DrawTempCornu();
- UndoStart( _("Create Cornu"),"newCornu curve");
- t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius,(trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt);
- if (t==NULL) {
- wBeep();
- InfoMessage(_("Cornu Create Failed for p1[%0.3f,%0.3f] p2[%0.3f,%0.3f], c1[%0.3f,%0.3f] c2[%0.3f,%0.3f], a1=%0.3f a2=%0.3f, r1=%s r2=%s"),
- Da.pos[0].x,Da.pos[0].y,
- Da.pos[1].x,Da.pos[1].y,
- Da.center[0].x,Da.center[0].y,
- Da.center[1].x,Da.center[1].y,
- Da.angle[0],Da.angle[1],
- FormatDistance(Da.radius[0]),FormatDistance(Da.radius[1]));
- return C_TERMINATE;
+ UndoStart( _("Create Cornu"),"newCornu curves");
+ BOOL_T end_point[2];
+ end_point[0] = TRUE;
+ end_point[1] = FALSE;
+ coOrd sub_pos[2];
+ sub_pos[0] = Da.pos[0];
+ if (Da.radius[0] == -1) end_point[0] = FALSE;
+ track_p first_trk= NULL,trk1=NULL,trk2 = NULL;
+
+ for (int i=0;i<Da.mid_points.cnt;i++) {
+ sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i);
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point))== NULL) return C_TERMINATE;
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]) {
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ DrawNewTrack(trk1);
+ if (first_trk == NULL) first_trk = trk1;
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ trk2 = trk1;
+ end_point[0] = FALSE;
+ sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i);
}
-
- CopyAttributes( Da.trk[0], t );
+ sub_pos[1] = Da.pos[1];
+ end_point[1] = TRUE;
+ if (Da.radius[1] == -1) end_point[1] = FALSE;
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == NULL) return C_TERMINATE;
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]){
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ if (first_trk == NULL) first_trk = trk1;
+ //t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius,(trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt);
for (int i=0;i<2;i++) {
- UndoModify(Da.trk[i]);
- MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0);
- if ((GetTrkType(Da.trk[i])==T_BEZIER) || (GetTrkType(Da.trk[i])==T_CORNU)) { //Bezier split position not precise, so readjust Cornu
- GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i]);
+ if (Da.trk[i]) {
+ UndoModify(Da.trk[i]);
+ MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0);
+ //End position not precise, so readjust Cornu
+ GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i],FALSE);
ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180);
- SetCornuEndPt(t,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
+ SetCornuEndPt(i==0?first_trk:trk1,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
+ if (Da.ep[i]>=0)
+ ConnectTracks(Da.trk[i],Da.ep[i],i==0?first_trk:trk1,i);
}
- if (Da.ep[i]>=0)
- ConnectTracks(Da.trk[i],Da.ep[i],t,i);
}
UndoEnd();
- DrawNewTrack(t);
+ if (infoSubst) {
+ InfoSubstituteControls( NULL, NULL );
+ infoSubst = FALSE;
+ }
Da.state = NONE;
- MainRedraw();
- MapRedraw();
return C_TERMINATE;
}
return C_CONTINUE;
case C_REDRAW:
+ if (Da.state == NONE) return C_CONTINUE;
DrawTempCornu();
+ if (anchors_da.cnt) {
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ }
return C_CONTINUE;
+ case C_CANCEL:
+ case C_FINISH:
+ break;
default:
return C_CONTINUE;
}
+ return C_CONTINUE;
}
+static void cornuModDlgUpdate(
+ paramGroup_p pg,
+ int inx,
+ void * valueP )
+{
+ AdjustCornuCurve(C_UPDATE, zero, InfoMessage);
+ ParamLoadControl(&cornuModPG,cornuModEndRadius); // Make sure Radius updated
+ ParamLoadControl(&cornuModPG,cornuModEndAngle); //Relative Angle as well
+ TempRedraw();
+
+}
/**
* CmdCornuModify
@@ -835,11 +1826,12 @@ EXPORT STATUS_T AdjustCornuCurve(
*
*/
STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG ) {
- track_p t;
struct extraData *xx = GetTrkExtraData(trk);
Da.trackGauge = trackG;
+ Da.commandType = CORNU_MODIFY;
+
switch (action&0xFF) {
case C_START:
Da.state = NONE;
@@ -847,42 +1839,90 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
Da.ep1Segs_da_cnt = 0;
Da.ep2Segs_da_cnt = 0;
Da.crvSegs_da_cnt = 0;
+ Da.midSegs.cnt = 0;
Da.extend[0] = FALSE;
Da.extend[1] = FALSE;
- Da.selectPoint = -1;
+ Da.selectEndPoint = -1;
Da.selectTrack = NULL;
+ DYNARR_RESET(coOrd,Da.mid_points);
+ DYNARR_RESET(track_p,Da.tracks);
Da.selectTrack = trk;
+ DYNARR_APPEND(track_p,Da.tracks,1);
+ DYNARR_LAST(track_p,Da.tracks) = trk;
Da.trk[0] = GetTrkEndTrk( trk, 0 );
+ track_p prior = trk;
if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk);
- Da.trk[1] = GetTrkEndTrk( trk, 1 );
- if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk);
+ EPINX_T ep0 = 0;
+ //Move down the LHS adding tracks until no more Cornu
+ while (Da.trk[0] && QueryTrack(Da.trk[0],Q_IS_CORNU)) {
+ prior = Da.trk[0];
+ ep0 = 1-Da.ep[0];
+ DYNARR_APPEND(track_p,Da.tracks,1);
+ DYNARR_LAST(track_p,Da.tracks) = prior;
+ DYNARR_APPEND(coOrd,Da.mid_points,1);
+ for (int i=Da.mid_points.cnt-1;i>0;i--) {
+ DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i-1);
+ }
+ DYNARR_N(coOrd,Da.mid_points,0) = GetTrkEndPos(prior,1-ep0);
+ Da.trk[0] = GetTrkEndTrk( prior, ep0 );
+ if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],prior);
+ else Da.ep[0] = -1;
+ }
+ if (prior) {
+ struct extraData *xx0 = GetTrkExtraData(prior);
+ Da.pos[0] = xx0->cornuData.pos[ep0]; //Copy parms from FIRST CORNU trk
+ Da.radius[0] = xx0->cornuData.r[ep0];
+ Da.angle[0] = xx0->cornuData.a[ep0];
+ Da.center[0] = xx0->cornuData.c[ep0];
+ }
- for (int i=0;i<2;i++) {
- Da.pos[i] = xx->cornuData.pos[i]; //Copy parms from old trk
- Da.radius[i] = xx->cornuData.r[i];
- Da.angle[i] = xx->cornuData.a[i];
- Da.center[i] = xx->cornuData.c[i];
- }
+ //Move to RHS
+ Da.trk[1] = GetTrkEndTrk( trk, 1 );
+ track_p next = trk;
+ EPINX_T ep1 = 1;
+ if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk);
+ //Move down RHS adding tracks until no more Cornu
+ while (Da.trk[1] && QueryTrack(Da.trk[1],Q_IS_CORNU)) {
+ next = Da.trk[1];
+ ep1 = 1-Da.ep[1];
+ DYNARR_APPEND(track_p,Da.tracks,1);
+ DYNARR_LAST(track_p,Da.tracks) = next;
+ DYNARR_APPEND(coOrd,Da.mid_points,1);
+ DYNARR_LAST(coOrd,Da.mid_points) = GetTrkEndPos(next,1-ep1);
+ Da.trk[1] = GetTrkEndTrk( next, ep1 );
+ if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],next);
+ }
- if ((Da.trk[0] && (!QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[0],Q_CAN_EXTEND))) &&
- (Da.trk[1] && (!QueryTrack(Da.trk[1],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[1],Q_CAN_EXTEND)))) {
- wBeep();
- ErrorMessage("Both Ends of this Cornu are UnAdjustable");
- return C_TERMINATE;
- }
+ if (next) {
+ struct extraData *xx1 = GetTrkExtraData(next);
+ Da.pos[1] = xx1->cornuData.pos[ep1]; //Copy parms from LAST CORNU trk
+ Da.radius[1] = xx1->cornuData.r[ep1];
+ Da.angle[1] = xx1->cornuData.a[ep1];
+ Da.center[1] = xx1->cornuData.c[ep1];
+ }
- InfoMessage(_("Track picked - now select a Point"));
+ InfoMessage(_("Now Select or Add (+Shift) a Point"));
Da.state = TRACK_SELECTED;
- DrawTrack(Da.selectTrack,&mainD,wDrawColorWhite); //Wipe out real track, draw replacement
+ for (int i=0;i<Da.tracks.cnt;i++) {
+ DrawTrack(DYNARR_N(track_p,Da.tracks,i),&mainD,wDrawColorWhite); //Wipe out real tracks, draw replacement
+ }
return AdjustCornuCurve(C_START, pos, InfoMessage);
+ case wActionMove:
+ return AdjustCornuCurve(wActionMove, pos, InfoMessage);
+ break;
+
case C_DOWN:
if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up
return AdjustCornuCurve(C_DOWN, pos, InfoMessage);
+ case C_LCLICK:
+ if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up
+ AdjustCornuCurve(C_DOWN, pos, InfoMessage);
+ return AdjustCornuCurve(C_UP, pos, InfoMessage);
case C_MOVE:
if (Da.state == TRACK_SELECTED) return C_CONTINUE; //Ignore until first up and down
@@ -895,10 +1935,19 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
return AdjustCornuCurve(C_UP, pos, InfoMessage); //Run Adjust
case C_TEXT:
- if ((action>>8) != 32)
+ //Delete or backspace deletes last selected index
+ if (action>>8 == 127 || action>>8 == 8) {
+ return AdjustCornuCurve(action, pos, InfoMessage);
+ }
+ //Space bar or enter means done
+ if ( (action>>8 != ' ') && (action>>8 != 13) )
return C_CONTINUE;
/* no break */
case C_OK:
+ if (infoSubst) {
+ InfoSubstituteControls( NULL, NULL );
+ infoSubst = FALSE;
+ }
if (Da.state != PICK_POINT) { //Too early - abandon
InfoMessage(_("No changes made"));
Da.state = NONE;
@@ -928,23 +1977,59 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
} else {
Da.trk[i] = NewCurvedTrack(Da.extendSeg[i].u.c.center,fabs(Da.extendSeg[i].u.c.radius),
Da.extendSeg[i].u.c.a0,Da.extendSeg[i].u.c.a1,FALSE);
-
- if (Da.angle[i]>180)
- Da.ep[i] = (Da.extendSeg[i].u.c.a0>90 && Da.extendSeg[i].u.c.a0<270)?0:1;
- else
- Da.ep[i] = (Da.extendSeg[i].u.c.a0>90 && Da.extendSeg[i].u.c.a0<270)?1:0;
+ if (FindDistance(GetTrkEndPos(Da.trk[i],0),Da.pos[i])<=connectDistance) {
+ Da.ep[i] = 0;
+ } else Da.ep[i] = 1;
}
if (!Da.trk[i]) {
wBeep();
InfoMessage(_("Cornu Extension Create Failed for end %d"),i);
+ Da.state = NONE;
return C_TERMINATE;
}
}
}
-
- t = NewCornuTrack( Da.pos, Da.center, Da.angle, Da.radius, (trkSeg_p)Da.crvSegs_da.ptr, Da.crvSegs_da.cnt);
- if (t==NULL) {
+ BOOL_T end_point[2];
+ end_point[0] = TRUE;
+ end_point[1] = FALSE;
+ coOrd sub_pos[2];
+ sub_pos[0] = Da.pos[0];
+
+ track_p first_trk= NULL,trk1=NULL,trk2 = NULL;
+ for (int i=0;i<Da.mid_points.cnt;i++) {
+ sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i);
+ if ((trk1 = CreateCornuFromPoints(sub_pos, end_point))== NULL) {
+ wBeep();
+ InfoMessage(_("Cornu Create Failed for p1[%0.3f,%0.3f] p2[%0.3f,%0.3f], c1[%0.3f,%0.3f] c2[%0.3f,%0.3f], a1=%0.3f a2=%0.3f, r1=%s r2=%s"),
+ Da.pos[0].x,Da.pos[0].y,
+ Da.pos[1].x,Da.pos[1].y,
+ Da.center[0].x,Da.center[0].y,
+ Da.center[1].x,Da.center[1].y,
+ Da.angle[0],Da.angle[1],
+ FormatDistance(Da.radius[0]),FormatDistance(Da.radius[1]));
+ UndoUndo();
+ Da.state = NONE;
+ return C_TERMINATE;
+ }
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]) {
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ DrawNewTrack(trk1);
+ if (first_trk == NULL) first_trk = trk1;
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ trk2 = trk1;
+ end_point[0] = FALSE;
+ sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i);
+ }
+ sub_pos[1] = Da.pos[1];
+ end_point[1] = TRUE;
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == NULL) {
wBeep();
InfoMessage(_("Cornu Create Failed for p1[%0.3f,%0.3f] p2[%0.3f,%0.3f], c1[%0.3f,%0.3f] c2[%0.3f,%0.3f], a1=%0.3f a2=%0.3f, r1=%s r2=%s"),
Da.pos[0].x,Da.pos[0].y,
@@ -954,15 +2039,26 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
Da.angle[0],Da.angle[1],
FormatDistance(Da.radius[0]),FormatDistance(Da.radius[1]));
UndoUndo();
- MainRedraw();
- MapRedraw();
- //DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
+ Da.state = NONE;
return C_TERMINATE;
}
+ DrawNewTrack(trk1);
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]) {
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ if (first_trk == NULL) first_trk = trk1;
- CopyAttributes( trk, t );
+ Da.state = NONE; //Must do before Delete
- DeleteTrack(trk, TRUE);
+ for (int i=0;i<Da.tracks.cnt;i++) {
+ DeleteTrack(DYNARR_N(track_p,Da.tracks,i), TRUE);
+ }
if (Da.trk[0]) UndoModify(Da.trk[0]);
if (Da.trk[1]) UndoModify(Da.trk[1]);
@@ -970,13 +2066,12 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
for (int i=0;i<2;i++) { //Attach new track
if (Da.trk[i] && Da.ep[i] != -1) { //Like the old track
if (MoveEndPt(&Da.trk[i],&Da.ep[i],Da.pos[i],0)) {
- if (GetTrkType(Da.trk[i])==T_BEZIER) { //Bezier split position not precise, so readjust Cornu
- GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i]);
- ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180);
- SetCornuEndPt(t,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
- }
+ //Bezier split position not precise, so readjust Cornu
+ GetConnectedTrackParms(Da.trk[i],GetTrkEndPos(Da.trk[i],Da.ep[i]),i,Da.ep[i],FALSE);
+ ANGLE_T endAngle = NormalizeAngle(GetTrkEndAngle(Da.trk[i],Da.ep[i])+180);
+ SetCornuEndPt(i==0?first_trk:trk1,i,GetTrkEndPos(Da.trk[i],Da.ep[i]),Da.center[i],endAngle,Da.radius[i]);
if (Da.ep[i]>= 0)
- ConnectTracks(t,i,Da.trk[i],Da.ep[i]);
+ ConnectTracks(i==0?first_trk:trk1,i,Da.trk[i],Da.ep[i]);
} else {
UndoUndo();
wBeep();
@@ -986,18 +2081,18 @@ STATUS_T CmdCornuModify (track_p trk, wAction_t action, coOrd pos, DIST_T trackG
}
}
UndoEnd();
- MainRedraw();
- MapRedraw();
Da.state = NONE;
- //DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
+ //DYNARR_FREE(trkSeg_t,Da.crvSegs_da)
return C_TERMINATE;
case C_CANCEL:
InfoMessage(_("Modify Cornu Cancelled"));
Da.state = NONE;
+ if (infoSubst) {
+ InfoSubstituteControls( NULL, NULL );
+ infoSubst = FALSE;
+ }
//DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
- MainRedraw();
- MapRedraw();
return C_TERMINATE;
case C_REDRAW:
@@ -1028,6 +2123,22 @@ DIST_T CornuLength(coOrd pos[4],dynArr_t segs) {
return dd;
}
+DIST_T CornuOffsetLength(dynArr_t segs, double offset) {
+ DIST_T dd = 0.0;
+ if (segs.cnt == 0 ) return dd;
+ for (int i = 0;i<segs.cnt;i++) {
+ trkSeg_t t = DYNARR_N(trkSeg_t, segs, i);
+ if (t.type == SEG_CRVTRK || t.type == SEG_CRVLIN) {
+ dd += fabs((t.u.c.radius+(t.u.c.radius>0?offset:-offset))*D2R(t.u.c.a1));
+ } else if (t.type == SEG_BEZLIN || t.type == SEG_BEZTRK) {
+ dd +=CornuOffsetLength(t.bezSegs,offset);
+ } else if (t.type == SEG_STRLIN || t.type == SEG_STRTRK ) {
+ dd += FindDistance(t.u.l.pos[0],t.u.l.pos[1]);
+ }
+ }
+ return dd;
+}
+
DIST_T CornuMinRadius(coOrd pos[4],dynArr_t segs) {
DIST_T r = 100000.0, rr;
if (segs.cnt == 0 ) return r;
@@ -1081,6 +2192,9 @@ DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4], dynArr_t segs, DIST_T * las
return r_max;
}
+
+
+
/*
* Create a Cornu Curve Track
* Sequence is
@@ -1091,167 +2205,359 @@ DIST_T CornuMaxRateofChangeofCurvature(coOrd pos[4], dynArr_t segs, DIST_T * las
*/
STATUS_T CmdCornu( wAction_t action, coOrd pos )
{
- track_p t;
+ track_p t = NULL;
cornuParm_t cp;
- Da.color = lineColor;
+ Da.commandType = CORNU_CREATE;
+
Da.width = (double)lineWidth/mainD.dpi;
Da.trackGauge = trackGauge;
+ Da.selectTrack = NULL;
switch (action&0xFF) {
case C_START:
+ Da.cmdType = (long)commandContext;
Da.state = NONE;
- Da. selectPoint = -1;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ Da.endHandle[0].end_valid = FALSE;
+ Da.endHandle[1].end_valid = FALSE;
for (int i=0;i<2;i++) {
+ Da.ends[i] = FALSE;
Da.pos[i] = zero;
+ Da.angle[i] = 0.0;
+ Da.radius[i] = -1.0;
}
Da.trk[0] = Da.trk[1] = NULL;
//tempD.orig = mainD.orig;
-
DYNARR_RESET(trkSeg_t,Da.crvSegs_da);
Da.ep1Segs_da_cnt = 0;
Da.ep2Segs_da_cnt = 0;
+ Da.crvSegs_da_cnt = 0;
+ Da.midSegs.cnt = 0;
+ DYNARR_RESET(coOrd,Da.mid_points);
+ DYNARR_RESET(track_p,Da.tracks);
+ DYNARR_RESET(trkSeg_t,anchors_da);
Da.extend[0] = FALSE;
Da.extend[1] = FALSE;
- if (selectedTrackCount==0)
- InfoMessage( _("Left click - join with Cornu track") );
- else
- InfoMessage( _("Left click - join with Cornu track, Shift Left click - move to join") );
+ if (Da.cmdType == cornuCmdCreateTrack)
+ InfoMessage( _("Left click - Start Cornu track") );
+ else if (Da.cmdType == cornuCmdHotBar) {
+ InfoMessage( _("Left click - Place Flextrack") );
+ } else {
+ if (selectedTrackCount==0)
+ InfoMessage( _("Left click - join with Cornu track") );
+ else
+ InfoMessage( _("Left click - join with Cornu track, Shift Left click - move to join") );
+ }
return C_CONTINUE;
case C_DOWN:
+ DYNARR_RESET(trkSeg_t,anchors_da);
if ( Da.state == NONE || Da.state == LOC_2) { //Set the first or second point
coOrd p = pos;
- int end = Da.state==NONE?0:1;
- EPINX_T ep;
- if ((t = OnTrack(&p, FALSE, TRUE)) != NULL) {
- if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where
- if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) {
+ t = NULL;
+ int end = 0;
+ if (Da.state != NONE) end=1;
+ EPINX_T ep = -1;
+ //Lock to endpoint if one is available and under pointer
+ if ((t = OnTrack(&p, FALSE, TRUE)) != NULL && t != Da.selectTrack) {
+ if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where
+ if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) {
+ wBeep();
InfoMessage(_("Helix Already Connected"));
- return C_CONTINUE;
+ t= NULL;
}
ep = -1; //Not a real ep yet
- } else ep = PickUnconnectedEndPointSilent(p, t);
- if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) ep=-1; //Ignore Turntable Unconnected
- else if (ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle
- wBeep();
- InfoMessage(_("No Unconnected end point on that track"));
- return C_CONTINUE;
+ } else if (QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) {
+ ep=-1; //Don't attach to existing Turntable ep
+ trackParams_t tp;
+ if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE;
+ ANGLE_T a = tp.angle;
+ Translate(&pos,tp.ttcenter,a,tp.ttradius);
+ p = pos; //Fix to wall of turntable initially
+ } else ep = PickUnconnectedEndPointSilent(p, t); //EP
+ if ( t && ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle
+ wBeep();
+ InfoMessage(_("No valid open endpoint on that track"));
+ t = NULL;
+ }
+ if (t && GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) {
+ wBeep();
+ InfoMessage(_("Track is different gauge"));
+ t = NULL;
}
+ }
+ if (ep>=0 && t) { //Real end point, real track
Da.trk[end] = t;
Da.ep[end] = ep; // Note: -1 for Turntable or Circle
- if (ep ==-1) pos = p;
- else pos = GetTrkEndPos(t,ep);
+ pos = GetTrkEndPos(t,ep);
Da.pos[end] = pos;
- InfoMessage( _("Place 2nd end point of Cornu track on track with an unconnected end-point") );
- } else {
+ Da.angle[end] = GetTrkEndAngle(t,ep);
+ } else if (t == NULL) { //end not on Track, OK for CreateCornu -> empty end point
+ pos = p; //Reset to initial
+ SnapPos( &pos );
+ if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) {
+ Da.trk[end] = NULL;
+ Da.pos[end] = pos;
+ Da.radius[end] = -1.0; //No End Rad for open
+ if (Da.state == NONE ) {
+ Da.state = POS_1;
+ Da.angle[0] = 270.0;
+ Da.radius[0] = 0.0;
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,TRUE,TRUE,FALSE,Da.angle[0],Da.radius[0],zero,&Da.endHandle[0]);
+ Da.ep2Segs_da_cnt = 0;
+ InfoMessage( _("Drag arm in the direction of track") );
+ return C_CONTINUE;
+ }
+ Da.state = POS_2; //Now this is second end and it is open
+ Da.selectEndPoint = 1;
+ Da.mid_points.cnt=0;
+ Da.angle[1] = GetOpenAngle(Da.pos,Da.angle,1);
+ Da.radius[1] = 0.0;
+ CreateBothEnds(1,-1,-1,-1);
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE))
+ Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ InfoMessage( _("Drag arm in the direction of track") );
+ return C_CONTINUE;
+ }
wBeep();
- InfoMessage(_("No Unconnected Track End there"));
+ InfoMessage(_("No Unconnected Track End there")); //Not creating a Cornu - Join can't be open
return C_CONTINUE;
+ } else {
+ Da.pos[end] = p;
+ //Either a real end or a track but no end
}
if (Da.state == NONE) {
- if (!GetConnectedTrackParms(t, pos, 0, Da.ep[0])) {
+ if (!GetConnectedTrackParms(t, pos, 0, Da.ep[0],FALSE)) { //Must get parms
Da.trk[0] = NULL;
+ Da.ep[0] = -1;
+ wBeep();
+ InfoMessage(_("No Valid Track End there"));
return C_CONTINUE;
}
+ if (ep<0) {
+ Da.trk[0] = t;
+ Da.pos[0] = p;
+ Da.ep[0] = ep;
+ }
Da.state = POS_1;
- Da.selectPoint = 0;
- Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE, !QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY));
- DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
- InfoMessage( _("Move 1st end point of Cornu track along track 1") );
- } else {
- if ( Da.trk[0] == t) {
+ Da.selectEndPoint = 0; //Select first end point
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE, !QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY),
+ Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL);
+ InfoMessage( _("Locked - Move 1st end point of Cornu track along track 1") );
+ return C_CONTINUE;
+ } else { //Second Point
+ if (Da.trk[0] == t) {
ErrorMessage( MSG_JOIN_CORNU_SAME );
Da.trk[1] = NULL;
+ Da.ep[1] = -1;
return C_CONTINUE;
}
- if (!GetConnectedTrackParms(t, pos, 1, Da.ep[1])) {
+ if (!GetConnectedTrackParms(t, pos, 1, Da.ep[1],FALSE)) {
Da.trk[1] = NULL; //Turntable Fail
+ wBeep();
+ InfoMessage(_("No Valid Track End there"));
return C_CONTINUE;
}
+ if (ep<0) {
+ Da.trk[1] = t;
+ Da.pos[1] = p;
+ Da.ep[1] = -1;
+ Da.radius[1] = 0.0;
+ }
CorrectHelixAngles();
- Da.selectPoint = 1;
+ Da.selectEndPoint = 1; //Select second end point
Da.state = POINT_PICKED;
- DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack); //Wipe out initial Arm
- CreateBothEnds(1);
- if (CallCornu(Da.pos,Da.trk,Da.ep,&Da.crvSegs_da, &cp))
- Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
- DrawTempCornu();
- InfoMessage( _("Move 2nd end point of Cornu track along track 2") );
+ InfoMessage( _("Locked - Move 2nd end point of Cornu track along track 2") );
}
+ CreateBothEnds(1,-1,-1,-1);
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE))
+ Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
return C_CONTINUE;
- } else {
+ } else { //This is after both ends exist
return AdjustCornuCurve( action&0xFF, pos, InfoMessage );
}
return C_CONTINUE;
+
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,anchors_da);
+ if (Da.state != NONE && Da.state != LOC_2) return C_CONTINUE;
+ if (Da.trk[0] && Da.trk[1]) return C_CONTINUE;
+ EPINX_T ep = -1;
+ t = NULL;
+ if (((MyGetKeyState() & WKEY_ALT) == 0) == magneticSnap) {
+ //Lock to endpoint if one is available and under pointer
+ if ((t = OnTrack(&pos, FALSE, TRUE)) != NULL && t != Da.selectTrack) {
+ if (QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS)) { //Circle/Helix find if there is an open slot and where
+ if ((GetTrkEndTrk(t,0) != NULL) && (GetTrkEndTrk(t,1) != NULL)) {
+ return C_CONTINUE;
+ }
+ ep = -1; //Not a real ep yet
+ } else ep = PickUnconnectedEndPointSilent(pos, t); //EP
+ if (ep>=0 && QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) ep=-1; //Don't attach to Turntable
+ if ( ep==-1 && (!QueryTrack(t,Q_CAN_ADD_ENDPOINTS) && !QueryTrack(t,Q_HAS_VARIABLE_ENDPOINTS))) { //No endpoints and not Turntable or Helix/Circle
+ return C_CONTINUE;
+ }
+ if (GetTrkGauge(t) != GetScaleTrackGauge(GetLayoutCurScale())) {
+ return C_CONTINUE;
+ }
+ if (Da.state != NONE && t==Da.trk[0]) return C_CONTINUE;
+ }
+ }
+ if (ep>=0 && t) {
+ pos = GetTrkEndPos(t,ep);
+ CreateCornuEndAnchor(pos,TRUE);
+ } else if (t) {
+ trackParams_t tp; //Turntable or extendable track
+ if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE;
+ if (QueryTrack(t,Q_CAN_ADD_ENDPOINTS)) {
+ if (!GetTrackParams(PARAMS_CORNU, t, pos, &tp)) return C_CONTINUE;
+ ANGLE_T a = tp.angle;
+ Translate(&pos,tp.ttcenter,a,tp.ttradius);
+ CreateCornuEndAnchor(pos,TRUE);
+ } else CreateCornuEndAnchor(pos,TRUE);
+ }
+
+ return C_CONTINUE;
case C_MOVE:
- if (Da.state == NONE) {
- InfoMessage("Place 1st end point of Cornu track on unconnected end-point");
+ if (Da.state == NONE) { //First point not created
+ if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) {
+ InfoMessage("Place 1st end point of Cornu track");
+ } else
+ InfoMessage("Place 1st end point of Cornu track on unconnected end-point");
return C_CONTINUE;
}
- if (Da.state == POS_1) {
+ if (Da.state == POS_1) { //First point has been created
+ if ((Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) && !Da.trk[0]) { //OK for CreateCornu -> No track selected
+ if (IsClose(FindDistance(pos,Da.pos[0]))) return C_CONTINUE;
+ Da.selectEndPoint = 0;
+ Da.angle[0] = NormalizeAngle(FindAngle(Da.pos[0],pos)+180);
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],TRUE,TRUE,TRUE,FALSE,Da.angle[0],0.0,zero,&Da.endHandle[0]);
+ Da.radius[1] = -1.0; /*No end*/
+ return C_CONTINUE;
+ }
EPINX_T ep = 0;
BOOL_T found = FALSE;
int end = Da.state==POS_1?0:1;
if(!QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY) && !QueryTrack(Da.trk[0],Q_CAN_ADD_ENDPOINTS)) {
- InfoMessage(_("Can't Split - Locked to End Point"));
+ InfoMessage(_("Track can't be split - so locked to endpoint"));
return C_CONTINUE;
}
if (Da.trk[0] != OnTrack(&pos, FALSE, TRUE)) {
wBeep();
InfoMessage(_("Point not on track 1"));
Da.state = POS_1;
- Da.selectPoint = 1;
+ Da.selectEndPoint = 0;
return C_CONTINUE;
}
t = Da.trk[0];
- DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
- if (!GetConnectedTrackParms(t, pos, ep, Da.ep[ep])) {
+ if (!GetConnectedTrackParms(t, pos, ep, Da.ep[ep],FALSE)) {
Da.state = POS_1;
- Da.selectPoint = 1;
+ Da.selectEndPoint = 0;
return C_CONTINUE;
}
Da.pos[ep] = pos;
- Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],TRUE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY));
- DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
- } else {
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs,Da.pos[0],TRUE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY),
+ Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL);
+ } else if (Da.state == POS_2 &&
+ (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) && !Da.trk[1]) { //OK for CreateCornu -> No track selected
+ if (IsClose(FindDistance(pos,Da.pos[1]))) return C_CONTINUE;
+ Da.selectEndPoint = 1;
+ Da.angle[1] = NormalizeAngle(FindAngle(Da.pos[1],pos)+180);
+ Da.radius[1] = 0.0; /*No end*/
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep2Segs,Da.pos[1],TRUE,TRUE,TRUE,FALSE,Da.angle[1],0.0,zero,&Da.endHandle[1]);
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ CreateBothEnds(-1,-1,-1,-1);
+ Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
+ return C_CONTINUE;
+ } else { //Second Point Has Been Created and aligned
return AdjustCornuCurve( action&0xFF, pos, InfoMessage );
}
return C_CONTINUE;
case C_UP:
- if (Da.state == POS_1 && Da.trk[0]) {
- DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
+ if (Da.state == POS_1 && (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar || Da.trk[0])) {
Da.state = LOC_2;
+ Da.selectEndPoint = -1;
+ if (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar) {
+ if (Da.cmdType == cornuCmdCreateTrack)
+ InfoMessage( _("Pick other end of Cornu") );
+ else
+ InfoMessage( _("Select flextrack ends or anchors and drag, Enter to approve, Esc to Cancel") );
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0],FALSE,TRUE,TRUE,FALSE,0.0,0.0,zero,NULL);
+ return C_CONTINUE;
+ }
InfoMessage( _("Put other end of Cornu on a track with an unconnected end point") );
- Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY));
- DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,NULL,0,NULL,0,NULL,NULL,NULL,drawColorBlack);
+ if (Da.trk[0])
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,!QueryTrack(Da.trk[0],Q_IS_CORNU),QueryTrack(Da.trk[0],Q_CORNU_CAN_MODIFY),
+ Da.trk[0]!=NULL,Da.angle[0],Da.radius[0],Da.center[0],NULL);
+ else
+ Da.ep1Segs_da_cnt = createEndPoint(Da.ep1Segs, Da.pos[0], FALSE,TRUE,TRUE,FALSE, Da.angle[0],Da.radius[0],Da.center[0],&Da.endHandle[0]);
+ return C_CONTINUE;
+ } else if (Da.state == POS_2 && (Da.cmdType == cornuCmdCreateTrack || Da.cmdType == cornuCmdHotBar || Da.trk[1] )){
+ Da.state = PICK_POINT;
+ Da.selectEndPoint = -1;
+ Da.prevEndPoint = 1;
+ Da.prevSelected = -1;
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else Da.crvSegs_da_cnt = 0;
+ CreateBothEnds(-1,-1,-1,-1);
+ Da.minRadius = CornuMinRadius(Da.pos,Da.crvSegs_da);
return C_CONTINUE;
} else {
return AdjustCornuCurve( action&0xFF, pos, InfoMessage );
}
+ return C_CONTINUE;
+ break;
case C_TEXT:
- if (Da.state != PICK_POINT || (action>>8) != 32) //Space is same as Enter.
+ if (Da.state != PICK_POINT) return C_CONTINUE;
+ if ((action>>8 == 127) || (action>>8 == 8)) //
+ return AdjustCornuCurve(action, pos, InfoMessage);
+ if (!(action>>8 == 32 )) //Space is same as Enter.
return C_CONTINUE;
/* no break */
case C_OK:
if (Da.state != PICK_POINT) return C_CONTINUE;
- return AdjustCornuCurve( C_OK, pos, InfoMessage);
+ STATUS_T rc = AdjustCornuCurve( C_OK, pos, InfoMessage);
+ if (rc == C_TERMINATE) {
+ Da.state = NONE;
+ Da.ep1Segs_da_cnt = 0;
+ Da.ep2Segs_da_cnt = 0;
+ Da.crvSegs_da_cnt = 0;
+ for (int i=0;i<2;i++) {
+ Da.radius[i] = 0.0;
+ Da.angle[i] = 0.0;
+ Da.center[i] = zero;
+ Da.trk[i] = NULL;
+ Da.ep[i] = -1;
+ Da.pos[i] = zero;
+ Da.endHandle[i].end_valid = FALSE;
+ }
+ }
+ return rc;
case C_REDRAW:
if ( Da.state != NONE ) {
- DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,Da.ep2Segs,Da.ep2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, NULL,
- Da.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,Da.color);
+ DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,Da.ep2Segs,Da.ep2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da_cnt, NULL,
+ Da.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,(trkSeg_t *)Da.midSegs.ptr,Da.midSegs.cnt,wDrawColorBlack);
}
+ if (anchors_da.cnt)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack );
+ if (MyGetKeyState()&WKEY_SHIFT) DrawHighlightBoxes(FALSE,FALSE,NULL);
+
return C_CONTINUE;
case C_CANCEL:
if (Da.state != NONE) {
- DrawCornuCurve(NULL,Da.ep1Segs,Da.ep1Segs_da_cnt,Da.ep2Segs,Da.ep2Segs_da_cnt,(trkSeg_t *)Da.crvSegs_da.ptr,Da.crvSegs_da.cnt, NULL,
- Da.extend[0]?&Da.extendSeg[0]:NULL,Da.extend[1]?&Da.extendSeg[1]:NULL,Da.color);
Da.ep1Segs_da_cnt = 0;
Da.ep2Segs_da_cnt = 0;
Da.crvSegs_da_cnt = 0;
@@ -1262,21 +2568,486 @@ STATUS_T CmdCornu( wAction_t action, coOrd pos )
Da.trk[i] = NULL;
Da.ep[i] = -1;
Da.pos[i] = zero;
+ Da.endHandle[i].end_valid = FALSE;
}
//DYNARR_FREE(trkSeg_t,Da.crvSegs_da);
}
Da.state = NONE;
+ if (infoSubst) {
+ InfoSubstituteControls( NULL, NULL );
+ infoSubst = FALSE;
+ }
return C_CONTINUE;
default:
return C_CONTINUE;
}
+ return C_CONTINUE;
+}
+BOOL_T GetTracksFromCornuTrack(track_p trk, track_p newTracks[2]) {
+ track_p trk_old = NULL;
+ newTracks[0] = NULL, newTracks[1] = NULL;
+ struct extraData * xx = GetTrkExtraData(trk);
+ if (!IsTrack(trk)) return FALSE;
+ for (int i=0; i<xx->cornuData.arcSegs.cnt;i++) {
+ track_p bezTrack[2];
+ bezTrack[0] = NULL, bezTrack[1] = NULL;
+ trkSeg_p seg = &DYNARR_N(trkSeg_t,xx->cornuData.arcSegs,i);
+ if (seg->type == SEG_BEZTRK) {
+ DYNARR_RESET(trkSeg_t,seg->bezSegs);
+ FixUpBezierSeg(seg->u.b.pos,seg,TRUE);
+ GetTracksFromBezierSegment(seg, bezTrack, trk);
+ if (newTracks[0] == NULL) newTracks[0] = bezTrack[0];
+ newTracks[1] = bezTrack[1];
+ if (trk_old) {
+ for (int i=0;i<2;i++) {
+ if (GetTrkEndTrk(trk_old,i)==NULL) {
+ coOrd pos = GetTrkEndPos(trk_old,i);
+ EPINX_T ep_n = PickUnconnectedEndPoint(pos,bezTrack[0]);
+ if ((connectDistance >= FindDistance(GetTrkEndPos(trk_old,i),GetTrkEndPos(bezTrack[0],ep_n))) &&
+ (connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(trk_old,i),GetTrkEndAngle(bezTrack[0],ep_n)+180))) ) {
+ ConnectTracks(trk_old,i,bezTrack[0],ep_n);
+ break;
+ }
+ }
+ }
+ }
+ trk_old = newTracks[1];
+ } else {
+ track_p new_trk;
+ if (seg->type == SEG_CRVTRK)
+ new_trk = NewCurvedTrack(seg->u.c.center,seg->u.c.radius,seg->u.c.a0,seg->u.c.a1,0);
+ else if (seg->type == SEG_STRTRK)
+ new_trk = NewStraightTrack(seg->u.l.pos[0],seg->u.l.pos[1]);
+ if (newTracks[0] == NULL) newTracks[0] = new_trk;
+ CopyAttributes( trk, new_trk );
+ newTracks[1] = new_trk;
+ if (trk_old) {
+ for (int i=0;i<2;i++) {
+ if (GetTrkEndTrk(trk_old,i)==NULL) {
+ coOrd pos = GetTrkEndPos(trk_old,i);
+ EPINX_T ep_n = PickUnconnectedEndPoint(pos,new_trk);
+ if ((connectDistance >= FindDistance(GetTrkEndPos(trk_old,i),GetTrkEndPos(new_trk,ep_n))) &&
+ (connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(trk_old,i),GetTrkEndAngle(new_trk,ep_n)+180)))) {
+ ConnectTracks(trk_old,i,new_trk,ep_n);
+ break;
+ }
+ }
+ }
+ }
+ trk_old = new_trk;
+ }
+ }
+ return TRUE;
+
+}
+
+static STATUS_T cmdCornuCreate(
+ wAction_t action,
+ coOrd pos ) {
+ static int createState = 0;
+ int rc = 0;
+
+ switch(action&0xFF) {
+
+ case C_DOWN:
+ return CmdCornu(C_DOWN,pos);
+ case C_UP:
+ rc = CmdCornu(C_UP,pos);
+ return rc;
+ case C_FINISH:
+ if (createState != 0 ) {
+ createState = 0;
+ CmdCornu( C_OK, pos );
+ } else
+ CmdCornu( C_CANCEL, pos );
+ Da.prevSelected = -1;
+ Da.selectEndHandle = -1;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ Da.selectTrack = NULL;
+ Da.trk[0] = NULL; Da.trk[1] = NULL;
+ Da.radius[0] = Da.radius[1] = -1.0;
+ Da.angle[0] = Da.angle[1] = 0.0;
+ Da.ends[0] = Da.ends[1] = FALSE;
+ Da.endHandle[0].end_valid = Da.endHandle[1].end_valid = FALSE;
+ return C_TERMINATE;
+ case C_TEXT:
+ if ((action>>8) != ' ' && (action>>8) != 32)
+ return CmdCornu(action,pos);
+ /*no break*/
+ case C_OK:
+ CmdCornu(C_OK,pos);
+ MainRedraw();
+ return C_CONTINUE;
+ case C_CANCEL:
+ HotBarCancel();
+ CmdCornu(C_CANCEL, pos);
+ createState = 0;
+ rc = C_TERMINATE;
+ /* no break */
+ case C_START:
+ createState = 0;
+ commandContext = (void *)cornuCmdHotBar;
+ rc = CmdCornu(C_START, pos);
+ Da.prevSelected = -1;
+ Da.selectEndHandle = -1;
+ Da.selectEndPoint = -1;
+ Da.selectMidPoint = -1;
+ Da.selectTrack = NULL;
+ Da.trk[0] = NULL; Da.trk[1] = NULL;
+ Da.radius[0] = Da.radius[1] = -1.0;
+ Da.angle[0] = Da.angle[1] = 0.0;
+ Da.ends[0] = Da.ends[1] = FALSE;
+ Da.endHandle[0].end_valid = Da.endHandle[1].end_valid = FALSE;
+ return rc;
+ default:
+ return CmdCornu(action,pos);
+ }
+ return C_CONTINUE;
}
+static STATUS_T CmdConvertTo(
+ wAction_t action,
+ coOrd pos )
+{
+ static track_p trk;
+ cornuParm_t cp;
+ switch (action) {
+
+ case wActionMove:
+ if ((trk = OnTrack(&pos,FALSE,TRUE)) == NULL) return C_CONTINUE;
+ if (!QueryTrack(trk, Q_CORNU_CAN_MODIFY) && //Not Fixed Track/Turnout/Turntable
+ !QueryTrack(trk, Q_IGNORE_EASEMENT_ON_EXTEND ))
+ trk = NULL;
+ return C_CONTINUE;
+
+ case C_LCLICK:
+ if ((trk = OnTrack(&pos,FALSE,TRUE))!=NULL) {
+ SetTrkBits(trk,TB_SELECTED);
+ selectedTrackCount = 1;
+ } else {
+ wBeep();
+ InfoMessage( _("Not on a Track") );
+ return C_CONTINUE;
+ }
+ trk = NULL;
+
+ /* no break */
+ case C_START:
+ if (selectedTrackCount==0) {
+ InfoMessage( _("Select a Track To Convert") );
+ return C_CONTINUE;
+ }
+ else if (selectedTrackCount>1) {
+ if (NoticeMessage(_("Convert all Selected Tracks to Cornu Tracks?"), _("Yes"), _("No"))<=0) {
+ SetAllTrackSelect(FALSE);
+ return C_TERMINATE;
+ }
+ }
+ UndoStart( _("Convert Cornu"),"newCornu curves");
+ trk = NULL;
+ int converted=0, not_convertable = 0, created=0, deleted=0;
+ DYNARR_RESET(track_p,Da.tracks);
+ while ( TrackIterate( &trk ) ) {
+ if (!GetTrkSelected( trk )) continue; //Only selected
+ if (!QueryTrack(trk, Q_CORNU_CAN_MODIFY) && //Not Fixed Track/Turnout/Turntable
+ !QueryTrack( trk, Q_IGNORE_EASEMENT_ON_EXTEND )) { //But Yes to Easement
+ not_convertable++;
+ continue;
+ }
+ converted++;
+ DYNARR_RESET(trkSeg_t,Da.crvSegs_da);
+ Da.ep1Segs_da_cnt = 0;
+ Da.ep2Segs_da_cnt = 0;
+ Da.midSegs.cnt = 0;
+ Da.extend[0] = FALSE;
+ Da.extend[1] = FALSE;
+ Da.selectEndPoint = -1;
+ Da.selectTrack = NULL;
+ DYNARR_RESET(coOrd,Da.mid_points);
+ ClrTrkBits( trk, TB_SELECTED ); //Done with this one
+ Da.selectTrack = trk;
+ DYNARR_APPEND(track_p,Da.tracks,1);
+ DYNARR_LAST(track_p,Da.tracks) = trk;
+ Da.trk[0] = GetTrkEndTrk( trk, 0 );
+ track_p prior = trk;
+ if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],trk);
+ else Da.ep[0] = -1;
+ EPINX_T ep0 = 0;
+ //Move down the LHS adding tracks until no more Selected or not modifyable
+ while (Da.trk[0] && GetTrkSelected( Da.trk[0]) && IsTrack(Da.trk[0]) && (QueryTrack(Da.trk[0], Q_CORNU_CAN_MODIFY) || QueryTrack(Da.trk[0], Q_IS_CORNU)) ) {
+ prior = Da.trk[0];
+ ep0 = 1-Da.ep[0];
+ ClrTrkBits( Da.trk[0], TB_SELECTED ); //Done with this one
+ if (selectedTrackCount>0) selectedTrackCount--;
+ DYNARR_APPEND(track_p,Da.tracks,1);
+ DYNARR_LAST(track_p,Da.tracks) = prior;
+ DYNARR_APPEND(coOrd,Da.mid_points,1);
+ for (int i=Da.mid_points.cnt-1;i>1;i--) {
+ DYNARR_N(coOrd,Da.mid_points,i) = DYNARR_N(coOrd,Da.mid_points,i-1);
+ }
+ DYNARR_N(coOrd,Da.mid_points,0) = GetTrkEndPos(prior,1-ep0);
+ Da.trk[0] = GetTrkEndTrk( prior, ep0 );
+ if (Da.trk[0]) Da.ep[0] = GetEndPtConnectedToMe(Da.trk[0],prior);
+ else Da.ep[0] = -1;
+ converted++;
+ }
+ Da.radius[0] = -1.0; //Initialize with no end
+ Da.ends[0] = FALSE;
+ Da.center[0] = zero;
+ Da.pos[0] = GetTrkEndPos(prior,ep0);
+ if (Da.trk[0] && Da.ep[0]>=0) {
+ GetConnectedTrackParms(Da.trk[0],GetTrkEndPos(Da.trk[0],Da.ep[0]),0,Da.ep[0],FALSE);
+ }
+
+ //Move to RHS
+
+ Da.trk[1] = GetTrkEndTrk( trk, 1 );
+ track_p next = trk;
+ EPINX_T ep1 = 1;
+ if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],trk);
+ else Da.ep[1] = -1;
+ //Move down RHS adding tracks until no more Selected or not modifyable
+ while (Da.trk[1] && GetTrkSelected( Da.trk[1]) && (QueryTrack(Da.trk[1], Q_CORNU_CAN_MODIFY) || QueryTrack(Da.trk[1], Q_IS_CORNU))) {
+ next = Da.trk[1];
+ ep1 = 1-Da.ep[1];
+ if (selectedTrackCount>0) selectedTrackCount--;
+ ClrTrkBits( Da.trk[1], TB_SELECTED ); //Done with this one
+ DYNARR_APPEND(track_p,Da.tracks,1);
+ DYNARR_LAST(track_p,Da.tracks) = next;
+ DYNARR_APPEND(coOrd,Da.mid_points,1);
+ DYNARR_LAST(coOrd,Da.mid_points) = GetTrkEndPos(next,1-ep1);
+ Da.trk[1] = GetTrkEndTrk( next, ep1 );
+ if (Da.trk[1]) Da.ep[1] = GetEndPtConnectedToMe(Da.trk[1],next);
+ converted++;
+ }
+ Da.radius[1] = -1.0; //Initialize with no end
+ Da.ends[1] = FALSE;
+ Da.center[1] = zero;
+ Da.pos[1] = GetTrkEndPos(next,ep1);
+ if (Da.trk[1] && Da.ep[1]>=0) {
+ GetConnectedTrackParms(Da.trk[1],GetTrkEndPos(Da.trk[1],Da.ep[1]),1,Da.ep[1],FALSE);
+ }
+ SetUpCornuParms(&cp);
+ if (CallCornuM(Da.mid_points,Da.ends,Da.pos,&cp,&Da.crvSegs_da,TRUE)) Da.crvSegs_da_cnt = Da.crvSegs_da.cnt;
+ else continue; //Checks that a solution can be found
+
+ // Do the deed - Create a replacement Cornu
+
+ BOOL_T end_point[2];
+ end_point[0] = TRUE;
+ end_point[1] = FALSE;
+ coOrd sub_pos[2];
+ sub_pos[0] = Da.pos[0];
+ if (Da.radius[0] == -1) end_point[0] = FALSE;
+ track_p first_trk= NULL,trk1=NULL,trk2 = NULL;
+
+ for (int i=0;i<Da.mid_points.cnt;i++) {
+ sub_pos[1] = DYNARR_N(coOrd,Da.mid_points,i);
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point))== NULL) continue;
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]) {
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ DrawNewTrack(trk1);
+ if (first_trk == NULL) first_trk = trk1;
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ trk2 = trk1;
+ end_point[0] = FALSE;
+ sub_pos[0] = DYNARR_N(coOrd,Da.mid_points,i);
+ }
+ sub_pos[1] = Da.pos[1];
+ end_point[1] = TRUE;
+ if (Da.radius[1] == -1) end_point[1] = FALSE;
+ if ((trk1 = CreateCornuFromPoints(sub_pos,end_point)) == NULL) continue;
+ created++;
+ DrawNewTrack(trk1);
+ if (Da.trk[0]) {
+ CopyAttributes( Da.trk[0], trk1 );
+ } else if (Da.trk[1]){
+ CopyAttributes( Da.trk[1], trk1 );
+ } else {
+ SetTrkScale( trk1, GetLayoutCurScale() );
+ SetTrkBits( trk1, TB_HIDEDESC );
+ }
+ if (trk2) ConnectTracks(trk1,0,trk2,1);
+ if (first_trk == NULL) first_trk = trk1;
+
+ for (int i=0;i<2;i++) {
+ if (Da.ep[i]>=0 && Da.trk[i]) {
+ track_p trk_old = GetTrkEndTrk(Da.trk[i],Da.ep[i]);
+ EPINX_T old_ep = GetEndPtConnectedToMe(trk_old,Da.trk[i]);
+ DisconnectTracks(Da.trk[i],Da.ep[i],trk_old,old_ep);
+ if (Da.ep[i]>=0 && Da.trk[i])
+ ConnectTracks(Da.trk[i],Da.ep[i],i==0?first_trk:trk1,i);
+ }
+ }
+
+ } //Find next track
+ SetAllTrackSelect(FALSE);
+ //Get rid of old tracks
+ for (int i = 0; i<Da.tracks.cnt;i++) {
+ DeleteTrack(DYNARR_N(track_p,Da.tracks,i),FALSE);
+ deleted++;
+ }
+
+ UndoEnd(); //Stop accumulating
+ NoticeMessage(_("Tracks Counts: %d converted %d unconvertible %d created %d deleted"),_("OK"),NULL,converted,not_convertable,created,deleted);
+
+ return C_TERMINATE;
+
+ case C_REDRAW:
+ if (trk) {
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ }
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ return C_TERMINATE;
+
+ case C_OK:
+ return C_TERMINATE;
+
+ case C_CONFIRM:
+ return C_CONTINUE;
+
+ default:
+ return C_CONTINUE;
+ }
+}
+static STATUS_T CmdConvertFrom(
+ wAction_t action,
+ coOrd pos )
+{
+ static track_p trk;
+ track_p trk1,trk2;
+ switch (action) {
+
+ case wActionMove:
+ if ((trk = OnTrack(&pos,FALSE,TRUE)) == NULL) return C_CONTINUE;
+ if ((!(GetTrkType(trk) == T_CORNU)) ||
+ (!(GetTrkType(trk) == T_BEZIER)))
+ trk = NULL;
+ return C_CONTINUE;
+
+ case C_LCLICK:
+ if ((trk = OnTrack(&pos,FALSE,TRUE))!=NULL) {
+ SetTrkBits(trk,TB_SELECTED);
+ selectedTrackCount = 1;
+ trk = NULL;
+ } else {
+ wBeep();
+ InfoMessage( _("Not on a Track") );
+ trk = NULL;
+ return C_CONTINUE;
+ }
+ /* no break */
+ case C_START:
+ if (selectedTrackCount==0) {
+ InfoMessage( _("Select a Cornu or Bezier Track To Convert to Fixed") );
+ return C_CONTINUE;
+ }
+ else if (selectedTrackCount>1) {
+ if (NoticeMessage(_("Convert all Selected Tracks to Fixed Tracks?"), _("Yes"), _("No"))<=0) {
+ SetAllTrackSelect(FALSE);
+ return C_TERMINATE;
+ }
+ }
+ dynArr_t trackSegs_da;
+ DYNARR_RESET(trkSeg_t,trackSegs_da);
+ trk1 = NULL;
+ trk2 = NULL;
+ trk = NULL;
+ UndoStart( _("Convert Bezier and Cornu"),"Try to convert all selected tracks");
+ track_p tracks[2];
+ DYNARR_RESET(track_p,Da.tracks);
+ int converted=0, not_convertable = 0, created=0, deleted=0;
+ while ( TrackIterate( &trk1 ) ) {
+ if ( GetTrkSelected( trk1 ) && IsTrack( trk1 ) ) {
+ //Only Cornu or Bezier
+ tracks[0] = NULL, tracks[1] = NULL;
+ if (selectedTrackCount>0) selectedTrackCount--;
+ ClrTrkBits( trk1, TB_SELECTED ); //Done with this one
+ if (GetTrkType(trk1) == T_CORNU) {
+ GetTracksFromCornuTrack(trk1,tracks);
+ DYNARR_APPEND(track_p,Da.tracks,1);
+ DYNARR_LAST(track_p,Da.tracks) = trk1;
+ converted++;
+ } else if (GetTrkType(trk1) == T_BEZIER) {
+ GetTracksFromBezierTrack(trk1,tracks);
+ DYNARR_APPEND(track_p,Da.tracks,1);
+ DYNARR_LAST(track_p,Da.tracks) = trk1;
+ converted++;
+ } else {
+ not_convertable++;
+ continue;
+ }
+ for (int i=0;i<2;i++) {
+ track_p trk2 = GetTrkEndTrk(trk1,i);
+ if (trk2) {
+ EPINX_T ep1 = GetEndPtConnectedToMe( trk2, trk1 );
+ DisconnectTracks(trk2,ep1,trk1,i);
+ pos = GetTrkEndPos(trk2,ep1);
+ for (int j=0;j<2;j++) {
+ EPINX_T ep2 = PickUnconnectedEndPointSilent( pos, tracks[j] );
+ coOrd ep_pos;
+ if (ep2<0) continue;
+ ep_pos = GetTrkEndPos(tracks[j],ep2);
+ if (connectDistance>=FindDistance(pos,ep_pos) &&
+ connectAngle >= fabs(DifferenceBetweenAngles(GetTrkEndAngle(tracks[j],ep2),GetTrkEndAngle(trk2,ep1)+180))) {
+ ConnectTracks(trk2,ep1,tracks[j],ep2);
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ SetAllTrackSelect(FALSE);
+ for (int i = 0; i<Da.tracks.cnt;i++) {
+ DeleteTrack(DYNARR_N(track_p,Da.tracks,i),FALSE);
+ deleted++;
+ }
+ UndoEnd();
+ NoticeMessage(_("Tracks Counts: %d converted %d unconvertible %d deleted"),_("OK"),NULL,converted,not_convertable,deleted);
+ return C_TERMINATE;
+
+ case C_REDRAW:
+ if (trk) {
+ DrawTrack(trk,&tempD,wDrawColorPreviewSelected);
+ }
+ return C_CONTINUE;
+
+ case C_CANCEL:
+ return C_TERMINATE;
+
+ case C_OK:
+ return C_TERMINATE;
+
+ case C_CONFIRM:
+ return C_CONTINUE;
+
+ default:
+ return C_CONTINUE;
+ }
+}
+
+#include "bitmaps/convertto.xpm"
+#include "bitmaps/convertfr.xpm"
EXPORT void InitCmdCornu( wMenu_p menu )
{
-
+ ButtonGroupBegin( _("Convert"), "cmdConvertSetCmd", _("Convert") );
+ AddMenuButton( menu, CmdConvertTo, "cmdConvertTo", _("Convert To Cornu"), wIconCreatePixMap(convertto_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP3|IC_WANT_MOVE,ACCL_CONVERTTO, NULL );
+ AddMenuButton( menu, CmdConvertFrom, "cmdConvertFrom", _("Convert From Cornu"), wIconCreatePixMap(convertfr_xpm), LEVEL0_50, IC_STICKY|IC_LCLICK|IC_POPUP3|IC_WANT_MOVE,ACCL_CONVERTFR, NULL );
+ cornuHotBarCmdInx = AddMenuButton(menu, cmdCornuCreate, "cmdCornuCreate", "", NULL, LEVEL0_50, IC_STICKY|IC_POPUP3|IC_WANT_MOVE, 0, NULL);
+ ButtonGroupEnd();
+ ParamCreateControls( &cornuModPG, cornuModDlgUpdate) ;
}