summaryrefslogtreecommitdiff
path: root/app/bin/cjoin.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2020-08-22 14:05:41 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2020-08-22 14:05:41 +0200
commitb55285a77da0e0b829e4ce8d7e09debaabc68e15 (patch)
treef622559ef65bbdd3e1c5bdb06098a8f89eec0563 /app/bin/cjoin.c
parentd3897ce090dbeb220ed2c782f095597e417cf3cc (diff)
parentd1ae75703e1ed81d65ea16946dcdb77e7a13adc9 (diff)
Merge branch 'feature/upstream' into develop
Diffstat (limited to 'app/bin/cjoin.c')
-rw-r--r--app/bin/cjoin.c610
1 files changed, 556 insertions, 54 deletions
diff --git a/app/bin/cjoin.c b/app/bin/cjoin.c
index 8cfa3d4..71f4dae 100644
--- a/app/bin/cjoin.c
+++ b/app/bin/cjoin.c
@@ -1,5 +1,5 @@
/*
- * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cjoin.c,v 1.4 2008-03-06 19:35:05 m_fischer Exp $
+ * $Header: /home/dave/Source/xtrkcad_5_1_2a/app/bin/RCS/cjoin.c,v 1.3 2019/07/24 15:11:51 dave Exp $
*
* JOINS
*
@@ -39,7 +39,7 @@
#include "cselect.h"
#include "fileio.h"
-
+static BOOL_T debug = 0;
static int log_join = 0;
typedef struct {
curveType_e type;
@@ -53,25 +53,18 @@ typedef struct {
static struct {
STATE_T state;
int joinMoveState;
+ BOOL_T cornuMode;
struct {
TRKTYP_T realType;
track_p trk;
coOrd pos;
EPINX_T ep;
trackParams_t params;
-#ifdef LATER
- curveType_e type;
- ANGLE_T angle;
- coOrd lineOrig;
- coOrd lineEnd;
- coOrd arcP;
- DIST_T arcR;
- ANGLE_T arcA0, arcA1;
-#endif
} inp[2];
joinRes_t jRes;
coOrd inp_pos[2];
easementData_t jointD[2];
+ dynArr_t anchors;
} Dj;
@@ -169,7 +162,8 @@ LOG( log_join, 2, (" = CURVE @ Pc=[%0.3f %0.3f] R=%0.3f A0=%0.3f A1=%0.3f Fli
d = D2R(res->arcA1);
if (d < 0.0)
d = 2*M_PI + d;
- InfoMessage( _("Curved Track: Radius=%s Length=%s"),
+ if (!debug)
+ InfoMessage( _("Curved Track: Radius=%s Length=%s"),
FormatDistance(res->arcR), FormatDistance(res->arcR*d) );
return TRUE;
@@ -213,7 +207,7 @@ LOG( log_join, 3, (" p1=[%0.3f %0.3f] aa=%0.3f a=%0.3f\n",
/* Straight: */
PointOnCircle( &pt, pos0, r0, a1);
LOG( log_join, 2, (" = STRAIGHT [%0.3f %0.3f] [%0.3f %0.3f]\n", pt.x, pt.y, pos1.x, pos1.y ) )
- InfoMessage( _("Straight Track: Length=%s Angle=%0.3f"),
+ if (!debug) InfoMessage( _("Straight Track: Length=%s Angle=%0.3f"),
FormatDistance(FindDistance( pt, pos1 )), PutAngle(FindAngle( pt, pos1 )) );
res->type = curveTypeStraight;
res->pos[0]=pt;
@@ -255,7 +249,7 @@ LOG( log_join, 3, (" A0=%0.3f A1=%0.3f R=%0.3f\n", res->arcA0, res->arcA1,
d = D2R(res->arcA1);
if (d < 0.0)
d = 2*M_PI + d;
- InfoMessage( _("Curved Track: Radius=%s Length=%s Angle=%0.3f"),
+ if (!debug) InfoMessage( _("Curved Track: Radius=%s Length=%s Angle=%0.3f"),
FormatDistance(res->arcR), FormatDistance(res->arcR*d), PutAngle(res->arcA1) );
res->type = curveTypeCurve;
}
@@ -302,11 +296,11 @@ static STATUS_T AdjustJoint(
switch ( Dj.inp[0].params.type ) {
case curveTypeCurve:
if (adjust) {
- a0 = FindAngle( Dj.inp[0].params.arcP, Dj.jRes.pos[0] ) +
- ((Dj.jointD[0].Scurve==TRUE || Dj.jointD[0].flip==FALSE)?0:+180);
+ a0 = FindAngle( Dj.inp[0].params.arcP, Dj.jRes.pos[0] );
Translate( &pc, Dj.inp[0].params.arcP, a0, Dj.jointD[0].x );
-LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f)\n",
- Dj.jointD[0].x, a0, Dj.jointD[1].x, a1 ) )
+LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f SC%d FL%d\n",
+ Dj.jointD[0].x, a0, Dj.jointD[1].x, a1,
+ Dj.jointD[0].Scurve, Dj.jointD[0].flip ) )
} else {
pc = Dj.inp[0].params.arcP;
}
@@ -368,7 +362,8 @@ LOG( log_join, 2, (" Move P0 X%0.3f A%0.3f P1 X%0.3f A%0.3f\n",
}
d -= l;
if ( d <= minLength ) {
- InfoMessage( _("Connecting track is too short by %0.3f"), PutDim(fabs(minLength-d)) );
+ if (!debug)
+ InfoMessage( _("Connecting track is too short by %0.3f"), PutDim(fabs(minLength-d)) );
return FALSE;
}
@@ -415,7 +410,6 @@ static STATUS_T DoMoveToJoin( coOrd pos )
_("Click on an unselected End-Point"):
_("Click on a selected End-Point") );
Dj.inp[0].pos = pos;
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
return C_CONTINUE;
}
if ( GetTrkSelected(Dj.inp[0].trk) == GetTrkSelected(Dj.inp[1].trk) ) {
@@ -423,7 +417,6 @@ static STATUS_T DoMoveToJoin( coOrd pos )
? _("unselected") : _("selected") );
return C_CONTINUE;
}
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
if (GetTrkSelected(Dj.inp[0].trk))
MoveToJoin( Dj.inp[0].trk, Dj.inp[0].params.ep, Dj.inp[1].trk, Dj.inp[1].params.ep );
else
@@ -432,6 +425,372 @@ static STATUS_T DoMoveToJoin( coOrd pos )
return C_TERMINATE;
}
+typedef enum {NO_LINE,FIRST_END,HAVE_LINE,HAVE_SECOND_LINE} LineState_t;
+
+static struct {
+ LineState_t line_state;
+ int joinMoveState;
+ track_p curr_line;
+ struct {
+ TRKTYP_T realType;
+ track_p line;
+ coOrd pos;
+ coOrd end;
+ int cnt;
+ } inp[2];
+ joinRes_t jRes;
+ coOrd inp_pos[2];
+ dynArr_t anchors_da;
+ trackParams_t params;
+ dynArr_t newLine;
+ } Dl;
+
+#define anchors(N) DYNARR_N(trkSeg_t,Dl.anchors_da,N)
+
+void AddAnchorEnd(coOrd p) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,Dl.anchors_da,1);
+ trkSeg_p a = &DYNARR_LAST(trkSeg_t,Dl.anchors_da);
+ a->type = SEG_CRVLIN;
+ a->width = 0;
+ a->u.c.a0 = 0.0;
+ a->u.c.a1 = 360.0;
+ a->u.c.center = p;
+ a->u.c.radius = d/2;
+ a->color = wDrawColorPowderedBlue;
+}
+
+
+static STATUS_T CmdJoinLine(
+ wAction_t action,
+ coOrd pos )
+/*
+ * Join 2 lines.
+ */
+{
+
+ switch (action&0xFF) {
+ case C_START:
+ InfoMessage( _("Left click - Select first draw object end") );
+ Dl.line_state = NO_LINE;
+ Dl.joinMoveState = 0;
+ tempSegs_da.cnt = 0;
+ DYNARR_RESET(trkSeg_t,Dl.newLine);
+ Dl.curr_line = NULL;
+ return C_CONTINUE;
+ case wActionMove:
+ DYNARR_RESET(trkSeg_t,Dl.anchors_da);
+ Dl.curr_line = NULL;
+ coOrd pos1= pos;
+ Dl.curr_line = OnTrack( &pos1, FALSE, FALSE );
+ if (!Dl.curr_line) return C_CONTINUE;
+ if (IsTrack(Dl.curr_line)) {
+ Dl.curr_line = NULL;
+ return C_CONTINUE;
+ }
+ if (!QueryTrack(Dl.curr_line,Q_GET_NODES)) {
+ Dl.curr_line = NULL;
+ return C_CONTINUE;
+ }
+ if (!GetTrackParams(PARAMS_NODES,Dl.curr_line,pos,&Dl.params)) {
+ Dl.curr_line = NULL;
+ return C_CONTINUE;
+ }
+ if ( (Dl.line_state != NO_LINE) &&
+ (Dl.inp[0].line == Dl.curr_line) &&
+ (IsClose(FindDistance(Dl.inp[0].pos,Dl.params.lineOrig)) ) ) {
+ Dl.curr_line = NULL;
+ } else {
+ AddAnchorEnd(Dl.params.lineOrig);
+ }
+ break;
+ case C_DOWN:
+ DYNARR_RESET(trkSeg_t,Dl.anchors_da);
+ Dl.curr_line = NULL;
+ if (Dl.line_state == NO_LINE) {
+ Dl.curr_line = OnTrack( &pos, FALSE, FALSE);
+ if (!Dl.curr_line || IsTrack(Dl.curr_line)) {
+ InfoMessage( _("Not a line - Try again") );
+ return C_CONTINUE;
+ }
+ if (!QueryTrack(Dl.curr_line,Q_GET_NODES)) return C_CONTINUE;
+ if (!GetTrackParams(PARAMS_NODES,Dl.curr_line,pos,&Dl.params)) return C_CONTINUE;
+ Dl.line_state = HAVE_LINE;
+ Dl.inp[0].line = Dl.curr_line;
+ Dl.inp[0].pos = Dl.params.lineOrig;
+ Dl.inp[0].end = Dl.params.lineEnd;
+ DYNARR_SET(trkSeg_t,Dl.newLine,1);
+
+ DYNARR_LAST(trkSeg_t,Dl.newLine).type = SEG_POLY;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).color = wDrawColorBlack;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).width = 0;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.polyType = POLYLINE;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts = MyMalloc(sizeof(pts_t)*Dl.params.nodes.cnt);
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt = Dl.params.nodes.cnt;
+ //Copy in reverse as we want this point to be last
+ for (int i=0;i<Dl.params.nodes.cnt;i++) {
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[i].pt = DYNARR_N(coOrd,Dl.params.nodes,Dl.params.nodes.cnt-1-i);
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[i].pt_type = wPolyLineStraight;
+ }
+ InfoMessage( _("Left click - Select second object end") );
+ } else {
+ Dl.curr_line = OnTrack( &pos, FALSE, FALSE );
+ if (!Dl.curr_line || IsTrack(Dl.curr_line)) {
+ InfoMessage( _("Not a line - Try again") );
+ return C_CONTINUE;
+ }
+ if (!QueryTrack(Dl.curr_line,Q_GET_NODES)) return C_CONTINUE;
+ if (!GetTrackParams(PARAMS_NODES,Dl.curr_line,pos,&Dl.params)) return C_CONTINUE;
+ if (Dl.curr_line == Dl.inp[0].line) {
+ if ((Dl.params.lineOrig.x == Dl.inp[0].pos.x) &&
+ (Dl.params.lineOrig.y == Dl.inp[0].pos.y)) {
+ InfoMessage( _("Same draw object and same endpoint - Try again") );
+ return C_CONTINUE;
+ }
+ }
+ Dl.line_state = HAVE_SECOND_LINE;
+ Dl.inp[1].line = Dl.curr_line;
+ Dl.inp[1].pos = Dl.params.lineOrig;
+ Dl.inp[1].end = Dl.params.lineEnd;
+ int old_cnt = DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt;
+ BOOL_T join_near = FALSE;
+ if (Dl.inp[1].line == Dl.inp[0].line) {
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts = MyRealloc(DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts,sizeof(pts_t)*(old_cnt+1));
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[old_cnt] = DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[0]; // Joined up Polygon
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt += 1;
+ } else {
+ if (IsClose(FindDistance(Dl.inp[0].pos,Dl.inp[1].pos)))
+ join_near = TRUE;
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts = MyRealloc(DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts,sizeof(pts_t)*(old_cnt+Dl.params.nodes.cnt-join_near));
+ //Copy forwards as this point is first
+ for (int i=join_near;i<Dl.params.nodes.cnt;i++) {
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[i-join_near+old_cnt].pt = DYNARR_N(coOrd,Dl.params.nodes,i);
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.pts[i-join_near+old_cnt].pt_type = wPolyLineStraight;
+ }
+ DYNARR_LAST(trkSeg_t,Dl.newLine).u.p.cnt += Dl.params.nodes.cnt-join_near;
+ }
+ }
+ UndrawNewTrack(Dl.curr_line);
+ Dl.curr_line = NULL;
+ break;
+ case C_MOVE:
+ break;
+ case C_UP:
+ if (Dl.line_state != HAVE_SECOND_LINE) return C_CONTINUE;
+ Dl.line_state = NO_LINE;
+ UndoStart(_("Create PolyLine"), "newPolyLine");
+ track_p newTrack = MakePolyLineFromSegs( zero, 0.0, &Dl.newLine );
+ DeleteTrack(Dl.inp[0].line,FALSE);
+ if (Dl.inp[0].line != Dl.inp[1].line)
+ DeleteTrack(Dl.inp[1].line,FALSE);
+ UndoEnd();
+ DrawNewTrack(newTrack);
+ CleanSegs(&Dl.newLine);
+ Dl.curr_line = NULL;
+ return C_TERMINATE;
+ break;
+ case C_CANCEL:
+ CleanSegs(&Dl.newLine);
+ Dl.line_state = NO_LINE;
+ Dl.curr_line = NULL;
+ break;
+ case C_REDRAW:
+ if (Dl.line_state != NO_LINE) DrawSegs(&tempD,zero,0.0,((trkSeg_t*)Dl.newLine.ptr), Dl.newLine.cnt, trackGauge, wDrawColorPreviewSelected);
+ if (Dl.curr_line) DrawTrack(Dl.curr_line,&tempD,wDrawColorPreviewSelected);
+ if (Dl.anchors_da.cnt>0)
+ DrawSegs( &tempD, zero, 0.0, &anchors(0), Dl.anchors_da.cnt, trackGauge, wDrawColorPreviewSelected );
+ break;
+ case C_TEXT:
+ case C_OK:
+ default:;
+
+ }
+
+
+ return C_CONTINUE;
+
+}
+
+void AnchorTempLine(coOrd p0, coOrd p1) {
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ p->type = SEG_STRLIN;
+ p->color = wDrawColorBlue;
+ p->width = 0.0;
+ p->u.l.pos[0] = p0;
+ p->u.l.pos[1] = p1;
+}
+
+void AnchorTempCircle(coOrd center,DIST_T radius, ANGLE_T a0, ANGLE_T a1) {
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ p->type = SEG_CRVLIN;
+ p->color = wDrawColorBlue;
+ p->width = 0.0;
+ p->u.c.a0 =a0;
+ p->u.c.a1 = a1;
+ p->u.c.radius = radius;
+ p->u.c.center = center;
+}
+
+void AnchorPoint(coOrd center) {
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ p->type = SEG_CRVLIN;
+ p->color = wDrawColorAqua;
+ p->width = 0.0;
+ p->u.c.a0 =0.0;
+ p->u.c.a1 = 360.0;
+ p->u.c.radius = mainD.scale/4;
+ p->u.c.center = center;
+}
+
+static DIST_T desired_radius = 0.0;
+
+static paramFloatRange_t r_0_10000 = { 0.0, 100000.0 };
+static paramData_t joinPLs[] = {
+#define joinRadPD (joinPLs[0])
+#define joinRadI 0
+ { PD_FLOAT, &desired_radius, "radius", PDO_DIM, &r_0_10000, N_("Desired Radius") }
+};
+static paramGroup_t joinPG = { "join-fixed", 0, joinPLs, sizeof joinPLs/sizeof joinPLs[0] };
+
+
+
+BOOL_T AdjustPosToRadius(coOrd *pos, DIST_T desired_radius, ANGLE_T an0, ANGLE_T an1) {
+ coOrd point1,point2;
+ switch ( Dj.inp[1].params.type ) {
+ case curveTypeCurve:
+ if (Dj.inp[0].params.type == curveTypeStraight) {
+ coOrd newP, newP1;
+ //Offset curve by desired_radius
+ DIST_T newR1;
+ newR1 = Dj.inp[1].params.arcR + desired_radius*((fabs(an1-Dj.inp[1].params.arcA0)<1.0)?1:-1);
+ if (newR1<=0.0) {
+ if (debug) InfoMessage("Zero Radius C1");
+ return FALSE;
+ }
+ //Offset line by desired_radius
+ Translate(&newP,Dj.inp[0].params.lineEnd,an0,desired_radius);
+ Translate(&newP1,Dj.inp[0].params.lineOrig,an0,desired_radius);
+ if (debug)
+ AnchorTempLine(newP,newP1);
+ //Intersect - this is the joining curve center
+ if (debug)
+ AnchorTempCircle(Dj.inp[1].params.arcP,newR1,Dj.inp[1].params.arcA0,Dj.inp[1].params.arcA1);
+ if (!FindArcAndLineIntersections(&point1,&point2,Dj.inp[1].params.arcP,newR1,newP,newP1))
+ return FALSE;
+ } else if (Dj.inp[0].params.type == curveTypeCurve) {
+ //Offset curve by desired_radius
+ DIST_T newR0;
+ newR0 = Dj.inp[0].params.arcR + desired_radius*((fabs(an0-Dj.inp[0].params.arcA0)<1.0)?1:-1);
+ if (newR0<=0.0) {
+ if (debug) InfoMessage("Zero Radius C0");
+ return FALSE;
+ }
+ //Offset curve by desired_radius
+ if (debug)
+ AnchorTempCircle(Dj.inp[0].params.arcP,newR0,Dj.inp[0].params.arcA0,Dj.inp[0].params.arcA1);
+ DIST_T newR1;
+ newR1 = Dj.inp[1].params.arcR + desired_radius*((fabs(an1-Dj.inp[1].params.arcA0)<1.0)?1:-1);
+ if (newR1<=0.0) {
+ if (debug) InfoMessage("Zero Radius C1");
+ return FALSE;
+ }
+ //Intersect - this is the joining curve center
+ if (debug)
+ AnchorTempCircle(Dj.inp[1].params.arcP,newR1,Dj.inp[1].params.arcA0,Dj.inp[1].params.arcA1);
+ if (!FindArcIntersections(&point1,&point2,Dj.inp[0].params.arcP,newR0,Dj.inp[1].params.arcP,newR1))
+ return FALSE;
+ }
+ if (debug) {
+ AnchorPoint(point1);
+ AnchorPoint(point2);
+ }
+ break;
+ case curveTypeStraight:
+ if (Dj.inp[0].params.type == curveTypeStraight) {
+ coOrd newI,newP0,newP01, newP1, newP11;
+ //Offset line1 by desired_radius
+ Translate(&newP0,Dj.inp[0].params.lineEnd,an0,desired_radius);
+ Translate(&newP01,Dj.inp[0].params.lineOrig,an0,desired_radius);
+ if (debug)
+ AnchorTempLine(newP0,newP01);
+ //Offset line2 by desired_radius
+ Translate(&newP1,Dj.inp[1].params.lineEnd,an1,desired_radius);
+ Translate(&newP11,Dj.inp[1].params.lineOrig,an1,desired_radius);
+ if (debug)
+ AnchorTempLine(newP1,newP11);
+ if (!FindIntersection(&newI,newP0,Dj.inp[0].params.angle,newP1,Dj.inp[1].params.angle))
+ return FALSE;
+ point1 = point2 = newI;
+ } else if (Dj.inp[0].params.type == curveTypeCurve) {
+ coOrd newP, newP1;
+ //Offset curve by desired_radius
+ DIST_T newR0;
+ newR0 = Dj.inp[0].params.arcR + desired_radius*((fabs(an0-Dj.inp[0].params.arcA0)<1.0)?1:-1);
+ if (newR0<=0.0) {
+ if (debug) InfoMessage("Zero Radius C0");
+ return FALSE;
+ }
+ if (debug)
+ AnchorTempCircle(Dj.inp[0].params.arcP,newR0,Dj.inp[0].params.arcA0,Dj.inp[0].params.arcA1);
+ //Offset line by desired_radius
+ Translate(&newP,Dj.inp[1].params.lineEnd,an1,desired_radius);
+ Translate(&newP1,Dj.inp[1].params.lineOrig,an1,desired_radius);
+ if (debug)
+ AnchorTempLine(newP,newP1);
+ //Intersect - this is the joining curve center
+ if (!FindArcAndLineIntersections(&point1,&point2,Dj.inp[0].params.arcP,newR0,newP,newP1))
+ return FALSE;
+ }
+ if (debug) {
+ AnchorPoint(point1);
+ AnchorPoint(point2);
+ }
+ break;
+ default:
+ return FALSE;
+ }
+ if (FindDistance(*pos,point1)<=FindDistance(*pos,point2)) {
+ if (Dj.inp[1].params.type == curveTypeCurve) {
+ ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,point1);
+ Translate(pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR);
+ } else {
+ Translate(pos,point1,NormalizeAngle(an1+180),desired_radius);
+ }
+ } else {
+ if (Dj.inp[1].params.type == curveTypeCurve) {
+ ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,point2);
+ Translate(pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR);
+ } else
+ Translate(pos,point2,NormalizeAngle(an1+180),desired_radius);
+ }
+
+ return TRUE;
+
+}
+
+void AddAnchorJoin(coOrd pos, ANGLE_T angle) {
+ DIST_T d = tempD.scale*0.15;
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p a = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ a->type = SEG_CRVLIN;
+ a->width = 0;
+ a->u.c.a0 = 0.0;
+ a->u.c.a1 = 360.0;
+ a->u.c.center = pos;
+ a->u.c.radius = d/2;
+ a->color = wDrawColorBlue;
+ DYNARR_SET(trkSeg_t,Dj.anchors,Dj.anchors.cnt+5);
+ DrawArrowHeads(&DYNARR_N(trkSeg_t,Dj.anchors,Dj.anchors.cnt-5),pos,angle,FALSE,wDrawColorBlue);
+
+}
+
+static BOOL_T infoSubst = FALSE;
+static track_p anchor_trk;
+static coOrd anchor_pos;
+static ANGLE_T anchor_angle = 0.0;
static STATUS_T CmdJoin(
wAction_t action,
@@ -451,26 +810,63 @@ static STATUS_T CmdJoin(
ANGLE_T a, a1;
DIST_T eR[2];
BOOL_T ok;
+ wControl_p controls[2];
+ char * labels[1];
switch (action&0xFF) {
case C_START:
+ if (joinPLs[0].control==NULL) {
+ ParamCreateControls(&joinPG, NULL);
+ }
if (selectedTrackCount==0)
InfoMessage( _("Left click - join with track") );
else
InfoMessage( _("Left click - join with track, Shift Left click - move to join") );
+ DYNARR_RESET(trkSeg_t,Dj.anchors);
Dj.state = 0;
Dj.joinMoveState = 0;
+ Dj.cornuMode = FALSE;
/*ParamGroupRecord( &easementPG );*/
- if (easementVal < 0)
+ infoSubst = FALSE;
+ anchor_trk = NULL;
+ if (easementVal < 0.0)
return CmdCornu(action, pos);
return C_CONTINUE;
+
+ case wActionMove:
+ anchor_trk = NULL;
+ DYNARR_RESET(rkSeg_t,Dj.anchors);
+ if ((easementVal < 0) && Dj.joinMoveState == 0 )
+ return CmdCornu(action, pos);
+ if ( Dj.state >= 2) return C_CONTINUE;
+ if ( (trk = OnTrack( &pos, FALSE, TRUE )) == NULL)
+ return C_CONTINUE;
+ if (!CheckTrackLayer( trk ) )
+ return C_CONTINUE;
+ if ((Dj.state > 0) && (trk == Dj.inp[0].trk))
+ return C_CONTINUE;
+ trackParams_t moveParams;
+ if (!GetTrackParams( PARAMS_1ST_JOIN, trk, pos, &moveParams ))
+ return C_CONTINUE;
+ ep = PickUnconnectedEndPointSilent(pos,trk);
+ if (ep <0) return C_CONTINUE;
+ if (IsClose(FindDistance(GetTrkEndPos(trk,ep),pos)))
+ anchor_angle = GetTrkEndAngle(trk,ep);
+ else
+ anchor_angle = FindAngle(pos,GetTrkEndPos(trk,ep));
+ anchor_trk = trk;
+ anchor_pos = pos;
+ AddAnchorJoin(pos,anchor_angle);
+ break;
case C_DOWN:
- if ( (Dj.state == 0 && (MyGetKeyState() & WKEY_SHIFT) != 0) || Dj.joinMoveState != 0 )
+ if ( !Dj.cornuMode && ((Dj.state == 0 && (MyGetKeyState() & WKEY_SHIFT) != 0) || Dj.joinMoveState != 0) )
return DoMoveToJoin( pos );
- if (easementVal < 0.0)
+ if (easementVal < 0.0 && Dj.joinMoveState == 0) {
+ Dj.cornuMode = TRUE;
return CmdCornu(action, pos);
+ }
DYNARR_SET( trkSeg_t, tempSegs_da, 3 );
tempSegs(0).color = drawColorBlack;
@@ -495,10 +891,18 @@ LOG( log_join, 1, ("JOIN: 1st track %d @[%0.3f %0.3f]\n",
Dj.inp[0].realType = GetTrkType(Dj.inp[0].trk);
InfoMessage( _("Select 2nd track") );
Dj.state = 1;
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
+ wPrefGetFloat("misc", "desired_radius", &desired_radius, desired_radius);
+ controls[0] = joinRadPD.control;
+ controls[1] = NULL;
+ labels[0] = N_("Desired Radius");
+ InfoSubstituteControls(controls, labels);
+ infoSubst = TRUE;
+ joinRadPD.option |= PDO_NORECORD;
+ ParamLoadControls(&joinPG);
+ ParamGroupRecord(&joinPG);
return C_CONTINUE;
} else {
- if ( (Dj.inp[1].trk = OnTrack( &pos, TRUE, TRUE )) == NULL)
+ if ( (Dj.inp[1].trk = OnTrack( &pos, FALSE, TRUE )) == NULL)
return C_CONTINUE;
if (!CheckTrackLayer( Dj.inp[1].trk ) )
return C_CONTINUE;
@@ -509,6 +913,10 @@ LOG( log_join, 1, ("JOIN: 1st track %d @[%0.3f %0.3f]\n",
ErrorMessage( MSG_JOIN_SAME );
return C_CONTINUE;
}
+ if (infoSubst)
+ InfoSubstituteControls(NULL, NULL);
+ infoSubst = FALSE;
+
Dj.inp[1].realType = GetTrkType(Dj.inp[1].trk);
if ( IsCurveCircle( Dj.inp[0].trk ) )
Dj.inp[0].params.ep = PickArcEndPt( Dj.inp[0].params.arcP, Dj.inp[0].pos, pos );
@@ -519,21 +927,30 @@ LOG( log_join, 1, (" 2nd track %d, @[%0.3f %0.3f] EP0=%d EP1=%d\n",
GetTrkIndex(Dj.inp[1].trk), Dj.inp[1].pos.x, Dj.inp[1].pos.y,
Dj.inp[0].params.ep, Dj.inp[1].params.ep ) )
LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
- if ( GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != NULL) {
- ErrorMessage( MSG_TRK_ALREADY_CONN, _("First") );
- return C_CONTINUE;
+ BOOL_T only_merge = FALSE;
+ if ( (Dj.inp[0].params.ep >=0) &&
+ (GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != NULL)) {
+ if (GetTrkEndTrk(Dj.inp[0].trk,Dj.inp[0].params.ep) != Dj.inp[1].trk) {
+ only_merge = TRUE;
+ ErrorMessage( MSG_TRK_ALREADY_CONN, _("First") );
+ return C_CONTINUE;
+ }
}
- if ( Dj.inp[1].params.ep >= 0 &&
- GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != NULL) {
- ErrorMessage( MSG_TRK_ALREADY_CONN, _("Second") );
- return C_CONTINUE;
+ if ( (Dj.inp[1].params.ep >= 0) &&
+ (GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != NULL)) {
+ if (GetTrkEndTrk(Dj.inp[1].trk,Dj.inp[1].params.ep) != Dj.inp[0].trk) {
+ only_merge = TRUE;
+ ErrorMessage( MSG_TRK_ALREADY_CONN, _("Second") );
+ return C_CONTINUE;
+ }
}
-
rc = C_CONTINUE;
if ( MergeTracks( Dj.inp[0].trk, Dj.inp[0].params.ep,
- Dj.inp[1].trk, Dj.inp[1].params.ep ) )
+ Dj.inp[1].trk, Dj.inp[1].params.ep ) ) {
+ rc = C_TERMINATE;
+ } else if (only_merge) {
rc = C_TERMINATE;
- else if ( Dj.inp[0].params.ep >= 0 && Dj.inp[1].params.ep >= 0 ) {
+ } else if ( Dj.inp[0].params.ep >= 0 && Dj.inp[1].params.ep >= 0 ) {
if ( Dj.inp[0].params.type == curveTypeStraight &&
Dj.inp[1].params.type == curveTypeStraight &&
ExtendStraightToJoin( Dj.inp[0].trk, Dj.inp[0].params.ep,
@@ -544,7 +961,6 @@ LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
rc = C_TERMINATE;
}
if ( rc == C_TERMINATE ) {
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
return rc;
}
if ( QueryTrack( Dj.inp[0].trk, Q_CANNOT_BE_ON_END ) ||
@@ -553,30 +969,103 @@ LOG( log_join, 1, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
return C_CONTINUE;
}
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
Dj.state = 2;
Dj.jRes.flip = FALSE;
}
tempSegs_da.cnt = 0;
+ /* no break */
case C_MOVE:
- if (easementVal < 0)
+ if (easementVal < 0 && Dj.cornuMode)
return CmdCornu(action, pos);
LOG( log_join, 3, ("P1=[%0.3f %0.3f]\n", pos.x, pos.y ) )
if (Dj.state != 2)
return C_CONTINUE;
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack );
+ DYNARR_RESET(trkSeg_t,Dj.anchors);
+
+
+ //Fix Pos onto the line of the second track
+ if (Dj.inp[1].params.type == curveTypeStraight) {
+ ANGLE_T a = NormalizeAngle(FindAngle(Dj.inp[1].params.lineOrig,pos)-Dj.inp[1].params.angle);
+ DIST_T d = FindDistance(Dj.inp[1].params.lineOrig,pos);
+ Translate(&pos,Dj.inp[1].params.lineOrig,Dj.inp[1].params.angle,d*cos(D2R(a)));
+ } else {
+ ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,pos);
+ Translate(&pos,Dj.inp[1].params.arcP,a,Dj.inp[1].params.arcR);
+ }
+
+ if ((desired_radius != 0.0) &&
+ ((Dj.inp[0].params.type == curveTypeStraight) || (Dj.inp[0].params.type == curveTypeCurve)) &&
+ ((Dj.inp[1].params.type == curveTypeStraight) || (Dj.inp[1].params.type == curveTypeCurve)) &&
+ Dj.jRes.type==curveTypeCurve
+ ) {
+ ANGLE_T na0=0.0,na1=0.0;
+ coOrd end0, end1;
+ ANGLE_T a0,a1;
+ end0 = GetTrkEndPos(Dj.inp[0].trk,Dj.inp[0].params.ep);
+ end1 = GetTrkEndPos(Dj.inp[1].trk,Dj.inp[1].params.ep);
+ if (Dj.inp[0].params.type == curveTypeStraight) {
+ a0 = DifferenceBetweenAngles(Dj.inp[0].params.angle,FindAngle(Dj.jRes.pos[0], pos));
+ na0 = NormalizeAngle( Dj.inp[0].params.angle +
+ ((a0>0.0)?90.0:-90.0));
+ } else {
+ na0 = Dj.inp[0].params.arcA0;
+ if (FindDistance(Dj.inp[0].params.arcP,pos)<Dj.inp[0].params.arcR)
+ na0 = NormalizeAngle(na0+180.0);
+ }
+ //Now Second Line offset
+ if (Dj.inp[1].params.type == curveTypeStraight) {
+ a1 = DifferenceBetweenAngles(Dj.inp[1].params.angle,FindAngle(pos, Dj.jRes.pos[0]));
+ na1 = NormalizeAngle( Dj.inp[1].params.angle +
+ ((a1>0.0)?90.0:-90.0));
+ } else {
+ na1 = Dj.inp[1].params.arcA0;
+ if (FindDistance(Dj.inp[1].params.arcP,Dj.jRes.pos[0])<Dj.inp[1].params.arcR)
+ na1 = NormalizeAngle(na1+180.0);
+ }
+ coOrd pos1 = pos;
+ if (AdjustPosToRadius(&pos1,desired_radius+(Dj.jointD[0].x), na0, na1)) {
+ if (Dj.inp[1].params.type == curveTypeStraight) {
+ FindPos( &off, &beyond, pos1, Dj.inp[1].params.lineOrig, Dj.inp[1].params.angle,
+ FindDistance(Dj.inp[1].params.lineOrig,Dj.inp[1].params.lineEnd) );
+ } else if (Dj.inp[1].params.type == curveTypeCurve) {
+ ANGLE_T a = FindAngle(Dj.inp[1].params.arcP,pos1);
+ if ((a>Dj.inp[1].params.arcA0+Dj.inp[1].params.arcA1) || (a< Dj.inp[1].params.arcA0)) {
+ beyond = 1.0;
+ }
+ }
+ //Suppress result unless on track and close to user position (when on track)
+ if (beyond>-0.01 && IsClose(FindDistance(pos,pos1))) {
+ pos = pos1;
+ DYNARR_APPEND(trkSeg_t,Dj.anchors,1);
+ trkSeg_p p = &DYNARR_LAST(trkSeg_t,Dj.anchors);
+ p->type= SEG_CRVLIN;
+ p->width = 0;
+ p->color = wDrawColorBlue;
+ p->u.c.center = pos;
+ p->u.c.a1= 360.0;
+ p->u.c.a0 = 0.0;
+ p->u.c.radius = tempD.scale*0.25/2;
+ }
+ }
+
+ }
+
+
tempSegs_da.cnt = 0;
tempSegs(0).color = drawColorBlack;
ok = FALSE;
/* Populate (Dj.inp[1]) */
+
if ( QueryTrack(Dj.inp[1].trk,Q_REFRESH_JOIN_PARAMS_ON_MOVE) ) {
if ( !GetTrackParams( PARAMS_2ND_JOIN, Dj.inp[1].trk, pos, &Dj.inp[1].params ) )
return C_CONTINUE;
}
+
+
beyond = 1.0;
switch ( Dj.inp[1].params.type ) {
case curveTypeCurve:
@@ -798,16 +1287,14 @@ errorReturn:
default:
AbortProg( "Bad track type %d", Dj.jRes.type );
}
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack );
if (!ok)
Dj.jRes.type = curveTypeNone;
return C_CONTINUE;
case C_UP:
-
if (Dj.state == 0) {
- if (easementVal<0)
- return CmdCornu(action, pos);
+ if (easementVal<0 && Dj.cornuMode)
+ return CmdCornu(action, pos);
else
return C_CONTINUE;
}
@@ -815,12 +1302,10 @@ errorReturn:
InfoMessage( _("Select 2nd track") );
return C_CONTINUE;
}
- DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, drawColorBlack );
tempSegs(0).color = drawColorBlack;
tempSegs_da.cnt = 0;
if (Dj.jRes.type == curveTypeNone) {
Dj.state = 1;
- DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
InfoMessage( _("Select 2nd track") );
return C_CONTINUE;
}
@@ -845,7 +1330,10 @@ errorReturn:
UndrawNewTrack( Dj.inp[1].trk );
ep = Dj.jRes.flip?1:0;
Dj.state = 0;
+ DYNARR_RESET(trkSeg_t,Dj.anchors);
rc = C_TERMINATE;
+ if (easementVal == 0.0)
+ wPrefSetFloat("misc", "desired_radius", desired_radius);
if ( (!JoinTracks( Dj.inp[0].trk, Dj.inp[0].params.ep, Dj.inp_pos[0],
trk, ep, Dj.jRes.pos[0], &Dj.jointD[0] ) ) ||
(!JoinTracks( Dj.inp[1].trk, Dj.inp[1].params.ep, Dj.inp_pos[1],
@@ -856,24 +1344,34 @@ errorReturn:
DrawNewTrack( Dj.inp[0].trk );
DrawNewTrack( Dj.inp[1].trk );
DrawNewTrack( trk );
+ if (infoSubst)
+ InfoSubstituteControls(NULL, NULL);
+ infoSubst = FALSE;
return rc;
case C_CANCEL:
- case C_REDRAW:
-
+ if (infoSubst)
+ InfoSubstituteControls(NULL, NULL);
+ infoSubst = FALSE;
+ break;
+ case C_REDRAW:
if ( Dj.joinMoveState == 1 || Dj.state == 1 ) {
DrawFillCircle( &tempD, Dj.inp[0].pos, 0.10*mainD.scale, selectedColor );
- } else if (easementVal<0 )
- return CmdCornu(action,pos);
-
+ } else if (easementVal<0 && Dj.joinMoveState == 0)
+ return CmdCornu(action,pos);
+ if (Dj.anchors.cnt)
+ DrawSegs(&tempD, zero, 0.0, &(((trkSeg_t *)Dj.anchors.ptr)[0]), Dj.anchors.cnt,trackGauge,wDrawColorBlack);
DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack );
break;
case C_TEXT:
case C_OK:
- if (easementVal<0 )
- return CmdCornu(action,pos);
+ if (easementVal<0 && Dj.cornuMode)
+ return CmdCornu(action,pos);
+ if (infoSubst)
+ InfoSubstituteControls(NULL, NULL);
+ infoSubst = FALSE;
}
@@ -889,10 +1387,14 @@ errorReturn:
*/
#include "bitmaps/join.xpm"
+#include "bitmaps/joinline.xpm"
void InitCmdJoin( wMenu_p menu )
{
- joinCmdInx = AddMenuButton( menu, CmdJoin, "cmdJoin", _("Join"), wIconCreatePixMap(join_xpm), LEVEL0_50, IC_STICKY|IC_POPUP, ACCL_JOIN, NULL );
+ ButtonGroupBegin( _("Join"), "cmdJoinSetCmd", _("Join") );
+ joinCmdInx = AddMenuButton( menu, CmdJoin, "cmdJoinTrack", _("Join Track"), wIconCreatePixMap(join_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_JOIN, NULL );
+ AddMenuButton( menu, CmdJoinLine, "cmdJoinLine", _("Join Lines"), wIconCreatePixMap(joinline_xpm), LEVEL0_50, IC_STICKY|IC_POPUP|IC_WANT_MOVE, ACCL_JOIN, NULL );
+ ButtonGroupEnd();
log_join = LogFindIndex( "join" );
}