summaryrefslogtreecommitdiff
path: root/app/bin/tease.c
diff options
context:
space:
mode:
Diffstat (limited to 'app/bin/tease.c')
-rw-r--r--app/bin/tease.c1950
1 files changed, 1950 insertions, 0 deletions
diff --git a/app/bin/tease.c b/app/bin/tease.c
new file mode 100644
index 0000000..3667fe1
--- /dev/null
+++ b/app/bin/tease.c
@@ -0,0 +1,1950 @@
+/*
+ * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/tease.c,v 1.2 2008-01-20 23:29:15 mni77 Exp $
+ *
+ * TRANSISTION-CURVES (JOINTS)
+ *
+ */
+
+/* XTrkCad - Model Railroad CAD
+ * Copyright (C) 2005 Dave Bullis
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+
+Transistion-curves (aka joints or spirals) connect curves with different
+radius (including straights which have infinite radius, indicated by radius=0).
+The curve is described by 2 control parameters: R and L.
+L is the length along the tangent of the curve and
+R is the radius of an arc at the end of the curve.
+At any point (l) along the tangent the arc at that point has radius
+r=(R*L)/l.
+The transition curve offset (x) is the closest distance between the arc
+and the tangent.
+The center of any arc is at (l/2, r+x).
+See 'ComputeJointPos()' for details on this.
+
+Warning crude ascii graphics!
+
+a aa
+ aaa aaa *
+ aaaa aaaa *
+ aaaaa aaaaa ***
+ aaaaaaa aaaaaa ****
+ aaaaaaa aaaaaaa *****
+ aaaaaaaaaaaaaaaaaaaa ******
+ ^ *******
+ x ********
+ *******v*
+0*****************************TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+ L/2 L
+
+'R' and 'L' are curve control parameters.
+'0' is curve origin.
+'**..TT' is tangent line.
+'a' is arc with radius 'R'.
+'*' is the transisition curve.
+'x' is transisition curve offset.
+
+For a better representation of this, build 'testjoin' and
+do 'testjoin psplot 10 10 40 1 | lpr -Ppostscript'
+*/
+
+
+#include "track.h"
+#include "ccurve.h"
+#include "cstraigh.h"
+#include "cjoin.h"
+#include "i18n.h"
+
+static TRKTYP_T T_EASEMENT = -1;
+
+static ANGLE_T JOINT_ANGLE_INCR = 2.0;
+
+struct extraData {
+ DIST_T l0, l1; /* curve start and end parameter */
+ DIST_T R, L; /* curve control parameters */
+ BOOL_T flip; /* T: endPt[1] - is l0 */
+ BOOL_T negate; /* T: curves to the left */
+ BOOL_T Scurve; /* T: is an S-curve */
+ coOrd pos; /* Pos of origin */
+ ANGLE_T angle; /* Angle of curve tangent */
+ };
+
+#define xl0 extraData->l0
+#define xl1 extraData->l1
+#define xR extraData->R
+#define xL extraData->L
+#define xflip extraData->flip
+#define xnegate extraData->negate
+#define xScurve extraData->Scurve
+#define xpos extraData->pos
+#define xangle extraData->angle
+
+#define EASE_MIN_X (0.01)
+
+static int log_ease;
+static int log_traverseJoint;
+
+
+static DIST_T FindL(
+ DIST_T r,
+ DIST_T R,
+ DIST_T L )
+/*
+ * Given a radius (r) return control value (l).
+ * This function is it's inverse!
+ */
+{
+ return (r==0.0)?L:(R*L)/r;
+}
+
+
+static void GetLandD(
+ DIST_T *RL,
+ DIST_T *RD,
+ coOrd q,
+ coOrd p,
+ ANGLE_T a,
+ DIST_T R,
+ DIST_T L,
+ BOOL_T negate,
+ BOOL_T Scurve )
+{
+ DIST_T l, d, x;
+
+ q.x -= p.x;
+ q.y -= p.y;
+ Rotate( &q, zero, -a );
+ l = q.y;
+ x = (l*l*l)/(6*R*L);
+ if (!negate) {
+ d = q.x - x;
+ } else {
+ d = q.x + x;
+ }
+ if (RL)
+ *RL = l;
+ if (RD)
+ *RD = d;
+}
+
+
+int OLDEASE = 0;
+static void ComputeJoinPos(
+ DIST_T l,
+ DIST_T R,
+ DIST_T L,
+ DIST_T *RR,
+ ANGLE_T *RA,
+ coOrd *P,
+ coOrd *PC )
+/*
+ * Compute position along transition-curve.
+ * Also compute angle and position of tangent circle's center.
+ */
+{
+ ANGLE_T a;
+ DIST_T r;
+ coOrd pp, pc;
+ if (l==0.0)
+ r = 100000.0;
+ else
+ r = (R*L)/l;
+ pp.y = l;
+ pc.y = l/2.0;
+ a = asin( l/2.0 / r );
+if (OLDEASE){
+ pc.x = l*l / (24*r) + r;
+ pp.x = pc.x - r*cos(a);
+}else{
+ pp.x = (l*l*l)/(6*R*L);
+ pc.x = pp.x + r*cos(a);
+}
+/*lprintf( "A %0.3f %0.3f %0.3f [%0.3f %0.3f]\n", a, aa, aaa, q.x, q.y );*/
+ if (P)
+ *P = pp;
+ if (PC)
+ *PC = pc;
+ if (RR)
+ *RR = r;
+ if (RA)
+ *RA = R2D(a);
+}
+
+static DIST_T JoinD(
+ DIST_T l,
+ DIST_T R,
+ DIST_T L )
+/*
+ * Compute distance from transition-curve origin to specified point.
+ * Distance is approximately equal to length of arc from origin
+ * to specified point with radius = 2.0 * radius at point.
+ * This is a very good approximation (< 0.1%).
+ */
+{
+ DIST_T rr1, d1;
+ ANGLE_T a1;
+ coOrd p0;
+ DIST_T sign = 1;
+ if ( l < 0 ) {
+ sign = -1;
+ l = -l;
+ }
+ ComputeJoinPos( l, R, L, &rr1, NULL, &p0, NULL );
+ rr1 *= 2.0;
+ a1=asin(sqrt(p0.x*p0.x + p0.y*p0.y)/2.0/rr1);
+ d1 = rr1 * a1 * 2.0;
+ return d1*sign;
+}
+
+
+static DIST_T GetLfromD(
+ DIST_T D,
+ DIST_T R,
+ DIST_T L )
+{
+ DIST_T deltaD, d, l, deltaL;
+ l = L/2.0;
+ deltaL = L/4.0;
+ while ( deltaL>0.0001 ) {
+ d = JoinD(l,R,L);
+ if ( d < D ) {
+ deltaD = D-d;
+ } else {
+ deltaD = d-D;
+ }
+ if ( deltaD < 0.000001 )
+ return l;
+ if ( d < D )
+ l += deltaL;
+ else
+ l -= deltaL;
+ deltaL /= 2.0;
+ }
+/*printf( "GetLfromD( %0.3f %0.3f %0.3f ) = %0.3f\n", D, R, L, l );*/
+ return l;
+}
+
+
+#ifdef LATER
+static void JoinDistance(
+ DIST_T r,
+ DIST_T R,
+ DIST_T X,
+ DIST_T L,
+ DIST_T *dr,
+ DIST_T *xr,
+ DIST_T *lr )
+{
+ DIST_T l, d, rr;
+ coOrd p, pc;
+ if (r == 0.0) {
+ *dr = 0.0;
+ *lr = *xr = 0.0;
+ return;
+ }
+ l = FindL( r, R, L );
+ d = JoinD( l, R, L );
+ ComputeJoinPos( l, R, L, NULL, NULL, &p, NULL );
+LOG( log_ease, 2, ( "joinDistance r=%0.3f rr=%0.3f\n", r, rr ) )
+ *xr = pc.x - rr;
+ *dr = d;
+ *lr = pc.y;
+}
+#endif
+
+EXPORT STATUS_T ComputeJoint(
+ DIST_T r0,
+ DIST_T r1,
+ easementData_t * e )
+/*
+ * Compute joint data given radius of the 2 curves being joined.
+ * Radius is =0 for straight tracks and <0 for left-handed curves.
+ * S-curves are handled by treating them as 2 transition-curves joined
+ * origin to origin.
+ */
+{
+ DIST_T t, l0, l1, d0, d1, rr0, rr1, xx;
+ ANGLE_T a, a0, a1;
+ coOrd rp0, rpc0, rp1, rpc1;
+
+LOG( log_ease, 4, ( "ComputeJoint( %0.3f, %0.3f )\n", r0, r1 ) )
+
+ if (easementVal <= 0.1) {
+ e->d0 = e->d1 = e->x = 0.0;
+ return E_NOTREQ;
+ }
+ if (r0 != 0.0 && fabs(r0) < easeR) {
+ ErrorMessage( MSG_RADIUS_LSS_EASE_MIN,
+ FormatDistance(fabs(r0)), FormatDistance(easeR) );
+ e->d0 = e->d1 = e->x = 0.0;
+ return E_ERROR;
+ }
+ if (r1 != 0.0 && fabs(r1) < easeR) {
+ ErrorMessage( MSG_RADIUS_LSS_EASE_MIN, FormatDistance(fabs(r1)), FormatDistance(easeR) );
+ e->d0 = e->d1 = e->x = 0.0;
+ return E_ERROR;
+ }
+ if (r0 == 0.0 && r1 == 0.0) {
+ /* ASSERT( FALSE ); CHECKME */
+ e->d0 = e->d1 = e->x = 0.0;
+ return E_NOTREQ;
+ }
+ e->r0 = r0;
+ e->r1 = r1;
+ e->Scurve = FALSE;
+ if ( ! ( (r0 >= 0 && r1 >= 0) || (r0 <= 0 && r1 <= 0) ) ) {
+ /* S-curve */
+ e->Scurve = TRUE;
+ e->flip = FALSE;
+ e->negate = (r0 > 0.0);
+ l0 = FindL( fabs(r0), easeR, easeL );
+ ComputeJoinPos( l0, easeR, easeL, &rr0, NULL, &rp0, &rpc0 );
+ l1 = FindL( fabs(r1), easeR, easeL );
+ ComputeJoinPos( l1, easeR, easeL, &rr1, NULL, &rp1, &rpc1 );
+ rp1.x = - rp1.x;
+ rp1.y = - rp1.y;
+ rpc1.x = - rpc1.x;
+ rpc1.y = - rpc1.y;
+ xx = FindDistance(rpc0, rpc1) - rr0 - rr1;
+ a0 = NormalizeAngle( FindAngle(rpc0, rp0) - FindAngle(rpc0, rpc1) );
+ a1 = NormalizeAngle( FindAngle(rpc1, rp1) - FindAngle(rpc1, rpc0) );
+ d0 = fabs( rr0 * D2R(a0) );
+ d1 = fabs( rr1 * D2R(a1) );
+ } else {
+ /* ! S-curve */
+ e->negate = ( (r0==0.0||r1==0.0)? r0>r1 : r0<r1 );
+ r0 = fabs(r0);
+ r1 = fabs(r1);
+ e->flip = FALSE;
+ if ( r1 == 0 || (r0 != 0 && r1 > r0 ) ) {
+ e->flip = TRUE;
+ t=r0; r0=r1; r1=t;
+ }
+ if (r0 == 0) {
+ if (r1 == 0) {
+ xx = l0 = l1 = d0 = d1 = 0.0;
+ } else {
+ l0 = 0.0;
+ l1 = FindL( r1, easeR, easeL );
+ ComputeJoinPos( l1, easeR, easeL, &rr1, NULL, &rp1, &rpc1 );
+ d0 = rpc1.y;
+ a1 = FindAngle(rpc1, rp1) - 270.0;
+ d1 = rr1 * D2R(a1);
+ xx = rpc1.x - rr1;
+ }
+ } else {
+ l0 = FindL( r0, easeR, easeL );
+ ComputeJoinPos( l0, easeR, easeL, &rr0, NULL, &rp0, &rpc0 );
+ l1 = FindL( r1, easeR, easeL );
+ ComputeJoinPos( l1, easeR, easeL, &rr1, NULL, &rp1, &rpc1 );
+ a = FindAngle( rpc0, rpc1 );
+ a0 = a - FindAngle(rpc0, rp0);/*???*/
+ a1 = FindAngle(rpc1, rp1) - a;
+ xx = rr0 - ( rr1 + FindDistance(rpc0, rpc1) );
+ d0 = rr0 * D2R(a0);
+ d1 = rr1 * D2R(a1);
+ }
+ }
+LOG( log_ease, 2, ( "CJoint(%0.3f %0.3f) l0=%0.3f d0=%0.3f l1=%0.3f d1=%0.3f x=%0.3f S%d F%d N%d\n",
+ e->r0, e->r1, l0, d0, l1, d1, xx, e->Scurve, e->flip, e->negate ) )
+ if (xx < EASE_MIN_X || d0+d1<=minLength) {
+ e->d0 = e->d1 = e->x = 0.0;
+ return E_NOTREQ;
+ } else {
+ if (!e->flip) {
+ e->d0 = d0;
+ e->d1 = d1;
+ e->l0 = l0;
+ e->l1 = l1;
+ } else {
+ e->d0 = d1;
+ e->d1 = d0;
+ e->l0 = l1;
+ e->l1 = l0;
+ }
+ e->x = xx;
+ return E_REQ;
+ }
+}
+
+static track_p NewJoint(
+ coOrd pos0,
+ ANGLE_T angle0,
+ coOrd pos1,
+ ANGLE_T angle1,
+ DIST_T trackGauge,
+ DIST_T R,
+ DIST_T L,
+ easementData_t * e )
+/*
+ * Allocate a joint track segment.
+ * Allocate a track, save relevant data from (*e),
+ * and compute origin and angle of transition-curve.
+ * Position is determined relative to endPoints.
+ */
+{
+ track_p trk;
+ struct extraData *xx;
+ coOrd p, p0, p1, q0, q1;
+ static coOrd qZero = { 0.0, 0.0 };
+ ANGLE_T az0, a01, b, b01, b1, d, d1;
+ trk = NewTrack( 0, T_EASEMENT, 2, sizeof *xx );
+ SetTrkScale( trk, curScaleInx );
+ xx = GetTrkExtraData( trk );
+ SetTrkEndPoint( trk, 0, pos0, NormalizeAngle(angle0+180.0) );
+ SetTrkEndPoint( trk, 1, pos1, NormalizeAngle(angle1+180.0) );
+ xx->R = R;
+ xx->L = L;
+ xx->flip = e->flip;
+ xx->negate = e->negate;
+ xx->Scurve = e->Scurve;
+ if (!e->flip) {
+ xx->l0 = e->l0;
+ xx->l1 = e->l1;
+ p0 = pos0;
+ p1 = pos1;
+ } else {
+ xx->l0 = e->l1;
+ xx->l1 = e->l0;
+ p0 = pos1;
+ p1 = pos0;
+ }
+ ComputeJoinPos( xx->l0, R, L, NULL, NULL, &q0, NULL );
+ ComputeJoinPos( xx->l1, R, L, NULL, NULL, &q1, NULL );
+ if (e->negate) {
+ q0.x = -q0.x;
+ q1.x = -q1.x;
+ }
+ b01 = FindAngle( p0, p1 );
+ if (!e->Scurve) {
+ az0 = FindAngle( qZero, q0 );
+ a01 = FindAngle( q0, q1 );
+ b1 = NormalizeAngle( b01 - (a01+az0) );
+ b = NormalizeAngle( b01 - a01 );
+ } else {
+ q1.x = -q1.x;
+ q1.y = -q1.y;
+ az0 = FindAngle( qZero, q0 );
+ a01 = FindAngle( q0, q1 );
+ b = NormalizeAngle( b01 - a01 );
+ }
+ /*a = NormalizeAngle(a0+a1-90.0);*/
+ p = q0;
+ Rotate( &p, qZero, b );
+ xx->pos.x = p0.x - p.x;
+ xx->pos.y = p0.y - p.y;
+ xx->angle = b;
+ ComputeBoundingBox( trk );
+ d = FindDistance( p0, p1 );
+ d1 = FindDistance( q0, q1 );
+LOG( log_ease, 1, ( "NewJoint( [%0.3f %0.3f] A%0.3f, [%0.3f %0.3f] A%0.3f\n B01=%0.3f AZ0=%0.3f A01=%0.3f B=%0.3f D0=%0.3f D1=%0.3f\n",
+ pos0.x, pos0.y, angle0, pos1.x, pos1.y, angle1,
+ b01, az0, a01, b, d, d1 ) )
+ CheckTrackLength( trk );
+ return trk;
+}
+
+/****************************************
+ *
+ * GENERIC FUNCTIONS
+ *
+ */
+
+static DIST_T GetLengthJoint( track_p trk )
+{
+ struct extraData *xx;
+ DIST_T d0, d1;
+ xx = GetTrkExtraData(trk);
+ d0 = JoinD( xx->l0, xx->R, xx->L );
+ d1 = JoinD( xx->l1, xx->R, xx->L );
+ if (xx->Scurve)
+ return d0+d1;
+ else
+ return fabs( d0-d1 );
+}
+
+
+static struct {
+ coOrd endPt[2];
+ DIST_T elev[2];
+ FLOAT_T length;
+ coOrd orig;
+ ANGLE_T angle;
+ DIST_T r;
+ DIST_T l;
+ DIST_T l0;
+ DIST_T l1;
+ FLOAT_T grade;
+ descPivot_t pivot;
+ LAYER_T layerNumber;
+ } jointData;
+typedef enum { E0, Z0, E1, Z1, OR, AL, RR, LL, L0, L1, GR, PV, LY } jointDesc_e;
+static descData_t jointDesc[] = {
+/*E0*/ { DESC_POS, N_("End Pt 1: X"), &jointData.endPt[0] },
+/*Z0*/ { DESC_DIM, N_("Z"), &jointData.elev[0] },
+/*E1*/ { DESC_POS, N_("End Pt 2: X"), &jointData.endPt[1] },
+/*Z1*/ { DESC_DIM, N_("Z"), &jointData.elev[1] },
+/*OR*/ { DESC_POS, N_("Origin: X"), &jointData.orig },
+/*AL*/ { DESC_ANGLE, N_("Angle"), &jointData.angle },
+/*RR*/ { DESC_DIM, N_("R"), &jointData.r },
+/*LL*/ { DESC_DIM, N_("L"), &jointData.l },
+/*L0*/ { DESC_DIM, N_("l0"), &jointData.l0 },
+/*L1*/ { DESC_DIM, N_("l1"), &jointData.l1 },
+/*GR*/ { DESC_FLOAT, N_("Grade"), &jointData.grade },
+/*PV*/ { DESC_PIVOT, N_("Pivot"), &jointData.pivot },
+/*LY*/ { DESC_LAYER, N_("Layer"), &jointData.layerNumber },
+ { DESC_NULL } };
+
+static void UpdateJoint( track_p trk, int inx, descData_p descUpd, BOOL_T final )
+{
+ EPINX_T ep;
+ switch (inx) {
+ case Z0:
+ case Z1:
+ ep = (inx==Z0?0:1);
+ UpdateTrkEndElev( trk, ep, GetTrkEndElevUnmaskedMode(trk,ep), jointData.elev[ep], NULL );
+ ComputeElev( trk, 1-ep, FALSE, &jointData.elev[1-ep], NULL );
+ if ( jointData.length > minLength )
+ jointData.grade = fabs( (jointData.elev[0]-jointData.elev[1])/jointData.length )*100.0;
+ else
+ jointData.grade = 0.0;
+ jointDesc[GR].mode |= DESC_CHANGE;
+ jointDesc[inx==Z0?Z1:Z0].mode |= DESC_CHANGE;
+ return;
+ case LY:
+ SetTrkLayer( trk, jointData.layerNumber );
+ break;
+ default:
+ return;
+ }
+}
+
+
+static void DescribeJoint(
+ track_p trk,
+ char * str,
+ CSIZE_T len )
+/*
+ * Print some interesting info about the track.
+ */
+{
+ struct extraData *xx = GetTrkExtraData(trk);
+ int fix0, fix1;
+
+ sprintf( str, _("Joint Track(%d): Layer=%d Length=%0.3f EP=[%0.3f,%0.3f A%0.3f] [%0.3f,%0.3f A%0.3f]"), GetTrkIndex(trk),
+ GetTrkLayer(trk)+1,
+ GetLengthJoint( trk ),
+ GetTrkEndPosXY(trk,0), GetTrkEndAngle(trk,0),
+ GetTrkEndPosXY(trk,1), GetTrkEndAngle(trk,1) );
+
+ fix0 = GetTrkEndTrk(trk,0)!=NULL;
+ fix1 = GetTrkEndTrk(trk,1)!=NULL;
+
+ jointData.endPt[0] = GetTrkEndPos(trk,0);
+ jointData.endPt[1] = GetTrkEndPos(trk,1);
+ jointData.length = GetLengthJoint(trk);
+ jointData.orig = xx->pos;
+ jointData.angle = xx->angle;
+ jointData.r = xx->R;
+ jointData.l = xx->L;
+ jointData.l0 = xx->l0;
+ jointData.l1 = xx->l1;
+ jointData.layerNumber = GetTrkLayer(trk);
+ ComputeElev( trk, 0, FALSE, &jointData.elev[0], NULL );
+ ComputeElev( trk, 1, FALSE, &jointData.elev[1], NULL );
+ if ( jointData.length > minLength )
+ jointData.grade = fabs( (jointData.elev[0]-jointData.elev[1])/jointData.length )*100.0;
+ else
+ jointData.grade = 0.0;
+
+ jointDesc[E0].mode =
+ jointDesc[E1].mode =
+ jointDesc[OR].mode =
+ jointDesc[AL].mode =
+ jointDesc[RR].mode =
+ jointDesc[LL].mode =
+ jointDesc[L0].mode =
+ jointDesc[L1].mode =
+ DESC_RO;
+ jointDesc[Z0].mode = (EndPtIsDefinedElev(trk,0)?0:DESC_RO)|DESC_NOREDRAW;
+ jointDesc[Z1].mode = (EndPtIsDefinedElev(trk,1)?0:DESC_RO)|DESC_NOREDRAW;
+ jointDesc[GR].mode = DESC_RO;
+ jointDesc[PV].mode = (fix0|fix1)?DESC_IGNORE:0;
+ jointDesc[LY].mode = DESC_NOREDRAW;
+ jointData.pivot = (fix0&fix1)?DESC_PIVOT_NONE:
+ fix0?DESC_PIVOT_FIRST:
+ fix1?DESC_PIVOT_SECOND:
+ DESC_PIVOT_MID;
+
+ DoDescribe( _("Easement Track"), trk, jointDesc, UpdateJoint );
+}
+
+static void GetJointPos(
+ coOrd * RP,
+ ANGLE_T * RA,
+ DIST_T l,
+ DIST_T R,
+ DIST_T L,
+ coOrd P,
+ ANGLE_T A,
+ BOOL_T N )
+/*
+ * Compute position of point on transition-curve.
+ */
+{
+ coOrd p1;
+ static coOrd pZero = {0.0,0.0};
+ ComputeJoinPos( l, R, L, NULL, RA, &p1, NULL );
+ if (N)
+ p1.x = -p1.x;
+ Rotate( &p1, pZero, A );
+ if (RP) {
+ RP->x = P.x + p1.x;
+ RP->y = P.y + p1.y;
+ }
+ if (RA)
+ *RA = NormalizeAngle( A + (N?-*RA:*RA) );
+}
+
+
+EXPORT DIST_T JointDistance(
+ coOrd * q,
+ coOrd pos,
+ ANGLE_T angle,
+ DIST_T l0,
+ DIST_T l1,
+ DIST_T R,
+ DIST_T L,
+ BOOL_T negate,
+ BOOL_T Scurve )
+{
+ DIST_T d, l;
+ coOrd p0 = *q;
+ GetLandD( &l, &d, p0, pos, angle, R, L, negate, Scurve );
+ if (Scurve) {
+ if ( l < -l1 )
+ l = -l1;
+ else if ( l > l0 )
+ l = l0;
+ } else {
+ if ( l < l0 )
+ l = l0;
+ else if ( l > l1 )
+ l = l1;
+ }
+ GetJointPos( q, NULL, l, R, L, pos, angle, negate );
+ d = FindDistance( p0, *q );
+ return d;
+}
+
+
+static DIST_T DistanceJoint(
+ track_p trk,
+ coOrd * p )
+/*
+ * Determine how close (p) is to (t).
+ */
+{
+ struct extraData * xx = GetTrkExtraData(trk);
+ return JointDistance( p, xx->pos, xx->angle, xx->l0, xx->l1, xx->R, xx->L, xx->negate, xx->Scurve );
+}
+
+
+#ifdef LATER
+static void DrawJointSegment1(
+ drawCmd_p d,
+ wIndex_t cnt,
+ DIST_T l0,
+ DIST_T l1,
+ DIST_T R,
+ DIST_T L,
+ coOrd P,
+ ANGLE_T A,
+ BOOL_T N,
+ track_p trk,
+ DIST_T trackGauge,
+ wDrawColor color )
+/*
+ * Draw a transition-curve from (l0) to (l1),
+ * at angle (A) from origin (P).
+ */
+{
+ DIST_T l, lincr;
+ wIndex_t i;
+ coOrd p0, p1;
+ long widthOptions = DTS_RIGHT|DTS_LEFT|DTS_TIES;
+
+ if (GetTrkWidth(trk) == 2)
+ widthOptions |= DTS_THICK2;
+ if (GetTrkWidth(trk) == 3)
+ widthOptions |= DTS_THICK3;
+
+ l = l0;
+ lincr = (l1-l0)/cnt;
+ GetJointPos( &p0, NULL, l0, R, L, P, A, N );
+ for (i=1; i<=cnt; i++) {
+ l += lincr;
+ GetJointPos( &p1, NULL, l, R, L, P, A, N );
+ DrawStraightTrack( d, p0, p1,
+ FindAngle( p1, p0 ), trk, trackGauge, color, widthOptions );
+ p0 = p1;
+ }
+}
+#endif
+
+static void DrawJointSegment(
+ drawCmd_p d,
+ wIndex_t cnt,
+ DIST_T l0,
+ DIST_T l1,
+ DIST_T R,
+ DIST_T L,
+ coOrd P,
+ ANGLE_T A,
+ BOOL_T N,
+ DIST_T trackGauge,
+ wDrawColor color,
+ long widthOptions,
+ track_p trk )
+/*
+ * Draw a transition-curve from (l0) to (l1),
+ * at angle (A) from origin (P).
+ */
+{
+ DIST_T ll;
+ wIndex_t i;
+ coOrd p0, p1;
+ ANGLE_T a0, a1;
+ int cnt1;
+
+ ComputeJoinPos( l0, R, L, NULL, &a0, NULL, NULL );
+ ComputeJoinPos( l1, R, L, NULL, &a1, NULL, NULL );
+ a1 = a1-a0;
+ if ( (d->options&DC_QUICK) ) {
+ cnt1 = 1;
+ } else {
+ cnt1 = (int)floor(a1/JOINT_ANGLE_INCR) + 1;
+ a1 /= cnt1;
+ }
+
+ widthOptions |= DTS_RIGHT|DTS_LEFT|DTS_TIES;
+ GetJointPos( &p0, NULL, l0, R, L, P, A, N );
+ for (i=1; i<=cnt1; i++) {
+ a0 += a1;
+ ll = sqrt( sin(D2R(a0)) * 2 * R * L );
+ GetJointPos( &p1, NULL, ll, R, L, P, A, N );
+ DrawStraightTrack( d, p0, p1, FindAngle( p1, p0 ), trk, trackGauge,
+ color, widthOptions );
+ p0 = p1;
+ }
+}
+
+
+EXPORT coOrd GetJointSegEndPos(
+ coOrd pos,
+ ANGLE_T angle,
+ DIST_T l0,
+ DIST_T l1,
+ DIST_T R,
+ DIST_T L,
+ BOOL_T negate,
+ BOOL_T flip,
+ BOOL_T Scurve,
+ EPINX_T ep,
+ ANGLE_T * angleR )
+{
+ coOrd p1;
+ DIST_T ll;
+ if ( flip ) ep = 1-ep;
+ ll = (ep==0?l0:l1);
+ if ( Scurve ) {
+ if ( ep==1 )
+ angle += 180;
+ }
+ GetJointPos( &p1, &angle, ll, R, L, pos, angle, negate );
+ if ( angleR ) {
+ if ( (!Scurve) && ep==0 )
+ angle = NormalizeAngle(angle+180);
+ *angleR = angle;
+ }
+ return p1;
+}
+
+
+EXPORT void DrawJointTrack(
+ drawCmd_p d,
+ coOrd pos,
+ ANGLE_T angle,
+ DIST_T l0,
+ DIST_T l1,
+ DIST_T R,
+ DIST_T L,
+ BOOL_T negate,
+ BOOL_T flip,
+ BOOL_T Scurve,
+ track_p trk,
+ EPINX_T ep0,
+ EPINX_T ep1,
+ DIST_T trackGauge,
+ wDrawColor color,
+ long options )
+{
+ wIndex_t cnt;
+ DIST_T len;
+ trkSeg_p segPtr;
+
+ if ( (d->options&DC_SEGTRACK) ) {
+ DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 );
+ segPtr = &tempSegs(tempSegs_da.cnt-1);
+ segPtr->type = SEG_JNTTRK;
+ segPtr->width = 0;
+ segPtr->color = wDrawColorBlack;
+ segPtr->u.j.pos = pos;
+ segPtr->u.j.angle = angle;
+ segPtr->u.j.l0 = l0;
+ segPtr->u.j.l1 = l1;
+ segPtr->u.j.R = R;
+ segPtr->u.j.L = L;
+ segPtr->u.j.negate = negate;
+ segPtr->u.j.flip = flip;
+ segPtr->u.j.Scurve = Scurve;
+ return;
+ }
+LOG( log_ease, 4, ( "DJT( (X%0.3f Y%0.3f A%0.3f) \n", pos.x, pos.y, angle ) )
+#ifdef LATER
+ scale2rail = (d->options&DC_PRINT)?(twoRailScale*2+1):twoRailScale;
+
+ if (options&DTS_THICK2)
+ width = 2;
+ if (options&DTS_THICK3)
+ width = 3;
+#ifdef WINDOWS
+ width *= (wDrawWidth)(d->dpi/mainD.dpi);
+#else
+ if (d->options&DC_PRINT)
+ width *= 300/75;
+#endif
+#endif
+ if (color == wDrawColorBlack)
+ color = normalColor;
+ if (!Scurve) {
+ /* print segments about 0.20" long */
+ len = (l0-l1)/(0.20*d->scale);
+ cnt = (int)ceil(fabs(len));
+ if (cnt == 0 || (d->options&DC_QUICK)) cnt = 1;
+ DrawJointSegment( d, cnt, l0, l1, R, L, pos,
+ angle, negate, trackGauge, color, options, trk );
+ } else {
+ /* print segments about 0.20" long */
+ cnt = (int)ceil((l0)/(0.20*d->scale));
+ if (cnt == 0 || (d->options&DC_QUICK)) cnt = 1;
+ DrawJointSegment( d, cnt, 0, l0, R, L, pos,
+ angle, negate, trackGauge, color, options, trk );
+ cnt = (int)ceil((l1)/(0.20*d->scale));
+ if (cnt == 0 || (d->options&DC_QUICK)) cnt = 1;
+ DrawJointSegment( d, cnt, 0, l1, R, L, pos,
+ angle+180, negate, trackGauge, color, options, trk );
+ }
+ if ( (d->funcs->options & wDrawOptTemp) == 0 && (d->options&DC_QUICK) == 0 ) {
+ DrawEndPt( d, trk, ep0, color );
+ DrawEndPt( d, trk, ep1, color );
+ }
+}
+
+
+static void DrawJoint(
+ track_p trk,
+ drawCmd_p d,
+ wDrawColor color )
+/*
+ * Draw a transition-curve.
+ */
+{
+ struct extraData * xx = GetTrkExtraData(trk);
+ long widthOptions = 0;
+
+ if (GetTrkWidth(trk) == 2)
+ widthOptions = DTS_THICK2;
+ if (GetTrkWidth(trk) == 3)
+ widthOptions = DTS_THICK3;
+ DrawJointTrack( d, xx->pos, xx->angle, xx->l0, xx->l1, xx->R, xx->L, xx->negate, xx->flip, xx->Scurve, trk, 0, 1, GetTrkGauge(trk), color, widthOptions );
+}
+
+
+static void DeleteJoint(
+ track_p t )
+/* Delete track - nothing to do */
+{
+}
+
+static BOOL_T WriteJoint(
+ track_p t,
+ FILE * f )
+/*
+ * Write track data to a file (f).
+ */
+{
+ struct extraData * xx = GetTrkExtraData(t);
+ BOOL_T rc = TRUE;
+ rc &= fprintf(f, "JOINT %d %d %ld 0 0 %s %d %0.6f %0.6f %0.6f %0.6f %d %d %d %0.6f %0.6f 0 %0.6f\n",
+ GetTrkIndex(t), GetTrkLayer(t), (long)GetTrkWidth(t),
+ GetTrkScaleName(t), GetTrkVisible(t), xx->l0, xx->l1, xx->R, xx->L,
+ xx->flip, xx->negate, xx->Scurve, xx->pos.x, xx->pos.y, xx->angle )>0;
+ rc &= WriteEndPt( f, t, 0 );
+ rc &= WriteEndPt( f, t, 1 );
+ rc &= fprintf(f, "\tEND\n" )>0;
+ return rc;
+}
+
+static void ReadJoint(
+ char * line )
+/*
+ * Read track data from a file (f).
+ */
+{
+ track_p trk;
+ TRKINX_T index;
+ BOOL_T visible;
+ struct extraData e, *xx;
+ char scale[10];
+ wIndex_t layer;
+ long options;
+ DIST_T elev;
+
+ if ( !GetArgs( line+6, paramVersion<3?"dXZsdffffdddpYf":paramVersion<9?"dLl00sdffffdddpYf":"dLl00sdffffdddpff",
+ &index, &layer, &options, scale, &visible, &e.l0, &e.l1, &e.R, &e.L,
+ &e.flip, &e.negate, &e.Scurve, &e.pos, &elev, &e.angle) )
+ return;
+ trk = NewTrack( index, T_EASEMENT, 0, sizeof e );
+ xx = GetTrkExtraData(trk);
+ SetTrkVisible(trk, visible);
+ SetTrkScale(trk, LookupScale(scale));
+ SetTrkLayer(trk, layer);
+ SetTrkWidth(trk, (int)(options&3));
+ *xx = e;
+ ReadSegs();
+ SetEndPts( trk, 2 );
+ ComputeBoundingBox( trk );
+}
+
+static void MoveJoint(
+ track_p trk,
+ coOrd orig )
+/*
+ * Move a track.
+ */
+{
+ struct extraData * xx = GetTrkExtraData(trk);
+ xx->pos.x += orig.x;
+ xx->pos.y += orig.y;
+ ComputeBoundingBox( trk );
+}
+
+static void RotateJoint(
+ track_p trk,
+ coOrd orig,
+ ANGLE_T angle )
+/*
+ * Rotate a track.
+ */
+{
+ struct extraData * xx = GetTrkExtraData(trk);
+ Rotate( &xx->pos, orig, angle );
+ xx->angle = NormalizeAngle( xx->angle+angle );
+ ComputeBoundingBox( trk );
+}
+
+
+static void RescaleJoint( track_p trk, FLOAT_T ratio )
+{
+ struct extraData *xx = GetTrkExtraData(trk);
+ xx->pos.x *= ratio;
+ xx->pos.y *= ratio;
+ xx->R *= ratio;
+ xx->L *= ratio;
+ xx->l0 *= ratio;
+ xx->l1 *= ratio;
+}
+
+
+static ANGLE_T GetAngleJoint( track_p trk, coOrd pos, EPINX_T * ep0, EPINX_T * ep1 )
+{
+ struct extraData * xx = GetTrkExtraData(trk);
+ DIST_T l;
+ ANGLE_T a;
+ if ( ep0 && ep1 ) {
+ if (xx->flip) {
+ *ep0 = 1;
+ *ep1 = 0;
+ } else {
+ *ep0 = 0;
+ *ep1 = 1;
+ }
+ }
+ GetLandD( &l, NULL, pos, xx->pos, xx->angle, xx->R, xx->L, xx->negate, xx->Scurve );
+ if (small(l)) {
+ a = xx->angle;
+ } else {
+/* if (xx->Scurve && NormalizeAngle(FindAngle(xx->pos,pos)-xx->angle+90.0) > 180.0)*/
+ if (xx->Scurve && l < 0.0) {
+ GetJointPos( NULL, &a, -l, xx->R, xx->L, xx->pos, xx->angle+180.0, xx->negate );
+ a = NormalizeAngle( a-180.0 );
+ } else {
+ GetJointPos( NULL, &a, l, xx->R, xx->L, xx->pos, xx->angle, xx->negate );
+ }
+ }
+ return NormalizeAngle(a+180.0);
+}
+
+
+static void SplitJointA(
+ coOrd * posR,
+ EPINX_T ep,
+ struct extraData * xx,
+ struct extraData * xx1,
+ ANGLE_T * aR )
+{
+ struct extraData * xx0;
+ BOOL_T flip;
+ DIST_T l;
+
+ *xx1 = *xx;
+ if ( (ep==1) == (!xx->flip) ) {
+ xx0 = xx;
+ flip = FALSE;
+ } else {
+ xx0 = xx1;
+ xx1 = xx;
+ flip = TRUE;
+ }
+ GetLandD( &l, NULL, *posR, xx->pos, xx->angle, xx->R, xx->L, xx->negate, xx->Scurve );
+
+ if (!xx->Scurve) {
+ if (l < xx->l0 || l > xx->l1) {
+ NoticeMessage2( 0, "splitJoint: ! %0.3f <= %0.3f <= %0.3f", _("Ok"), NULL, xx->l0, l, xx->l1 );
+ if ( l < xx->l0 ) l = xx->l0;
+ else if ( l > xx->l1 ) l = xx->l1;
+ }
+ GetJointPos( posR, aR, l, xx->R, xx->L, xx->pos, xx->angle, xx->negate );
+ xx0->l1 = xx1->l0 = l;
+ } else if (small(l)){
+ xx0->Scurve = xx1->Scurve = 0;
+ xx0->l1 = xx0->l0;
+ xx0->flip = !xx0->flip;
+ xx1->angle = NormalizeAngle(xx1->angle+180.0);
+ xx0->l0 = xx1->l0 = 0;
+ *posR = xx->pos;
+ *aR = xx1->angle;
+ } else {
+ GetJointPos( posR, aR, l, xx->R, xx->L, xx->pos, xx->angle, xx->negate );
+ if (l > 0) {
+ xx0->Scurve = 0;
+ xx0->l1 = xx0->l0;
+ xx0->flip = !xx0->flip;
+ xx0->l0 = l;
+ xx1->l0 = l;
+ } else {
+ xx1->Scurve = 0;
+ xx1->l0 = -l;
+ xx1->angle = NormalizeAngle( xx1->angle+180.0 );
+ xx0->l1 = -l;
+ }
+ *aR = NormalizeAngle( *aR+180.0 );
+ }
+ if (flip)
+ *aR = NormalizeAngle( *aR + 180.0 );
+}
+
+
+static BOOL_T SplitJoint( track_p trk, coOrd pos, EPINX_T ep, track_p * leftover, EPINX_T *ep0, EPINX_T *ep1 )
+{
+ struct extraData *xx, *xx1;
+ track_p trk1;
+ ANGLE_T a;
+
+ xx = GetTrkExtraData(trk);
+ trk1 = NewTrack( 0, T_EASEMENT, 2, sizeof *xx );
+ xx1 = GetTrkExtraData(trk1);
+ *xx1 = *xx;
+ SetTrkEndPoint( trk1, ep, GetTrkEndPos(trk,ep), GetTrkEndAngle(trk,ep) );
+ *leftover = trk1;
+ *ep0 = 1-ep;
+ *ep1 = ep;
+ SplitJointA( &pos, ep, xx, xx1, &a );
+ SetTrkEndPoint( trk, ep, pos, a );
+ SetTrkEndPoint( trk1, 1-ep, pos, NormalizeAngle(a+180.0) );
+
+ ComputeBoundingBox( trk );
+ ComputeBoundingBox( trk1 );
+ return TRUE;
+}
+
+
+static BOOL_T TraverseJoint(
+ coOrd * posR,
+ ANGLE_T *angleR,
+ DIST_T *distR,
+ coOrd pos,
+ ANGLE_T angle,
+ DIST_T l0,
+ DIST_T l1,
+ DIST_T R,
+ DIST_T L,
+ BOOL_T negate,
+ BOOL_T flip,
+ BOOL_T Scurve )
+{
+
+ DIST_T l, lx, d, dx, ll0, ll1, d0, d1;
+ BOOL_T from_tangent, flip_angle;
+
+ GetLandD( &l, &d, *posR, pos, angle, R, L, negate, Scurve );
+
+LOG( log_traverseJoint, 2, ( "TJ: [%0.3f %0.3f] D%0.3f l0:%0.3f l1:%0.3f [%0.3f %0.3f] A%0.3f N%d F%d S%d = l:%0.3f ",
+ posR->x, posR->y, *distR, l0, l1, pos.x, pos.y, angle, negate, flip, Scurve, l ) )
+
+ if ( (!Scurve) ) {
+ if ( l < l0 ) l = l0;
+ else if ( l > l1 ) l = l1;
+ } else {
+ if ( l > l0 ) l = l0;
+ else if ( l < -l1 ) l = -l1;
+ }
+
+ lx = l;
+ from_tangent = !flip;
+ flip_angle = from_tangent;
+ if ( !Scurve ) {
+ ll0 = l0;
+ ll1 = l1;
+ } else if ( l > 0 ) {
+ ll1 = l0;
+ ll0 = 0;
+ } else {
+ ll0 = 0;
+ ll1 = l1;
+ lx = -l;
+ from_tangent = !from_tangent;
+ }
+ dx = JoinD( lx, R, L );
+ d0 = JoinD( ll0, R, L );
+ d1 = JoinD( ll1, R, L );
+ if ( from_tangent )
+ d = d1 - dx;
+ else
+ d = dx - d0;
+ if ( *distR < d ) {
+ if ( from_tangent ) {
+ d = dx + *distR;
+ } else {
+ d = dx - *distR;
+ }
+ lx = GetLfromD( d, R, L );
+ if ( l < 0 )
+ lx = - lx;
+ /* compute posR and angleR */
+ GetJointPos( posR, angleR, lx, R, L, pos, angle, negate );
+ if ( ! flip_angle )
+ *angleR = NormalizeAngle( *angleR + 180.0 );
+ *distR = 0;
+ goto doreturn;
+ }
+ *distR -= d;
+ if ( Scurve && (!from_tangent) ) {
+ /* skip over midpoint */
+ if ( l > 0 )
+ d = JoinD( l1, R, L );
+ else
+ d = JoinD( l0, R, L );
+ if ( *distR < d ) {
+ lx = GetLfromD( *distR, R, L );
+ if ( l > 0 )
+ lx = - lx;
+ GetJointPos( posR, angleR, lx, R, L, pos, angle, negate );
+ if ( ! flip_angle )
+ *angleR = NormalizeAngle( *angleR + 180.0 );
+ *distR = 0;
+ goto doreturn;
+ }
+ *distR -= d;
+ }
+doreturn:
+LOG( log_traverseJoint, 2, ( " [%0.3f %0.3f] A%0.3f D%0.3f\n", posR->x, posR->y, *angleR, *distR ) )
+ return TRUE;
+}
+
+
+static BOOL_T TraverseJointTrack(
+ traverseTrack_p trvTrk,
+ DIST_T * distR )
+{
+ track_p trk = trvTrk->trk;
+ struct extraData * xx = GetTrkExtraData(trk);
+ BOOL_T rc;
+ EPINX_T ep;
+ ANGLE_T angle;
+ BOOL_T flip;
+
+ angle = NormalizeAngle( xx->angle-trvTrk->angle );
+ flip = ( angle < 270 && angle > 90 );
+ rc = TraverseJoint( &trvTrk->pos, &trvTrk->angle, distR, xx->pos, xx->angle, xx->l0, xx->l1, xx->R, xx->L, xx->negate, flip, xx->Scurve );
+ if ( *distR > 0 ) {
+ ep = (flip?0:1);
+ if ( xx->flip )
+ ep = 1-ep;
+ if ( xx->Scurve )
+ ep = 1-ep;
+ trvTrk->pos = GetTrkEndPos( trk, ep );
+ trvTrk->angle = GetTrkEndAngle( trk, ep );
+ trvTrk->trk = GetTrkEndTrk( trk, ep );
+ }
+ return rc;
+}
+
+
+static BOOL_T EnumerateJoint( track_p trk )
+{
+ if (trk != NULL) {
+ ScaleLengthIncrement( GetTrkScale(trk), GetLengthJoint(trk) );
+ }
+ return TRUE;
+}
+
+static BOOL_T TrimJoint( track_p trk, EPINX_T ep, DIST_T maxX )
+{
+ DeleteTrack( trk, FALSE );
+ return TRUE;
+}
+
+
+static BOOL_T MergeJoint(
+ track_p trk0,
+ EPINX_T ep0,
+ track_p trk1,
+ EPINX_T ep1 )
+{
+ track_p trk2;
+ EPINX_T ep2=-1;
+ coOrd pos;
+ ANGLE_T a;
+ struct extraData *xx0 = GetTrkExtraData(trk0);
+ struct extraData *xx1 = GetTrkExtraData(trk1);
+
+ if ( ep0 == ep1 )
+ return FALSE;
+ if ( xx0->R != xx1->R ||
+ xx0->L != xx1->L ||
+ xx0->flip != xx1->flip ||
+ xx0->negate != xx1->negate ||
+ xx0->angle != xx1->angle ||
+ xx0->Scurve ||
+ xx1->Scurve ||
+ FindDistance( xx0->pos, xx1->pos ) > connectDistance )
+ return FALSE;
+
+ UndoStart( _("Merge Easements"), "MergeJoint( T%d[%d] T%d[%d] )", GetTrkIndex(trk0), ep0, GetTrkIndex(trk1), ep1 );
+ UndoModify( trk0 );
+ UndrawNewTrack( trk0 );
+ trk2 = GetTrkEndTrk( trk1, 1-ep1 );
+ if (trk2) {
+ ep2 = GetEndPtConnectedToMe( trk2, trk1 );
+ DisconnectTracks( trk1, 1-ep1, trk2, ep2 );
+ }
+
+ if (ep0 == 0) {
+ xx0->l0 = xx1->l0;
+ } else {
+ xx0->l1 = xx1->l1;
+ }
+
+ pos = GetTrkEndPos( trk1, 1-ep1 );
+ a = GetTrkEndAngle( trk1, 1-ep1 );
+ SetTrkEndPoint( trk0, ep0, pos, a );
+ ComputeBoundingBox( trk0 );
+
+ DeleteTrack( trk1, TRUE );
+ if (trk2) {
+ ConnectTracks( trk0, ep0, trk2, ep2 );
+ }
+ DrawNewTrack( trk0 );
+ return TRUE;
+}
+
+
+static BOOL_T GetParamsJoint( int inx, track_p trk, coOrd pos, trackParams_t * params )
+{
+ params->type = curveTypeStraight;
+ params->ep = PickUnconnectedEndPoint( pos, trk );
+ if (params->ep == -1)
+ return FALSE;
+ params->lineOrig = GetTrkEndPos(trk,params->ep);
+ params->lineEnd = params->lineOrig;
+ params->angle = GetTrkEndAngle(trk,params->ep);
+ params->len = 0.0;
+ params->arcR = 0.0;
+ return TRUE;
+}
+
+
+static BOOL_T MoveEndPtJoint( track_p *trk, EPINX_T *ep, coOrd pos, DIST_T d )
+{
+ return FALSE;
+}
+
+
+static BOOL_T QueryJoint( track_p trk, int query )
+{
+ struct extraData * xx = GetTrkExtraData(trk);
+ track_p trk1;
+
+ switch ( query ) {
+ case Q_CANNOT_BE_ON_END:
+ case Q_IGNORE_EASEMENT_ON_EXTEND:
+ case Q_ISTRACK:
+ return TRUE;
+ case Q_CAN_PARALLEL:
+ if ( xx->Scurve ) {
+ if ( FindDistance( xx->pos, GetTrkEndPos(trk,0) ) <= minLength ||
+ FindDistance( xx->pos, GetTrkEndPos(trk,1) ) <= minLength )
+ return FALSE;
+ UndoStart( _("Split Easement Curve"), "queryJoint T%d Scurve", GetTrkIndex(trk) );
+ SplitTrack( trk, xx->pos, 0, &trk1, FALSE );
+ }
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+
+static void FlipJoint(
+ track_p trk,
+ coOrd orig,
+ ANGLE_T angle )
+{
+ struct extraData * xx = GetTrkExtraData(trk);
+ FlipPoint( &xx->pos, orig, angle );
+ xx->angle = NormalizeAngle( 2*angle - xx->angle );
+ xx->negate = !xx->negate;
+ ComputeBoundingBox( trk );
+}
+
+
+static BOOL_T MakeParallelJoint(
+ track_p trk,
+ coOrd pos,
+ DIST_T sep,
+ track_p * newTrkR,
+ coOrd * p0R,
+ coOrd * p1R )
+{
+ struct extraData * xx = GetTrkExtraData(trk), *xx1;
+ ANGLE_T angle, A;
+ coOrd p0, p1, P, q1, r1;
+ DIST_T d, d0;
+ DIST_T R, L, l0, l1, len, dl;
+ int cnt, inx;
+
+ if ( xx->Scurve )
+ return FALSE;
+ GetLandD( NULL, &d, pos, xx->pos, xx->angle, xx->R, xx->L, xx->negate, FALSE );
+ angle = 90.0;
+ if ( (d < 0) == xx->negate )
+ sep = -sep;
+ if ( xx->negate )
+ angle = -90.0;
+ if ( xx->flip )
+ angle = -angle;
+ p0 = GetTrkEndPos(trk,0);
+ p1 = GetTrkEndPos(trk,1);
+ d0 = FindDistance( p0, p1 );
+ Translate( &p0, p0, GetTrkEndAngle(trk,0)+angle, sep );
+ Translate( &p1, p1, GetTrkEndAngle(trk,1)-angle, sep );
+ d = FindDistance( p0, p1 );
+ angle = R2D(asin(xx->L/2/xx->R));
+ A = xx->angle;
+ R = xx->R + sep*sin(D2R(angle));
+
+ dl = JoinD( xx->l1, xx->R, xx->L ) - JoinD( xx->l0, xx->R, xx->L );
+/*printf( "D = %0.3f %0.3f\n", d, dl );*/
+ d /= d0;
+ R = xx->R * d;
+ L = xx->L * d;
+ l0 = xx->l0 * d;
+ l1 = xx->l1 * d;
+/*printf( " R=%0.3f, L=%0.3f, l0=%0.3f, l1=%0.3f\n", R, L, l0, l1 );*/
+ Translate( &P, xx->pos, xx->angle+(xx->negate?90:-90), sep );
+ ComputeJoinPos( l1, R, L, NULL, NULL, &q1, NULL );
+ r1 = (xx->flip?p0:p1);
+ r1.x -= P.x;
+ r1.y -= P.y;
+ Rotate( &r1, zero, -A );
+ if ( xx->negate )
+ r1.x = -r1.x;
+ if ( r1.x > 0 && q1.x > 0 ) {
+/*printf( " %0.3f %0.3f, R=%0.3f ", q1.x, r1.x, R );*/
+ R *= q1.x/r1.x;
+/*printf( " %0.3f\n", R );*/
+ }
+
+ if ( newTrkR ) {
+ *newTrkR = NewTrack( 0, T_EASEMENT, 2, sizeof *xx );
+ xx1 = GetTrkExtraData( *newTrkR );
+ *xx1 = *xx;
+ xx1->angle = A;
+ xx1->R = R;
+ xx1->L = L;
+ xx1->l0 = l0;
+ xx1->l1 = l1;
+ xx1->pos = P;
+ SetTrkEndPoint( *newTrkR, 0, p0, GetTrkEndAngle(trk,0) );
+ SetTrkEndPoint( *newTrkR, 1, p1, GetTrkEndAngle(trk,1) );
+ ComputeBoundingBox( *newTrkR );
+ } else {
+ /* print segments about 0.20" long */
+ dl = fabs(l0-l1);
+ len = dl/(0.20*mainD.scale);
+ cnt = (int)ceil(len);
+ if (cnt == 0 || (mainD.options&DC_QUICK)) cnt = 1;
+ dl /= cnt;
+ DYNARR_SET( trkSeg_t, tempSegs_da, cnt );
+ for ( inx=0; inx<cnt; inx++ ) {
+ tempSegs(inx).color = wDrawColorBlack;
+ tempSegs(inx).width = 0;
+ tempSegs(inx).type = SEG_STRTRK;
+ if ( inx == 0 ) {
+ GetJointPos( &tempSegs(inx).u.l.pos[0], NULL, l0, R, L, P, A, xx->negate );
+ } else {
+ tempSegs(inx).u.l.pos[0] = tempSegs(inx-1).u.l.pos[1];
+ }
+ l0 += dl;
+ GetJointPos( &tempSegs(inx).u.l.pos[1], NULL, l0, R, L, P, A, xx->negate );
+ }
+ tempSegs_da.cnt = cnt;
+ }
+ if ( p0R ) *p0R = p0;
+ if ( p1R ) *p1R = p1;
+ return TRUE;
+}
+
+
+static trackCmd_t easementCmds = {
+ "JOINT",
+ DrawJoint,
+ DistanceJoint,
+ DescribeJoint,
+ DeleteJoint,
+ WriteJoint,
+ ReadJoint,
+ MoveJoint,
+ RotateJoint,
+ RescaleJoint,
+ NULL, /* audit */
+ GetAngleJoint,
+ SplitJoint,
+ TraverseJointTrack,
+ EnumerateJoint,
+ NULL, /* redraw */
+ TrimJoint,
+ MergeJoint,
+ ExtendStraightFromOrig,
+ GetLengthJoint,
+ GetParamsJoint,
+ MoveEndPtJoint,
+ QueryJoint,
+ NULL, /* ungroup */
+ FlipJoint,
+ NULL,
+ NULL,
+ NULL,
+ MakeParallelJoint };
+
+
+EXPORT void JointSegProc(
+ segProc_e cmd,
+ trkSeg_p segPtr,
+ segProcData_p data )
+{
+ DIST_T l;
+ ANGLE_T a;
+ BOOL_T flip;
+ struct extraData * xx, xxx[2];
+ coOrd p;
+ int inx;
+ EPINX_T ep0;
+
+ switch (cmd) {
+
+ case SEGPROC_TRAVERSE1:
+ GetLandD( &l, NULL, data->traverse1.pos, segPtr->u.j.pos, segPtr->u.j.angle, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.negate, segPtr->u.j.Scurve );
+ if (small(l)) {
+ a = segPtr->u.j.angle;
+ } else {
+ if (segPtr->u.j.Scurve && l < 0.0) {
+ GetJointPos( NULL, &a, -l, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.pos, segPtr->u.j.angle+180.0, segPtr->u.j.negate );
+ a = NormalizeAngle( a-180.0 );
+ } else {
+ GetJointPos( NULL, &a, l, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.pos, segPtr->u.j.angle, segPtr->u.j.negate );
+ }
+ }
+ a = NormalizeAngle( data->traverse1.angle+a );
+ data->traverse1.backwards = (a < 270 && a > 90 );
+ if ( !segPtr->u.j.Scurve ) {
+ if ( data->traverse1.backwards==0 )
+ data->traverse1.dist = JoinD( l, segPtr->u.j.R, segPtr->u.j.L ) - JoinD( segPtr->u.j.l0, segPtr->u.j.R, segPtr->u.j.L );
+ else
+ data->traverse1.dist = JoinD( segPtr->u.j.l1, segPtr->u.j.R, segPtr->u.j.L ) - JoinD( l, segPtr->u.j.R, segPtr->u.j.L );
+ } else {
+ data->traverse1.backwards = !data->traverse1.backwards;
+ if ( data->traverse1.backwards==0 )
+ data->traverse1.dist = JoinD( segPtr->u.j.l0, segPtr->u.j.R, segPtr->u.j.L ) - JoinD( l, segPtr->u.j.R, segPtr->u.j.L );
+ else
+ data->traverse1.dist = JoinD( segPtr->u.j.l1, segPtr->u.j.R, segPtr->u.j.L ) + JoinD( l, segPtr->u.j.R, segPtr->u.j.L );
+ }
+ if ( segPtr->u.j.flip )
+ data->traverse1.backwards = !data->traverse1.backwards;
+LOG( log_traverseJoint, 1, ( "TJ0: ?[%0.3f %0.3f] A=%0.3f l=%0.3f J[%0.3f %0.3f] A=%0.3f l0=%0.3f l1=%0.3f R=%0.3f L=%0.3f N:%d F:%d S:%d = a=%0.3f D=%0.3f B=%d\n",
+ data->traverse1.pos.x, data->traverse1.pos.y, data->traverse1.angle,
+ l,
+ segPtr->u.j.pos.x, segPtr->u.j.pos.y, segPtr->u.j.angle,
+ segPtr->u.j.l0, segPtr->u.j.l1, segPtr->u.j.R, segPtr->u.j.L,
+ segPtr->u.j.negate, segPtr->u.j.flip, segPtr->u.j.Scurve,
+ a, data->traverse1.dist, data->traverse1.backwards ) );
+ break;
+
+ case SEGPROC_TRAVERSE2:
+ flip = segPtr->u.j.flip;
+ if (data->traverse2.segDir!=0)
+ flip = !flip;
+ if (segPtr->u.j.Scurve)
+ flip = !flip;
+ data->traverse2.pos = GetSegEndPt( segPtr, data->traverse2.segDir, FALSE, NULL );
+ TraverseJoint( &data->traverse2.pos, &data->traverse2.angle, &data->traverse2.dist, segPtr->u.j.pos, segPtr->u.j.angle, segPtr->u.j.l0, segPtr->u.j.l1, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.negate, flip, segPtr->u.j.Scurve );
+ break;
+
+ case SEGPROC_DRAWROADBEDSIDE:
+ /* TODO: JointSegProc( SEGPROC_DRAWROADBEDSIDE, ... */
+ break;
+
+ case SEGPROC_DISTANCE:
+ data->distance.dd = JointDistance( &data->distance.pos1, segPtr->u.j.pos, segPtr->u.j.angle, segPtr->u.j.l0, segPtr->u.j.l1, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.negate, segPtr->u.j.Scurve );
+ break;
+
+ case SEGPROC_FLIP:
+ segPtr->u.j.flip = !segPtr->u.j.flip;
+ break;
+
+ case SEGPROC_NEWTRACK:
+ data->newTrack.trk = NewTrack( 0, T_EASEMENT, 2, sizeof *xx );
+ xx = GetTrkExtraData(data->newTrack.trk);
+ xx->pos = segPtr->u.j.pos;
+ xx->angle = segPtr->u.j.angle;
+ xx->l0 = segPtr->u.j.l0;
+ xx->l1 = segPtr->u.j.l1;
+ xx->R = segPtr->u.j.R;
+ xx->L = segPtr->u.j.L;
+ xx->negate = segPtr->u.j.negate;
+ xx->flip = segPtr->u.j.flip;
+ xx->Scurve = segPtr->u.j.Scurve;
+ ep0 = 0;
+ if ( xx->flip )
+ ep0 = 1-ep0;
+ if ( xx->Scurve )
+ ep0 = 1-ep0;
+ GetJointPos( &p, &a, xx->l0, xx->R, xx->L, xx->pos, xx->angle, xx->negate );
+ if ( !xx->Scurve )
+ a = NormalizeAngle(a+180.0);
+ SetTrkEndPoint( data->newTrack.trk, ep0, p, a );
+ a = xx->angle;
+ if ( xx->Scurve )
+ a = NormalizeAngle(a+180.0);
+ GetJointPos( &p, &a, xx->l1, xx->R, xx->L, xx->pos, a, xx->negate );
+ if ( xx->Scurve )
+ a = NormalizeAngle(a+180.0);
+ SetTrkEndPoint( data->newTrack.trk, 1-ep0, p, a );
+ ComputeBoundingBox( data->newTrack.trk );
+ data->newTrack.ep[0] = 0;
+ data->newTrack.ep[1] = 1;
+ break;
+
+ case SEGPROC_LENGTH:
+ if ( !segPtr->u.j.Scurve )
+ data->length.length = JoinD( segPtr->u.j.l1, segPtr->u.j.R, segPtr->u.j.L ) - JoinD( segPtr->u.j.l0, segPtr->u.j.R, segPtr->u.j.L );
+ else
+ data->length.length = JoinD( segPtr->u.j.l1, segPtr->u.j.R, segPtr->u.j.L ) + JoinD( segPtr->u.j.l0, segPtr->u.j.R, segPtr->u.j.L );
+ break;
+
+ case SEGPROC_SPLIT:
+ xxx[0].pos = segPtr->u.j.pos;
+ xxx[0].angle = segPtr->u.j.angle;
+ xxx[0].l0 = segPtr->u.j.l0;
+ xxx[0].l1 = segPtr->u.j.l1;
+ xxx[0].R = segPtr->u.j.R;
+ xxx[0].L = segPtr->u.j.L;
+ xxx[0].negate = segPtr->u.j.negate;
+ xxx[0].flip = segPtr->u.j.flip;
+ xxx[0].Scurve = segPtr->u.j.Scurve;
+ SplitJointA( &data->split.pos, 0, &xxx[0], &xxx[1], &a );
+ for ( inx=0; inx<2; inx++ ) {
+ xx = &xxx[(!segPtr->u.j.flip)?1-inx:inx];
+ data->split.newSeg[inx] = *segPtr;
+ data->split.newSeg[inx].u.j.pos = xx->pos;
+ data->split.newSeg[inx].u.j.angle = xx->angle;
+ data->split.newSeg[inx].u.j.l0 = xx->l0;
+ data->split.newSeg[inx].u.j.l1 = xx->l1;
+ data->split.newSeg[inx].u.j.R = xx->R;
+ data->split.newSeg[inx].u.j.L = xx->L;
+ data->split.newSeg[inx].u.j.negate = xx->negate;
+ data->split.newSeg[inx].u.j.flip = xx->flip;
+ data->split.newSeg[inx].u.j.Scurve = xx->Scurve;
+ if ( !xx->Scurve )
+ data->split.length[inx] = JoinD( xx->l1, xx->R, xx->L ) - JoinD( xx->l0, xx->R, xx->L );
+ else
+ data->split.length[inx] = JoinD( xx->l1, xx->R, xx->L ) + JoinD( xx->l0, xx->R, xx->L );
+ }
+ break;
+
+ case SEGPROC_GETANGLE:
+ GetLandD( &l, NULL, data->getAngle.pos, segPtr->u.j.pos, segPtr->u.j.angle, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.negate, segPtr->u.j.Scurve );
+ if (small(l)) {
+ a = segPtr->u.j.angle;
+ } else {
+ if (segPtr->u.j.Scurve && l < 0.0) {
+ GetJointPos( NULL, &a, -l, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.pos, segPtr->u.j.angle+180.0, segPtr->u.j.negate );
+ a = NormalizeAngle( a-180.0 );
+ } else {
+ GetJointPos( NULL, &a, l, segPtr->u.j.R, segPtr->u.j.L, segPtr->u.j.pos, segPtr->u.j.angle, segPtr->u.j.negate );
+ }
+ }
+ data->getAngle.angle = a;
+ break;
+ }
+}
+
+
+
+#ifndef TEST
+BOOL_T JoinTracks(
+ track_p trk0,
+ EPINX_T ep0,
+ coOrd pos0,
+ track_p trk1,
+ EPINX_T ep1,
+ coOrd pos1,
+ easementData_t * e )
+/*
+ * Join 2 tracks with joint described in (e).
+ * (pos0) and (pos1) are points that would be connected if there was no
+ * transition-curve.
+ * If there is then:
+ * (pos0) and (pos1) have been moved (x) apart.
+ * Adjust the endPoints by moving (pos0) and (pos1) by (e->d0) and (e->d1)
+ * along the track.
+ * Connect the tracks.
+ */
+{
+ track_p joint;
+
+LOG( log_ease, 1, ( "join T%d[%d] @[%0.3f %0.3f], T%d[%d] @[%0.3f %0.3f]\n",
+ GetTrkIndex(trk0), ep0, pos0.x, pos0.y, GetTrkIndex(trk1), ep1, pos1.x, pos1.y ) )
+
+ if ( GetTrkType(trk0) == T_EASEMENT ) {
+ DIST_T d;
+ ANGLE_T aa;
+ d = FindDistance( GetTrkEndPos(trk0,ep0), GetTrkEndPos(trk1,ep1) );
+ aa = NormalizeAngle( GetTrkEndAngle(trk0,ep0) - GetTrkEndAngle(trk1,ep1) + 180.0 + connectAngle/2.0 );
+ if ( d <= connectDistance && aa <= connectAngle ) {
+ ConnectTracks( trk0, ep0, trk1, ep1 );
+ }
+ return TRUE;
+ }
+
+ /* Move the endPoint for (trk0) */
+ if (!MoveEndPt( &trk0, &ep0, pos0, e->d0 ))
+ return FALSE;
+
+ /* Move the endPoint for (trk1) */
+ if (!MoveEndPt( &trk1, &ep1, pos1, e->d1 ))
+ return FALSE;
+
+LOG( log_ease, 1, ( " EASE R%0.3f..%0.3f L%0.3f..%0.3f\n",
+ e->r0, e->r1, e->d0, e->d1 ) )
+
+ /* Connect the tracks */
+ if (e->x == 0.0) {
+ /* No transition-curve */
+ ConnectTracks( trk0, ep0, trk1, ep1 );
+ } else {
+ /* Connect with transition-curve */
+ joint = NewJoint( GetTrkEndPos(trk0,ep0), GetTrkEndAngle(trk0,ep0),
+ GetTrkEndPos(trk1,ep1), GetTrkEndAngle(trk1,ep1),
+ GetTrkGauge(trk0), easeR, easeL, e );
+ CopyAttributes( trk0, joint );
+ ConnectTracks( trk1, ep1, joint, 1 );
+ ConnectTracks( trk0, ep0, joint, 0 );
+ DrawNewTrack( joint );
+ }
+ return TRUE;
+}
+
+
+EXPORT void UndoJoint(
+ track_p trk,
+ EPINX_T ep,
+ track_p trk1,
+ EPINX_T ep1 )
+{
+ struct extraData * xx;
+ DIST_T d;
+
+ if ( GetTrkType(trk1) != T_EASEMENT )
+ return;
+ xx = GetTrkExtraData(trk1);
+ if ( ep1 == 0 )
+ d = xx->L/2.0 - xx->l0;
+ else
+ d = xx->l1 - xx->L/2.0;
+ if ( d < 0.01 )
+ return;
+ UndrawNewTrack( trk );
+ MoveEndPt( &trk, &ep, GetTrkEndPos(trk,ep), -d );
+ DrawNewTrack( trk );
+}
+#endif
+
+/*****************************************************************************
+ *
+ * INITIALIZATION
+ *
+ */
+
+
+
+void InitTrkEase( void )
+{
+ T_EASEMENT = InitObject( &easementCmds );
+ log_ease = LogFindIndex( "ease" );
+ log_traverseJoint = LogFindIndex( "traverseJoint" );
+}
+
+
+/*****************************************************************************
+ *
+ * TEST
+ *
+ */
+
+#ifdef TEST
+
+
+void ErrorMessage( char * msg, ... )
+{
+ lprintf( "%s\n", msg );
+}
+
+void InfoMessage( char * msg, ... )
+{
+ lprintf( "%s\n", msg );
+}
+
+scaleInfo_p curScale;
+
+track_p NewTrack( TRKINX_T a, TRKTYP_T b, EPINX_T c, TRKTYP_T d )
+{
+ return NULL;
+}
+
+void DrawStraightTrack( drawCmd_p a, coOrd b, coOrd c, ANGLE_T d,
+ DIST_T trackGauge, wDrawColor color, int opts )
+{
+}
+
+void DrawNewTrack( track_p t )
+{
+}
+
+static DIST_T JoinDalt(
+ DIST_T x,
+ DIST_T R,
+ DIST_T L )
+/*
+ * Alternative distance computation, integrate over the curve.
+ */
+{
+#define DCNT (1000)
+ DIST_T d;
+ wIndex_t i;
+ coOrd p0, p1;
+ d = 0.0;
+ p0.x = p0.y = 0.0;
+ for ( i=1;i<=DCNT; i++) {
+ ComputeJoinPos( x*((DIST_T)i)/((DIST_T)DCNT), R, L, NULL, NULL, &p1, NULL );
+ d += FindDistance( p0, p1 );
+ p0 = p1;
+ }
+ return d;
+}
+
+
+test_plot( INT_T argc, char * argv[] )
+{
+ DIST_T l, X, L, rr, ra, d, d1, R;
+ coOrd p, pc, p1;
+ INT_T i, C;
+ if (argc != 4) {
+ lprintf("%s R L C\n", argv[0]);
+ Exit(1);
+ }
+ argv++;
+ R = atof( *argv++ );
+ L = atof( *argv++ );
+ C = atol( *argv++ );
+ X = L*L/(24*R);
+ lprintf("R=%0.3f X=%0.3f L=%0.3f\n", R, X, L );
+
+ for (i=0;i<=C;i++) {
+ l = L*((DIST_T)i)/((DIST_T)C);
+ d = JoinD( l, R, L );
+ d1 = JoinDalt( l, R, L );
+ ComputeJoinPos( l, R, L, &rr, &ra, &p, &pc );
+ lprintf("d: [%0.3f %0.3f] [%0.3f %03f] R=%0.3f A=%0.3f D=%0.3f D1=%0.3f X=%0.4f\n",
+ i, p.x, p.y, pc.x, pc.y, rr, ra, d, d1, pc.x-rr );
+ }
+}
+
+test_psplot( INT_T argc, char * argv[] )
+{
+ DIST_T l, L, rr, ra, d, d1, R, S, X;
+ coOrd p, q, pc, p1;
+ INT_T i, C;
+ if (argc != 5) {
+ lprintf("%s R L C S\n", argv[0]);
+ Exit(1);
+ }
+ argv++;
+ easeR = R = atof( *argv++ );
+ easeL = L = atof( *argv++ );
+ C = atol( *argv++ );
+ S = atof( *argv++ );
+ X = L*L/(24*R);
+
+lprintf("%%! kvjfv\nsave\n0 setlinewidth\n");
+lprintf("/Times-BoldItalic findfont 16 scalefont setfont\n");
+lprintf("36 36 moveto (R=%0.3f X=%0.3f L=%0.3f S=%0.3f) show\n", easeR, X, L, S );
+/*lprintf("24 768 translate -90 rotate\n");*/
+lprintf("gsave\n72 72 translate\n");
+lprintf("%0.3f %0.3f scale\n", 72.0/S, 72.0/S );
+lprintf("%0.3f %0.3f moveto %0.3f %0.3f lineto stroke\n", 0.0, 0.0, L, 0.0 );
+lprintf("%0.3f %0.3f %0.3f 270.0 90.0 arc stroke\n", L/2.0, easeR+X, easeR );
+lprintf("%0.3f %0.3f %0.3f 0.0 360.0 arc stroke\n", 0.0, 0.0, 0.25 );
+ q.x = q.y = 0.0;
+ for (i=0;i<=C;i++) {
+ l = L*((DIST_T)i)/((DIST_T)C);
+ ComputeJoinPos( l, R, L, &rr, &ra, &p, &pc );
+lprintf("%0.3f %0.3f moveto %0.3f %0.3f lineto stroke\n", q.x, q.y, p.x, p.y );
+ q = p;
+ }
+lprintf("%0.3f %0.3f %0.3f 0.0 360.0 arc stroke\n", p.x, p.y, 0.25 );
+lprintf("grestore\nrestore\nshowpage\n%%Trailer\n%%Pages: 1\n");
+}
+
+void Test_compute( INT_T argc, char * argv[] )
+{
+ DIST_T r0, r1, x, l0, l1, R, X, d;
+ coOrd q0, q1, qc0, qc1;
+ easementData_t e;
+ if (argc != 5) {
+ lprintf("compute R0 R1 R L\n");
+ Exit(1);
+ }
+ /*debugEase = 5;*/
+ argv++;
+ r0 = atof( *argv++);
+ r1 = atof( *argv++);
+ easementVal = 1.0;
+ easeR = atof( *argv++);
+ easeL = atof( *argv++);
+ ComputeJoint( r0, r1, &e );
+ ComputeJoinPos( e.l0, easeR, easeL, NULL, NULL, &q0, &qc0 );
+ ComputeJoinPos( e.l1, easeR, easeL, NULL, NULL, &q1, &qc1 );
+ if (e.Scurve) {
+ q1.x = - q1.x; q1.y = - q1.y;
+ qc1.x = - qc1.x; qc1.y = - qc1.y;
+ }
+ d = FindDistance( q0, q1 );
+ lprintf("ENDPT [%0.3f %0.3f] [%0.3f %0.3f]\n", q0.x, q0.y, q1.x, q1.y );
+ lprintf("CENTER [%0.3f %0.3f] [%0.3f %0.3f]\n", qc0.x, qc0.y, qc1.x, qc1.y );
+ lprintf("ComputeJoint( %0.3f %0.3f) { %0.3f %0.3f %0.3f } D0=%0.5f D1=%0.5f, D=%0.3f\n",
+ r0, r1, easeR, easeL, e.x, e.d0, e.d1, d );
+}
+
+void Test_findL( INT_T argc, char * argv[] )
+{
+ DIST_T l, r, R, L;
+ if (argc != 5) {
+ lprintf("findL r R L\n");
+ Exit(1);
+ }
+ /*debugEase = 5;*/
+ argv++;
+ r = atof( *argv++ );
+ R = atof( *argv++ );
+ L = atof( *argv++ );
+ l = FindL( r, R, L );
+ lprintf("FindL( %0.3f %0.3f %0.3f ) = %0.3f\n", r, R, L, l );
+}
+
+
+main( INT_T argc, char * argv[] )
+{
+INT_T flagX = 0;
+INT_T flagV = 0;
+ if (argc<1) {
+ lprintf("plot|compute\n");
+ Exit(1);
+ }
+ argv++; argc--;
+ while (argv[0][0] == '-') {
+ switch (argv[0][1]) {
+ case 'x':
+ flagX++;
+ argc--;argv++;
+ break;
+ case 'v':
+ flagV++;
+ argc--;argv++;
+ break;
+ default:
+ lprintf("Huh: %s\n", *argv );
+ argc--;argv++;
+ break;
+ }
+ }
+ if (strcmp(argv[0],"plot")==0) {
+ Test_plot( argc, argv );
+ } else if (strcmp(argv[0],"psplot")==0) {
+ Test_psplot( argc, argv );
+ } else if (strcmp(argv[0],"compute")==0) {
+ Test_compute( argc, argv );
+ } else if (strcmp(argv[0],"findL")==0) {
+ Test_findL( argc, argv );
+ } else {
+ lprintf("unknown cmd %s\n", argv[0] );
+ }
+}
+#endif