From b623f5953691b2a0614e6f1f4def86bdbb9a4113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 8 Aug 2020 11:53:00 +0200 Subject: New upstream version 5.2.0Beta2.1 --- app/bin/ccornu.c | 2515 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 2143 insertions(+), 372 deletions(-) (limited to 'app/bin/ccornu.c') 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 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;iradius[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=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 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=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=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=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;i4*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=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>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= 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;i0?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; icornuData.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=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; i1) { + 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