/* \file ctodesgn.c * T_TURNOUT Designer * */ /* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "ccurve.h" #include "compound.h" #include "cstraigh.h" #include "custom.h" #include "fileio.h" #include "param.h" #include "track.h" #include "trkendpt.h" #include "ccornu.h" #include "cbezier.h" #include "misc.h" #include "common-ui.h" static int log_cornuturnoutdesigner; dynArr_t tempSegs_da; char tempCustom[4096]; #define TURNOUTDESIGNER "CTURNOUT DESIGNER" dynArr_t tempSegs_da; // Minimum Track Segment length #define MIN_TRACK_LENGTH (0.20) /***************************************** * * TURNOUT DESIGNER * */ #define NTO_REGULAR (1) #define NTO_CURVED (2) #define NTO_WYE (3) #define NTO_3WAY (4) #define NTO_CROSSING (5) #define NTO_S_SLIP (6) #define NTO_D_SLIP (7) #define NTO_R_CROSSOVER (8) #define NTO_L_CROSSOVER (9) #define NTO_D_CROSSOVER (10) #define NTO_STR_SECTION (11) #define NTO_CRV_SECTION (12) #define NTO_BUMPER (13) #define NTO_TURNTABLE (14) #define NTO_CORNU (15) #define NTO_CORNUWYE (16) #define NTO_CORNU3WAY (17) #define FLOAT (1) typedef struct { struct { wWinPix_t x, y; } pos; int index; char * winLabel; char * printLabel; enum { Dim_e, Frog_e, Angle_e, Rad_e } mode; } toDesignFloat_t; typedef struct { PATHPTR_T paths; char * segOrder; } toDesignSchema_t; typedef struct { int type; char * label; int strCnt; int lineCnt; wLines_t * lines; int floatCnt; toDesignFloat_t * floats; toDesignSchema_t * paths; int angleModeCnt; wLine_p lineC; wBool_t slipmode; } toDesignDesc_t; #ifndef MKTURNOUT static wWin_p newTurnW; #endif static FLOAT_T newTurnRad0; static FLOAT_T newTurnAngle0; static FLOAT_T newTurnLen0; static FLOAT_T newTurnOff0; static FLOAT_T newTurnRad1; static FLOAT_T newTurnAngle1; static FLOAT_T newTurnLen1; static FLOAT_T newTurnOff1; static FLOAT_T newTurnRad2; static FLOAT_T newTurnAngle2; static FLOAT_T newTurnLen2; static FLOAT_T newTurnOff2; static FLOAT_T newTurnRad3; static FLOAT_T newTurnAngle3; static FLOAT_T newTurnOff3; static FLOAT_T newTurnLen3; static FLOAT_T newTurnToeL; static FLOAT_T newTurnToeR; static long newTurnAngleMode = 1; static long newTurnSlipMode = 0; static char newTurnRightDesc[STR_SIZE], newTurnLeftDesc[STR_SIZE]; static char newTurnRightPartno[STR_SIZE], newTurnLeftPartno[STR_SIZE]; static char newTurnManufacturer[STR_SIZE]; static char *newTurnAngleModeLabels[] = { N_("Frog #"), N_("Degrees"), NULL }; static char *newTurnSlipModeLabels[] = { N_("Dual Path"), N_("Quad Path"), NULL }; static DIST_T newTurnRoadbedWidth; static LWIDTH_T newTurnRoadbedLineWidth = 0; static wDrawColor newTurnRoadbedColor; static DIST_T newTurnTrackGauge; static char * newTurnScaleName; static paramFloatRange_t r0d001_10000 = { 0.001, 10000, 80 }; static paramFloatRange_t r0d300_10000 = { 0.300, 10000, 80 }; //static paramFloatRange_t r0_10000 = { 0, 10000, 80 }; static paramFloatRange_t r_10000_10000 = { -1000, 10000, 80 }; static paramFloatRange_t r0d001_90 = { 0.001, 90, 80 }; static paramFloatRange_t r0_100 = { 0, 100, 80 }; static paramIntegerRange_t i0_100 = { 0, 100, 40 }; static void NewTurnOk( void * context ); #ifndef MKTURNOUT static paramFloatRange_t r_90_90 = { -90, 90, 80 }; static void ShowTurnoutDesigner( void * context ); #endif static coOrd points[20]; #ifndef MKTURNOUT static coOrd end_points[20]; static coOrd end_centers[20]; static double end_arcs[20]; static double end_angles[20]; #endif static DIST_T radii[10]; static double angles[10]; #define POSX(X) ((wWinPix_t)((X)*newTurnout_d.dpi)) #define POSY(Y) ((wWinPix_t)((Y)*newTurnout_d.dpi)) static paramData_t turnDesignPLs[] = { #define I_TOLENGTH (0) #define I_TO_FIRST_FLOAT (0) { PD_FLOAT, &newTurnLen0, "len0", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d001_10000, N_("Length") }, { PD_FLOAT, &newTurnLen1, "len1", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d001_10000, N_("Length") }, { PD_FLOAT, &newTurnLen2, "len2", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d001_10000, N_("Length") }, { PD_FLOAT, &newTurnLen3, "len3", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d001_10000, N_("Length") }, #define I_TOOFFSET (4) { PD_FLOAT, &newTurnOff0, "off0", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d001_10000, N_("Offset") }, { PD_FLOAT, &newTurnOff1, "off1", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d001_10000, N_("Offset") }, { PD_FLOAT, &newTurnOff2, "off2", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d001_10000, N_("Offset") }, { PD_FLOAT, &newTurnOff3, "off3", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d001_10000, N_("Offset") }, #define I_TORAD (8) { PD_FLOAT, &newTurnRad0, "rad0", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Radius") }, { PD_FLOAT, &newTurnRad1, "rad1", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Radius") }, { PD_FLOAT, &newTurnRad2, "rad2", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Radius") }, { PD_FLOAT, &newTurnRad3, "rad3", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r_10000_10000, N_("Radius") }, #define I_TOTOELENGTH (12) { PD_FLOAT, &newTurnToeL, "toeL", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d300_10000, N_("Length") }, { PD_FLOAT, &newTurnToeR, "toeR", PDO_DIM|PDO_DLGIGNORELABELWIDTH, &r0d300_10000, N_("Length") }, #define I_TOANGLE (14) { PD_FLOAT, &newTurnAngle0, "angle0", PDO_DLGIGNORELABELWIDTH, &r0d001_90, N_("Angle") }, { PD_FLOAT, &newTurnAngle1, "angle1", PDO_DLGIGNORELABELWIDTH, &r0d001_90, N_("Angle") }, { PD_FLOAT, &newTurnAngle2, "angle2", PDO_DLGIGNORELABELWIDTH, &r0d001_90, N_("Angle") }, #define I_TO_LAST_FLOAT (17) { PD_FLOAT, &newTurnAngle3, "angle3", PDO_DLGIGNORELABELWIDTH, &r0d001_90, N_("Angle") }, #define I_TOMANUF (18) { PD_STRING, &newTurnManufacturer, "manuf", PDO_NOTBLANK, NULL, N_("Manufacturer"), 0, 0, sizeof(newTurnManufacturer)}, #define I_TOLDESC (19) { PD_STRING, &newTurnLeftDesc, "desc1", PDO_NOTBLANK, NULL, N_("Left Description"), 0, 0, sizeof(newTurnLeftDesc)}, { PD_STRING, &newTurnLeftPartno, "partno1", PDO_DLGHORZ | PDO_NOTBLANK, NULL, N_(" #"), 0, 0, sizeof(newTurnLeftPartno)}, #define I_TORDESC (21) { PD_STRING, &newTurnRightDesc, "desc2", PDO_NOTBLANK, NULL, N_("Right Description"),0, 0, sizeof(newTurnRightDesc)}, { PD_STRING, &newTurnRightPartno, "partno2", PDO_DLGHORZ | PDO_NOTBLANK, NULL, N_(" #"),0, 0, sizeof(newTurnRightPartno)}, { PD_FLOAT, &newTurnRoadbedWidth, "roadbedWidth", PDO_DIM, &r0_100, N_("Roadbed Width") }, { PD_LONG, &newTurnRoadbedLineWidth, "roadbedLineWidth", PDO_DLGHORZ, &i0_100, N_("Line Width") }, { PD_COLORLIST, &newTurnRoadbedColor, "color", PDO_DLGHORZ|PDO_DLGBOXEND, NULL, N_("Color") }, { PD_BUTTON, NewTurnOk, "done", PDO_DLGCMDBUTTON, NULL, N_("Ok") }, { PD_BUTTON, wPrintSetup, "printsetup", 0, NULL, N_("Print Setup") }, #define I_TOANGMODE (28) { PD_RADIO, &newTurnAngleMode, "angleMode", 0, newTurnAngleModeLabels }, #define I_TOSLIPMODE (29) { PD_RADIO, &newTurnSlipMode, "slipMode", 0, newTurnSlipModeLabels } }; #ifndef MKTURNOUT static paramGroup_t turnDesignPG = { "turnoutNew", 0, turnDesignPLs, COUNT( turnDesignPLs ) }; static turnoutInfo_t * customTurnout1, * customTurnout2; static BOOL_T includeNontrackSegments; #else int doCustomInfoLine = 1; int doRoadBed = 0; char specialLine[256]; #endif static toDesignDesc_t * curDesign; /* * Regular Turnouts */ static wLines_t RegLines[] = { #include "toreg.lin" }; static toDesignFloat_t RegFloats[] = { { { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Diverging Length"), Dim_e }, { { 400, 28 }, I_TOANGLE+0, N_("Angle"), N_("Diverging Angle"), Frog_e }, { { 325, 68 }, I_TOOFFSET+0, N_("Offset"), N_("Diverging Offset"), Dim_e }, { { 100, 120 }, I_TOLENGTH+1, N_("Length"), N_("Overall Length"), Dim_e }, }; static signed char RegPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 3, 4, 0, 0, 0 }; static toDesignSchema_t RegSchema = { RegPaths, "030" "310" "341" "420" }; static toDesignDesc_t RegDesc = { NTO_REGULAR, N_("Regular Turnout"), 2, COUNT( RegLines ), RegLines, COUNT( RegFloats ), RegFloats, &RegSchema, 1 }; static wLines_t CrvLines[] = { #include "tocrv.lin" }; static toDesignFloat_t CrvFloats[] = { { { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Inner Length"), Dim_e }, { { 375, 12 }, I_TOANGLE+0, N_("Angle"), N_("Inner Angle"), Frog_e }, { { 375, 34 }, I_TOOFFSET+0, N_("Offset"), N_("Inner Offset"), Dim_e }, { { 400, 62 }, I_TOANGLE+1, N_("Angle"), N_("Outer Angle"), Frog_e }, { { 400, 84 }, I_TOOFFSET+1, N_("Offset"), N_("Outer Offset"), Dim_e }, { { 175, 120 }, I_TOLENGTH+1, N_("Length"), N_("Outer Length"), Dim_e } }; static signed char Crv1Paths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 4, 5, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 2, 3, 0, 0, 0 }; static toDesignSchema_t Crv1Schema = { Crv1Paths, "030" "341" "410" "362" "620" }; static signed char Crv2Paths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 4, 5, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 6, 2, 3, 0, 0, 0 }; static toDesignSchema_t Crv2Schema = { Crv2Paths, "050" "341" "410" "562" "620" "530" }; static signed char Crv3Paths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 6, 4, 5, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 2, 3, 0, 0, 0 }; static toDesignSchema_t Crv3Schema = { Crv3Paths, "030" "341" "410" "562" "620" "350" }; static toDesignDesc_t CrvDesc = { NTO_CURVED, N_("Curved Turnout"), 2, COUNT( CrvLines ), CrvLines, COUNT( CrvFloats ), CrvFloats, &Crv1Schema, 1 }; #ifndef MKTURNOUT static wLines_t CornuLines[] = { #include "tocornu.lin" }; static toDesignFloat_t CornuFloats[] = { { { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Inner Length"), Dim_e }, { { 375, 0 }, I_TOANGLE+0, N_("Angle"), N_("Inner Angle"), Frog_e }, { { 375, 22 }, I_TOOFFSET+0, N_("Offset"), N_("Inner Offset"), Dim_e }, { { 375, 44 }, I_TORAD+0, N_("Radius"), N_("Inner Radius"), Dim_e }, { { 400, 62 }, I_TOANGLE+1, N_("Angle"), N_("Outer Angle"), Frog_e }, { { 400, 84 }, I_TOOFFSET+1, N_("Offset"), N_("Outer Offset"), Dim_e }, { { 400, 106 }, I_TORAD+1, N_("Radius"), N_("Outer Radius"), Dim_e }, { { 175, 120 }, I_TOLENGTH+1, N_("Length"), N_("Outer Length"), Dim_e }, { { 50, 90 }, I_TORAD+2, N_("Radius"), N_("Toe Radius"), Dim_e }, { { 50, 40 }, I_TOTOELENGTH+0, N_("Length"), N_("Toe Length"), Dim_e } }; static signed char CornuPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 4, 0, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 2, 0, 0, 0, 0 }; static toDesignSchema_t CornuSchema = { CornuPaths, "033" "343" "413" }; static toDesignDesc_t CornuDesc = { NTO_CORNU, N_("Cornu Curved Turnout"), 2, COUNT( CornuLines ), CornuLines, COUNT( CornuFloats ), CornuFloats, &CornuSchema, 1 }; #endif static wLines_t WyeLines[] = { #include "towye.lin" }; static toDesignFloat_t WyeFloats[] = { { { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Left Length"), Dim_e }, { { 400, 28 }, I_TOANGLE+0, N_("Angle"), N_("Left Angle"), Frog_e }, { { 325, 68 }, I_TOOFFSET+0, N_("Offset"), N_("Left Offset"), Dim_e }, { { 325, 115 }, I_TOOFFSET+1, N_("Offset"), N_("Right Offset"), Dim_e }, { { 400, 153 }, I_TOANGLE+1, N_("Angle"), N_("Right Angle"), Frog_e }, { { 175, 170 }, I_TOLENGTH+1, N_("Length"), N_("Right Length"), Dim_e }, }; static signed char Wye1Paths[] = { 'L', 'e', 'f', 't', 0, 1, 2, 3, 0, 0, 'R', 'i', 'g', 'h', 't', 0, 1, 4, 5, 0, 0, 0 }; static toDesignSchema_t Wye1Schema = { Wye1Paths, "030" "341" "410" "362" "620" }; static signed char Wye2Paths[] = { 'L', 'e', 'f', 't', 0, 1, 2, 3, 4, 0, 0, 'R', 'i', 'g', 'h', 't', 0, 1, 5, 6, 0, 0, 0 }; static toDesignSchema_t Wye2Schema = { Wye2Paths, "050" "530" "341" "410" "562" "620" }; static signed char Wye3Paths[] = { 'L', 'e', 'f', 't', 0, 1, 2, 3, 0, 0, 'R', 'i', 'g', 'h', 't', 0, 1, 4, 5, 6, 0, 0, 0 }; static toDesignSchema_t Wye3Schema = { Wye3Paths, "030" "341" "410" "350" "562" "620" }; static toDesignDesc_t WyeDesc = { NTO_WYE, N_("Wye Turnout"), 1, COUNT( WyeLines ), WyeLines, COUNT( WyeFloats ), WyeFloats, NULL, 1 }; #ifndef MKTURNOUT static wLines_t CornuWyeLines[] = { #include "tocornuwye.lin" }; static toDesignFloat_t CornuWyeFloats[] = { { { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Left Length"), Dim_e }, { { 400, 28 }, I_TOANGLE+0, N_("Angle"), N_("Left Angle"), Frog_e }, { { 400, 48 }, I_TOOFFSET+0, N_("Offset"), N_("Left Offset"), Dim_e }, { { 400, 68 }, I_TORAD+0, N_("Radius"), N_("Left Radius"), Dim_e }, { { 400, 108 }, I_TORAD+1, N_("Radius"), N_("Right Radius"), Dim_e }, { { 400, 128 }, I_TOOFFSET+1, N_("Offset"), N_("Right Offset"), Dim_e }, { { 400, 148 }, I_TOANGLE+1, N_("Angle"), N_("Right Angle"), Frog_e }, { { 175, 170 }, I_TOLENGTH+1, N_("Length"), N_("Right Length"), Dim_e }, { { 80, 48 }, I_TOTOELENGTH+0, N_("Length"), N_("Toe Length"), Dim_e }, { { 80, 28 }, I_TORAD+2, N_("Radius"), N_("Toe Radius"), Dim_e }, }; static signed char CornuWyePaths[] = { 'L', 'e', 'f', 't', 0, 1, 2, 3, 0, 0, 'R', 'i', 'g', 'h', 't', 0, 1, 4, 5, 0, 0, 0 }; /* Not Used */ static toDesignSchema_t CornuWyeSchema = { CornuWyePaths, "030" "341" "410" "362" "620" }; /* Not Used */ static toDesignDesc_t CornuWyeDesc = { NTO_CORNUWYE, N_("Cornu Wye Turnout"), 1, COUNT( CornuWyeLines ), CornuWyeLines, COUNT( CornuWyeFloats ), CornuWyeFloats, NULL, 1 }; #endif static wLines_t ThreewayLines[] = { #include "to3way.lin" }; static toDesignFloat_t ThreewayFloats[] = { { { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Left Length"), Dim_e }, { { 400, 28 }, I_TOANGLE+0, N_("Angle"), N_("Left Angle"), Frog_e }, { { 325, 68 }, I_TOOFFSET+0, N_("Offset"), N_("Left Offset"), Dim_e }, { { 100, 90 }, I_TOLENGTH+2, N_("Length"), N_("Length"), Dim_e }, { { 325, 115 }, I_TOOFFSET+1, N_("Offset"), N_("Right Offset"), Dim_e }, { { 400, 153 }, I_TOANGLE+1, N_("Angle"), N_("Right Angle"), Frog_e }, { { 175, 170 }, I_TOLENGTH+1, N_("Length"), N_("Right Length"), Dim_e }, }; static signed char Tri1Paths[] = { 'L', 'e', 'f', 't', 0, 1, 2, 3, 0, 0, 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 6, 0, 0, 'R', 'i', 'g', 'h', 't', 0, 1, 4, 5, 0, 0, 0 }; static toDesignSchema_t Tri1Schema = { Tri1Paths, "030" "341" "410" "362" "620" "370" }; static signed char Tri2Paths[] = { 'L', 'e', 'f', 't', 0, 1, 2, 3, 4, 0, 0, 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 7, 0, 0, 'R', 'i', 'g', 'h', 't', 0, 1, 5, 6, 0, 0, 0 }; static toDesignSchema_t Tri2Schema = { Tri2Paths, "050" "530" "341" "410" "562" "620" "370" }; static signed char Tri3Paths[] = { 'L', 'e', 'f', 't', 0, 1, 2, 3, 0, 0, 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 4, 7, 0, 0, 'R', 'i', 'g', 'h', 't', 0, 1, 4, 5, 6, 0, 0, 0 }; static toDesignSchema_t Tri3Schema = { Tri3Paths, "030" "341" "410" "350" "562" "620" "570" }; static toDesignDesc_t ThreewayDesc = { NTO_3WAY, N_("3-way Turnout"), 1, COUNT( ThreewayLines ), ThreewayLines, COUNT( ThreewayFloats ), ThreewayFloats, NULL, 1 }; #ifndef MKTURNOUT static wLines_t CornuThreewayLines[] = { #include "tocornu3way.lin" }; static toDesignFloat_t CornuThreewayFloats[] = { { { 175, 10 }, I_TOLENGTH+0, N_("Length"), N_("Left Length"), Dim_e }, { { 380, 10 }, I_TOANGLE+0, N_("Angle"), N_("Left Angle"), Frog_e }, { { 380, 50 }, I_TOOFFSET+0, N_("Offset"), N_("Left Offset"), Dim_e }, { { 380, 30 }, I_TORAD+0, N_("Radius"), N_("Left Radius"), Dim_e }, { { 130, 90 }, I_TOLENGTH+3, N_("Length"), N_("Center Length"), Dim_e }, { { 400, 70 }, I_TOANGLE+3, N_("Angle"), N_("Center Angle"), Dim_e }, { { 400, 90}, I_TOOFFSET+3, N_("Offset"), N_("Center Offset"), Dim_e }, { { 400, 110 }, I_TORAD+3, N_("Radius"), N_("Center Radius"), Dim_e }, { { 420, 150 }, I_TORAD+1, N_("Radius"), N_("Right Radius"), Dim_e }, { { 420, 130 }, I_TOOFFSET+1, N_("Offset"), N_("Right Offset"), Dim_e }, { { 420, 170 }, I_TOANGLE+1, N_("Angle"), N_("Right Angle"), Frog_e }, { { 175, 170 }, I_TOLENGTH+1, N_("Length"), N_("Right Length"), Dim_e }, { { 45, 50 }, I_TOTOELENGTH+0, N_("Length"), N_("Toe Length Left"), Dim_e }, { { 55, 140 }, I_TOTOELENGTH+1, N_("Length"), N_("Toe Length Right"), Dim_e }, { { 40, 105 }, I_TORAD+2, N_("Radius"), N_("Toe Radius"), Dim_e }, }; static signed char CornuTriPaths[] = { 'L', 'e', 'f', 't', 0, 1, 2, 3, 0, 0, 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 6, 0, 0, 'R', 'i', 'g', 'h', 't', 0, 1, 4, 5, 0, 0, 0 }; static toDesignSchema_t CornuTriSchema = { CornuTriPaths, "030" "341" "410" "362" "620" "370" }; static toDesignDesc_t CornuThreewayDesc = { NTO_CORNU3WAY, N_("Cornu 3-way Turnout"), 1, COUNT( CornuThreewayLines ), CornuThreewayLines, COUNT( CornuThreewayFloats ), CornuThreewayFloats, NULL, 1 }; #endif static wLines_t CrossingLines[] = { #include "toxing.lin" }; static toDesignFloat_t CrossingFloats[] = { { { 329, 30 }, I_TOLENGTH+0, N_("Length"), N_("Length"), Dim_e }, { { 370, 90 }, I_TOANGLE+0, N_("Angle"), N_("Angle"), Frog_e }, { { 329, 150 }, I_TOLENGTH+1, N_("Length"), N_("Length"), Dim_e } }; static signed char CrossingPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 0, 2, 0, 0, 0 }; static toDesignSchema_t CrossingSchema = { CrossingPaths, "010" "230" }; static toDesignDesc_t CrossingDesc = { NTO_CROSSING, N_("Crossing"), 1, COUNT( CrossingLines ), CrossingLines, COUNT( CrossingFloats ), CrossingFloats, &CrossingSchema, 1 }; static wLines_t SingleSlipLines[] = { #include "tosslip.lin" }; static toDesignFloat_t SingleSlipFloats[] = { { { 329, 30 }, I_TOLENGTH+0, N_("Length"), N_("Length"), Dim_e }, { { 370, 90 }, I_TOANGLE+0, N_("Angle"), N_("Angle"), Frog_e }, { { 329, 155 }, I_TOLENGTH+1, N_("Length"), N_("Length"), Dim_e } }; static signed char SingleSlipPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 0, 3, 4, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 5, 4, 0, 0, 0 }; static toDesignSchema_t SingleSlipSchema = { SingleSlipPaths, "040" "410" "250" "530" "451" }; static toDesignDesc_t SingleSlipDesc = { NTO_S_SLIP, N_("Single Slipswitch"), 1, COUNT( SingleSlipLines ), SingleSlipLines, COUNT( SingleSlipFloats ), SingleSlipFloats, &SingleSlipSchema, 1 }; static wLines_t DoubleSlipLines[] = { #include "todslip.lin" }; static toDesignFloat_t DoubleSlipFloats[] = { { { 329, 30 }, I_TOLENGTH+0, N_("Length"), N_("Length"), Dim_e }, { { 370, 90 }, I_TOANGLE+0, N_("Angle"), N_("Angle"), Frog_e }, { { 329, 155 }, I_TOLENGTH+1, N_("Length"), N_("Length"), Dim_e } }; static signed char DoubleSlipPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 3, 0, 4, 5, 6, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 7, 6, 0, 4, 8, 3, 0, 0, 0 }; static signed char DoubleSlipPaths2[] = { 'C', 'r', 'o', 's', 's', '1', 0, 1, 2, 3, 0, 0, 'C', 'r', 'o', 's', 's', '2', 0, 4, 5, 6, 0, 0, 'S', 'l', 'i', 'p', '1', 0, 1, 7, 6, 0, 0, 'S', 'l', 'i', 'p', '2', 0, 4, 8, 3, 0, 0, 0 }; static toDesignSchema_t DoubleSlipSchema = { DoubleSlipPaths, "040" "460" "610" "270" "750" "530" "451" "762" }; static toDesignSchema_t DoubleSlipSchema2 = { DoubleSlipPaths2, "040" "460" "610" "270" "750" "530" "451" "762" }; static toDesignDesc_t DoubleSlipDesc = { NTO_D_SLIP, N_("Double Slipswitch"), 1, COUNT( DoubleSlipLines ), DoubleSlipLines, COUNT( DoubleSlipFloats ), DoubleSlipFloats, &DoubleSlipSchema, 1 }; #ifndef MKTURNOUT static wLines_t RightCrossoverLines[] = { #include "torcross.lin" }; static toDesignFloat_t RightCrossoverFloats[] = { { { 200, 10 }, I_TOLENGTH+0, N_("Length"), N_("Length"), Dim_e }, { { 90, 85 }, I_TOOFFSET+0, N_("Separation"), N_("Separation"), Dim_e } }; static signed char RightCrossoverPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 0, 3, 4, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 3, 5, 6, 7, 2, 0, 0, 0 }; static toDesignSchema_t RightCrossoverSchema = { RightCrossoverPaths, "060" "610" "280" "830" "892" "970" "761" }; static toDesignDesc_t RightCrossoverDesc = { NTO_R_CROSSOVER, N_("Right Crossover"), 1, COUNT( RightCrossoverLines ), RightCrossoverLines, COUNT( RightCrossoverFloats ), RightCrossoverFloats, &RightCrossoverSchema, 0 }; #endif #ifndef MKTURNOUT static wLines_t LeftCrossoverLines[] = { #include "tolcross.lin" }; static toDesignFloat_t LeftCrossoverFloats[] = { { { 200, 10 }, I_TOLENGTH+0, N_("Length"), N_("Length"), Dim_e }, { { 90, 85 }, I_TOOFFSET+0, N_("Separation"), N_("Separation"), Dim_e } }; static signed char LeftCrossoverPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 0, 3, 4, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 5, 6, 7, 4, 0, 0, 0 }; static toDesignSchema_t LeftCrossoverSchema = { LeftCrossoverPaths, "040" "410" "2A0" "A30" "451" "5B0" "BA2" }; static toDesignDesc_t LeftCrossoverDesc = { NTO_L_CROSSOVER, N_("Left Crossover"), 1, COUNT( LeftCrossoverLines ), LeftCrossoverLines, COUNT( LeftCrossoverFloats ), LeftCrossoverFloats, &LeftCrossoverSchema, 0 }; #endif static wLines_t DoubleCrossoverLines[] = { #include "todcross.lin" }; static toDesignFloat_t DoubleCrossoverFloats[] = { { { 200, 10 }, I_TOLENGTH+0, N_("Length"), N_("Length"), Dim_e }, { { 90, 85 }, I_TOOFFSET+0, N_("Separation"), N_("Separation"), Dim_e } }; static signed char DoubleCrossoverPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 2, 3, 0, 4, 5, 6, 0, 0, 'R', 'e', 'v', 'e', 'r', 's', 'e', 0, 1, 7, 8, 9, 6, 0, 4, 10, 11, 12, 3, 0, 0, 0 }; static toDesignSchema_t DoubleCrossoverSchema = { DoubleCrossoverPaths, "040" "460" "610" "280" "8A0" "A30" "451" "5B0" "BA2" "892" "970" "761" }; static toDesignDesc_t DoubleCrossoverDesc = { NTO_D_CROSSOVER, N_("Double Crossover"), 1, COUNT( DoubleCrossoverLines ), DoubleCrossoverLines, COUNT( DoubleCrossoverFloats ), DoubleCrossoverFloats, &DoubleCrossoverSchema, 0 }; static wLines_t StrSectionLines[] = { #include "tostrsct.lin" }; static toDesignFloat_t StrSectionFloats[] = { { { 200, 10 }, I_TOLENGTH+0, N_("Length"), N_("Length"), Dim_e } }; static signed char StrSectionPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 0, 0, 0 }; static toDesignSchema_t StrSectionSchema = { StrSectionPaths, "010" }; static toDesignDesc_t StrSectionDesc = { NTO_STR_SECTION, N_("Straight Section"), 1, COUNT( StrSectionLines ), StrSectionLines, COUNT( StrSectionFloats ), StrSectionFloats, &StrSectionSchema, 0 }; static wLines_t CrvSectionLines[] = { #include "tocrvsct.lin" }; static toDesignFloat_t CrvSectionFloats[] = { { { 225, 90 }, I_TOLENGTH+0, N_("Radius"), N_("Radius"), Dim_e }, { { 225, 140}, I_TOANGLE+0, N_("Angle (Degrees)"), N_("Angle"), Angle_e } }; static signed char CrvSectionPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 0, 0, 0 }; static toDesignSchema_t CrvSectionSchema = { CrvSectionPaths, "011" }; static toDesignDesc_t CrvSectionDesc = { NTO_CRV_SECTION, N_("Curved Section"), 1, COUNT( CrvSectionLines ), CrvSectionLines, COUNT( CrvSectionFloats ), CrvSectionFloats, &CrvSectionSchema, 0 }; #ifdef LATER static wLines_t BumperLines[] = { #include "tostrsct.lin" }; static toDesignFloat_t BumperFloats[] = { { { 200, 10 }, I_TOLENGTH+0, N_("Length"), N_("Length"), Dim_e } }; static signed char BumperPaths[] = { 'N', 'o', 'r', 'm', 'a', 'l', 0, 1, 0, 0, 0 }; static toDesignSchema_t BumperSchema = { BumperPaths, "010" }; static toDesignDesc_t BumperDesc = { NTO_BUMPER, N_("Bumper Section"), 1, COUNT( BumberLines ), BumperLines, COUNT( BumperFloats ), BumperFloats, &BumperSchema, 0 }; static wLines_t TurntableLines[] = { #include "tostrsct.lin" }; static toDesignFloat_t TurntableFloats[] = { { { 200, 10 }, I_TOOFFSET+0, N_("Offset"), N_("Count"), 0 }, { { 200, 10 }, I_TOLENGTH+0, N_("Length"), N_("Radius1"), Dim_e }, { { 200, 10 }, I_TOLENGTH+1, N_("Length"), N_("Radius2"), Dim_e } }; static signed char TurntablePaths[] = { '1', 0, 1, 0, 0, '2', 0, 2, 0, 0, '3', 0, 3, 0, 0, '4', 0, 4, 0, 0, '5', 0, 5, 0, 0, '6', 0, 6, 0, 0, '7', 0, 7, 0, 0, '8', 0, 8, 0, 0, '9', 0, 9, 0, 0, '1', '0', 0, 10, 0, 0, '1', '1', 0, 11, 0, 0, '1', '2', 0, 12, 0, 0, '1', '3', 0, 13, 0, 0, '1', '4', 0, 14, 0, 0, '1', '5', 0, 15, 0, 0, '1', '6', 0, 16, 0, 0, '1', '7', 0, 17, 0, 0, '1', '8', 0, 18, 0, 0, '1', '9', 0, 19, 0, 0, '2', '0', 0, 20, 0, 0, '2', '1', 0, 21, 0, 0, '2', '2', 0, 22, 0, 0, '2', '3', 0, 23, 0, 0, '2', '4', 0, 24, 0, 0, '2', '5', 0, 25, 0, 0, '2', '6', 0, 26, 0, 0, '2', '7', 0, 27, 0, 0, '2', '8', 0, 28, 0, 0, '2', '9', 0, 29, 0, 0, '3', '0', 0, 30, 0, 0, '3', '1', 0, 31, 0, 0, '3', '2', 0, 32, 0, 0, '3', '3', 0, 33, 0, 0, '3', '4', 0, 34, 0, 0, '3', '5', 0, 35, 0, 0, '3', '6', 0, 36, 0, 0, '3', '7', 0, 37, 0, 0, '3', '8', 0, 38, 0, 0, '3', '9', 0, 39, 0, 0, '4', '0', 0, 40, 0, 0, '4', '1', 0, 41, 0, 0, '4', '2', 0, 42, 0, 0, '4', '3', 0, 43, 0, 0, '4', '4', 0, 44, 0, 0, '4', '5', 0, 45, 0, 0, '4', '6', 0, 46, 0, 0, '4', '7', 0, 47, 0, 0, '4', '8', 0, 48, 0, 0, '4', '9', 0, 49, 0, 0, '5', '0', 0, 50, 0, 0, '5', '1', 0, 51, 0, 0, '5', '2', 0, 52, 0, 0, '5', '3', 0, 53, 0, 0, '5', '4', 0, 54, 0, 0, '5', '5', 0, 55, 0, 0, '5', '6', 0, 56, 0, 0, '5', '7', 0, 57, 0, 0, '5', '8', 0, 58, 0, 0, '5', '9', 0, 59, 0, 0, '6', '0', 0, 60, 0, 0, '6', '1', 0, 61, 0, 0, '6', '2', 0, 62, 0, 0, '6', '3', 0, 63, 0, 0, '6', '4', 0, 64, 0, 0, '6', '5', 0, 65, 0, 0, '6', '6', 0, 66, 0, 0, '6', '7', 0, 67, 0, 0, '6', '8', 0, 68, 0, 0, '6', '9', 0, 69, 0, 0, '7', '0', 0, 70, 0, 0, '7', '1', 0, 71, 0, 0, '7', '2', 0, 72, 0, 0, 0 }; static toDesignSchema_t TurntableSchema = { TurntablePaths, "010" "020" "030" "040" "050" "060" "070" "080" "090" "0A0" "0B0" }; static toDesignDesc_t TurntableDesc = { NTO_TURNTABLE, N_("Turntable Section"), 1, COUNT( TurntableLines ), TurntableLines, COUNT( TurntableFloats ), TurntableFLoats, &TurntableSchema, 0 }; #endif #ifndef MKTURNOUT static toDesignDesc_t * designDescs[] = { &RegDesc, &CrvDesc, &CornuDesc, &WyeDesc, &CornuWyeDesc, &ThreewayDesc, &CornuThreewayDesc, &CrossingDesc, &SingleSlipDesc, &DoubleSlipDesc, &RightCrossoverDesc, &LeftCrossoverDesc, &DoubleCrossoverDesc, &StrSectionDesc, &CrvSectionDesc }; #endif /************************************************************************** * * Compute Roadbed * */ int debugComputeRoadbed = 0; #ifdef LATER typedef struct { int start; unsigned long bits; unsigned long mask; int width; } searchTable_t; static searchTable_t searchTable[] = { { 0, 0xFFFF0000, 0xFFFF0000, 32000}, { 32, 0x0000FFFF, 0x0000FFFF, 32000}, { 16, 0x00FFFF00, 0x00FFFF00, 16}, { 8, 0x0FF00000, 0x0FF00000, 8}, { 24, 0x00000FF0, 0x00000FF0, 8}, { 4, 0x3C000000, 0x3C000000, 4}, { 12, 0x003C0000, 0x003C0000, 4}, { 20, 0x00003C00, 0x00003C00, 4}, { 28, 0x0000003C, 0x0000003C, 4}, { 2, 0x60000000, 0x60000000, 2}, { 6, 0x06000000, 0x06000000, 2}, { 10, 0x00600000, 0x00600000, 2}, { 14, 0x00060000, 0x00060000, 2}, { 18, 0x00006000, 0x00006000, 2}, { 22, 0x00000600, 0x00000600, 2}, { 26, 0x00000060, 0x00000060, 2}, { 30, 0x00000006, 0x00000006, 2}, { 1, 0x40000000, 0x60000000, 1}, { 3, 0x10000000, 0x30000000, 1}, { 5, 0x04000000, 0x06000000, 1}, { 7, 0x01000000, 0x03000000, 1}, { 9, 0x00400000, 0x00600000, 1}, { 11, 0x00100000, 0x00300000, 1}, { 13, 0x00040000, 0x00060000, 1}, { 15, 0x00010000, 0x00030000, 1}, { 17, 0x00004000, 0x00006000, 1}, { 19, 0x00001000, 0x00003000, 1}, { 21, 0x00000400, 0x00000600, 1}, { 23, 0x00000100, 0x00000300, 1}, { 25, 0x00000040, 0x00000060, 1}, { 27, 0x00000010, 0x00000030, 1}, { 29, 0x00000004, 0x00000006, 1}, { 31, 0x00000001, 0x00000003, 1} }; #endif double LineSegDistance( coOrd p, coOrd p0, coOrd p1 ) { double d, a; coOrd pp, zero; zero.x = zero.y = (POS_T)0.0; d = FindDistance( p0, p1 ); a = FindAngle( p0, p1 ); pp.x = p.x-p0.x; pp.y = p.y-p0.y; Rotate( &pp, zero, -a ); if (pp.y < 0.0-EPSILON) { return FindDistance( p, p0 ); } else if (pp.y > d+EPSILON ) { return FindDistance( p, p1 ); } else { return pp.x>=0? pp.x : -pp.x; } } double CircleSegDistance( coOrd p, coOrd c, double r, double a0, double a1 ) { double d, d0, d1; double a,aa; coOrd p1; d = FindDistance( c, p ); a = FindAngle( c, p ); aa = NormalizeAngle( a - a0 ); d -= r; if ( aa <= a1 ) { return d>=0 ? d : -d; } PointOnCircle( &p1, c, r, a0 ); d0 = FindDistance( p, p1 ); PointOnCircle( &p1, c, r, a0+a1 ); d1 = FindDistance( p, p1 ); if (d0 < d1) { return d0; } else { return d1; } } BOOL_T HittestTurnoutRoadbed( trkSeg_p segPtr, int segCnt, int segInx, ANGLE_T side, int fraction, DIST_T roadbedWidth ) { ANGLE_T a; DIST_T d; int inx; trkSeg_p sp; coOrd p0, p1; DIST_T dd; int closest; sp = &segPtr[segInx]; if (sp->type == SEG_STRTRK) { d = FindDistance( sp->u.l.pos[0], sp->u.l.pos[1] ); a = FindAngle( sp->u.l.pos[0], sp->u.l.pos[1] ); d *= (fraction*2+1)/64.0; Translate( &p0, sp->u.l.pos[0], a, d ); Translate( &p0, p0, a+side, roadbedWidth/2.0 ); } else { d = sp->u.c.radius; if ( d < 0 ) { d = -d; fraction = 31-fraction; } a = sp->u.c.a0 + sp->u.c.a1*(fraction*2+1)/64.0; if (side>0) { d += roadbedWidth/2.0; } else { d -= roadbedWidth/2.0; } PointOnCircle( &p0, sp->u.c.center, d, a ); } dd = DIST_INF; closest = -1; for (inx=0; inxtype ) { case SEG_STRTRK: d = LineSegDistance( p1, sp->u.l.pos[0], sp->u.l.pos[1] ); break; case SEG_CRVTRK: d = CircleSegDistance( p1, sp->u.c.center, fabs(sp->u.c.radius), sp->u.c.a0, sp->u.c.a1 ); break; default: continue; } #ifdef LATER if (inx==segInx) { d *= .999; } #endif if ( d < dd ) { dd = d; closest = inx; } } if (closest == segInx) { return FALSE; } else { return TRUE; } } #ifdef LATER EXPORT long ComputeTurnoutRoadbedSide( trkSeg_p segPtr, int segCnt, int segInx, ANGLE_T side, DIST_T roadbedWidth ) { DIST_T length; int rbw; unsigned long res, res1; searchTable_t * p; double where; trkSeg_p sp; sp = &segPtr[segInx]; if (sp->type == SEG_STRTRK) { length = FindDistance( sp->u.l.pos[0], sp->u.l.pos[1] ); } else { length = (fabs(sp->u.c.radius) + (side>0?roadbedWidth/2.0:-roadbedWidth/2.0) ) * 2 * M_PI * sp->u.c.a1 / 360.0; } rbw = (int)(roadbedWidth/length*32/2); /*printf( "L=%0.3f G=%0.3f [%0.3f %0.3f] RBW=%d\n", length, gapWidth, first, last, rbw );*/ res = 0xFF0000FF; for ( p=searchTable; p<&searchTable[COUNT( searchTable )]; p++) { if ( (p->width < rbw && res==0xFFFFFFFF) || res==0 ) { break; } res1 = (p->mask & res); where = p->start*length/32.0; if (p->width >= rbw || (res1!=p->mask && res1!=0)) { if (HittestTurnoutRoadbed(segPtr, segCnt, segInx, side, p->start)) { res &= ~p->bits; if (debugComputeRoadbed>=1) { printf( "res=%08lx *p={%02d %08lx %08lx %02d} res1=%08lx W=%0.3f HIT\n", res, p->start, p->bits, p->mask, p->width, res1, where ); } } else { res |= p->bits; if (debugComputeRoadbed>=1) { printf( "res=%08lx *p={%02d %08lx %08lx %02d} res1=%08lx W=%0.3f MISS\n", res, p->start, p->bits, p->mask, p->width, res1, where ); } } } else { if (debugComputeRoadbed>=2) { printf( "res=%08lx *p={%02d %08lx %08lx %02d} res1=%08lx W=%0.3f SKIP\n", res, p->start, p->bits, p->mask, p->width, res1, where ); } } } if (debugComputeRoadbed>=1) { printf( "res=%08lx\n", res ); } return res; } #endif EXPORT long ComputeTurnoutRoadbedSide( trkSeg_p segPtr, int segCnt, int segInx, ANGLE_T side, DIST_T roadbedWidth ) { trkSeg_p sp; DIST_T length; int bitWidth; unsigned long res, mask; int hit0, hit1, inx0, inx1; int i, j, k, hitx; sp = &segPtr[segInx]; if (sp->type == SEG_STRTRK) { length = FindDistance( sp->u.l.pos[0], sp->u.l.pos[1] ); } else { length = (fabs(sp->u.c.radius) + (side>0?roadbedWidth/2.0:-roadbedWidth/2.0) ) * 2 * M_PI * sp->u.c.a1 / 360.0; } bitWidth = (int)floor(roadbedWidth*32/length); if ( bitWidth > 31 ) { bitWidth = 31; } else if ( bitWidth <= 0 ) { bitWidth = 2; } res = 0; mask = (1<=3 ) { printf( "bW=%d HT[0]=%d\n", bitWidth, hit0 ); } while ( 1 ) { if ( inx1 > 31 ) { inx1 = 31; } hit1 = HittestTurnoutRoadbed( segPtr, segCnt, segInx, side, inx1, roadbedWidth ); if ( debugComputeRoadbed>=3 ) { printf( " HT[%d]=%d\n", inx1, hit1 ); } if ( hit0 != hit1 ) { i=inx0; j=inx1; while ( j-i >= 2 ) { k = (i+j)/2; hitx = HittestTurnoutRoadbed( segPtr, segCnt, segInx, side, k, roadbedWidth ); if ( debugComputeRoadbed>=3 ) { printf( " .HT[%d]=%d\n", k, hitx ); } if ( hitx == hit0 ) { i = k; } else { j = k; } } if ( !hit0 ) { res |= ((1<<(i-inx0+1))-1)<=3 ) { printf( " res=%lx\n", res ); } if ( inx1 >= 31 ) { if ( !hit1 ) { res |= 0x80000000; } break; } mask <<= bitWidth; inx0 = inx1; inx1 += bitWidth; hit0 = hit1; } if ( debugComputeRoadbed>=2 ) { printf( "S%d %c res=%lx\n", segInx, side>0?'+':'-', res ); } return (0xFFFFFFFF)&res; } static BOOL_T IsNear( coOrd p0, coOrd p1 ) { DIST_T d; d = FindDistance( p0, p1 ); return d < 0.05; } static void AddRoadbedPieces( int inx, ANGLE_T side, int first, int last ) { DIST_T d0, d1; ANGLE_T a0, a1; coOrd p0, p1; trkSeg_p sp, sq; if (last<=first) { return; } sp = &tempSegs(inx); if ( sp->type == SEG_STRTRK ) { d0 = FindDistance( sp->u.l.pos[0], sp->u.l.pos[1] ); a0 = FindAngle( sp->u.l.pos[0], sp->u.l.pos[1] ); d1 = d0*first/32.0; Translate( &p0, sp->u.l.pos[0], a0, d1 ); Translate( &p0, p0, a0+side, newTurnRoadbedWidth/2.0 ); d1 = d0*last/32.0; Translate( &p1, sp->u.l.pos[0], a0, d1 ); Translate( &p1, p1, a0+side, newTurnRoadbedWidth/2.0 ); if ( first==0 || last==32 ) { for ( sq=&tempSegs(0); sq<&tempSegs(tempSegs_da.cnt); sq++ ) { if ( sq->type == SEG_STRLIN ) { a1 = FindAngle( sq->u.l.pos[0], sq->u.l.pos[1] ); a1 = NormalizeAngle( a1-a0+0.5 ); if ( first==0 ) { if ( a1 < 1.0 && IsNear( p0, sq->u.l.pos[1] ) ) { sq->u.l.pos[1] = p1; return; } else if ( a1 > 180.0 && a1 < 181.0 && IsNear( p0, sq->u.l.pos[0] ) ) { sq->u.l.pos[0] = p1; return; } } if ( last==32 ) { if ( a1 < 1.0 && IsNear( p1, sq->u.l.pos[0] ) ) { sq->u.l.pos[0] = p0; return; } else if ( a1 > 180.0 && a1 < 181.0 && IsNear( p1, sq->u.l.pos[1] ) ) { sq->u.l.pos[1] = p0; return; } } } } } } DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 ); sp = &tempSegs(inx); sq = &tempSegs(tempSegs_da.cnt-1); sq->lineWidth = newTurnRoadbedLineWidth; sq->color = newTurnRoadbedColor; if (sp->type == SEG_STRTRK) { sq->type = SEG_STRLIN; sq->u.l.pos[0] = p0; sq->u.l.pos[1] = p1; } else { d0 = sp->u.c.radius; if ( d0 > 0 ) { a0 = NormalizeAngle( sp->u.c.a0 + sp->u.c.a1*first/32.0 ); } else { d0 = -d0; a0 = NormalizeAngle( sp->u.c.a0 + sp->u.c.a1*(32-last)/32.0 ); } a1 = sp->u.c.a1*(last-first)/32.0; if (side>0) { d0 += newTurnRoadbedWidth/2.0; } else { d0 -= newTurnRoadbedWidth/2.0; } sq->type = SEG_CRVLIN; sq->u.c.center = sp->u.c.center; sq->u.c.radius = d0; sq->u.c.a0 = a0; sq->u.c.a1 = a1; } } static void AddRoadbedToOneSide( int trkCnt, int inx, ANGLE_T side ) { unsigned long res, res1; int b0, b1; res = ComputeTurnoutRoadbedSide( &tempSegs(0), trkCnt, inx, side, newTurnRoadbedWidth ); if ( res == 0L ) { return; } else if ( res == 0xFFFFFFFF ) { AddRoadbedPieces( inx, side, 0, 32 ); } else { for ( b0=0, res1=0x00000001; res1&&(res1&res); b0++,res1<<=1 ); for ( b1=32,res1=0x80000000; res1&&(res1&res); b1--,res1>>=1 ); AddRoadbedPieces( inx, side, 0, b0 ); AddRoadbedPieces( inx, side, b1, 32 ); } } static void AddRoadbed( void ) { int trkCnt, inx; trkSeg_p sp; if ( newTurnRoadbedWidth < newTurnTrackGauge ) { return; } trkCnt = tempSegs_da.cnt; for ( inx=0; inxtype!=SEG_STRTRK && sp->type!=SEG_CRVTRK ) { continue; } AddRoadbedToOneSide( trkCnt, inx, +90 ); AddRoadbedToOneSide( trkCnt, inx, -90 ); } } /********************************************************************* * * Functions * */ static BOOL_T ComputeCurve( coOrd *p0, coOrd *p1, DIST_T *radius, DIST_T len, DIST_T off, ANGLE_T angle ) { coOrd Pf; coOrd Px, Pc; DIST_T d; Pf.x = len; Pf.y = off; p0->x = p0->y = 0.0; /*lprintf( "Angle = %0.3f\n", angle );*/ FindIntersection( &Px, *p0, 90.0, Pf, 90.0-angle ); d = FindDistance( Px, Pf )-newTurnTrackGauge; if (Px.x < newTurnTrackGauge || d < 0.0) { NoticeMessage( MSG_TODSGN_NO_CONVERGE, _("Ok"), NULL ); return FALSE; } if (Px.x-newTurnTrackGauge < d) { d = Px.x-newTurnTrackGauge; } *radius = d * cos( D2R(angle/2.0) ) / sin( D2R(angle/2.0) ); p0->x = Px.x - *radius * sin( D2R(angle/2.0) ) / cos( D2R(angle/2.0) ); Translate( &Pc, *p0, 0.0, *radius ); PointOnCircle( p1, Pc, *radius, 180.0-angle ); return TRUE; } #ifndef MKTURNOUT /* For Bezier Segs we need to duplicate the subSegs Array as well */ void AppendSegs(dynArr_t * target, dynArr_t * source) { #define sourceSegs(N) DYNARR_N( trkSeg_t, *source, N ) #define targetSegs(N) DYNARR_N( trkSeg_t, *target, N ) trkSeg_p src; for (int i=0; icnt; i++) { src = &sourceSegs(i); addSegBezier(target, src); } } /* Bezier Segs will have subSegs Array - free it before resetting the array */ void ClearSegs(dynArr_t * target) { for (int i=0; i<(*target).cnt; i++) { if (targetSegs(i).type == SEG_BEZTRK) { // Free DA if a BEZTRK DYNARR_FREE( trkSeg_t, targetSegs(i).bezSegs ); } else { // Otherwise just clear it DYNARR_INIT( trkSeg_t, targetSegs(i).bezSegs ); } } DYNARR_RESET( trkSeg_t, *target ); } BOOL_T CallCornuNoBez(coOrd pos[2], coOrd center[2], ANGLE_T angle[2], DIST_T radius[2], dynArr_t * array_p) { dynArr_t temp_array; DYNARR_INIT(trkSeg_t,temp_array); wBool_t rc = CallCornu0(pos,center,angle,radius, &temp_array, FALSE); if (!rc) { return FALSE; } for (int i=0; itype == SEG_BEZTRK) || (from_seg->type == SEG_BEZLIN)) { for (int j=0; jbezSegs.cnt; j++) { trkSeg_p sub_seg = &DYNARR_N(trkSeg_t,from_seg->bezSegs,j); DYNARR_APPEND(trkSeg_t,*array_p,5); trkSeg_p to_seg = &DYNARR_N(trkSeg_t,*array_p,(*array_p).cnt-1); to_seg->u = sub_seg->u; to_seg->type = sub_seg->type; to_seg->color = wDrawColorBlack; to_seg->lineWidth = sub_seg->lineWidth; } } else { DYNARR_APPEND(trkSeg_t,*array_p,5); trkSeg_p to_seg = &DYNARR_N(trkSeg_t,*array_p,(*array_p).cnt-1); to_seg->u = from_seg->u; to_seg->type = from_seg->type; to_seg->color = wDrawColorBlack; to_seg->lineWidth = from_seg->lineWidth; } } ClearSegs(&temp_array); return TRUE; } #endif static toDesignSchema_t * LoadSegs( toDesignDesc_t * dp, wBool_t loadPoints ) { wIndex_t s; int p, p0, p1; DIST_T d; toDesignSchema_t * pp; char *segOrder; coOrd pos; wIndex_t segCnt = 0; ANGLE_T angle0, angle1, angle2, angle3; trkSeg_p segPtr; #ifndef MKTURNOUT wIndex_t pathLen; struct { coOrd pos[10]; coOrd center[10]; DIST_T radius[10]; DIST_T angle[10]; } cornuData; #endif DYNARR_RESET( trkSeg_t, tempSegs_da ); angle0 = newTurnAngle0; angle1 = newTurnAngle1; angle2 = newTurnAngle2; angle3 = newTurnAngle3; if ( newTurnAngleMode == 0 && dp->type != NTO_CRV_SECTION ) { /* convert from Frog Num to degrees */ if ( angle0 > 0 ) { angle0 = R2D(asin(1.0 / angle0)); } if ( angle1 > 0 ) { angle1 = R2D(asin(1.0 / angle1)); } if ( angle2 > 0 ) { angle2 = R2D(asin(1.0 / angle2)); } if ( angle3 > 0 ) { angle3 = R2D(asin(1.0 / angle3)); } } pp = dp->paths; if (loadPoints) { TempEndPtsReset(); // for ( i=0; ifloatCnt; i++ ) // if ( *(FLOAT_T*)(turnDesignPLs[dp->floats[i].index].valueP) == 0.0 ) // if (dp->type != NTO_CORNU && // dp->type != NTO_CORNUWYE && // dp->type != NTO_CORNU3WAY // ) { // NoticeMessage( MSG_TODSGN_VALUES_GTR_0, _("Ok"), NULL ); // return NULL; // } switch (dp->type) { case NTO_REGULAR: TempEndPtsSet( 3 ); if ( !ComputeCurve( &points[3], &points[4], &radii[0], (newTurnLen0), fabs(newTurnOff0), angle0 ) ) { return NULL; } radii[0] = - radii[0]; points[0].x = points[0].y = points[1].y = 0.0; points[1].x = (newTurnLen1); points[2].y = fabs(newTurnOff0); points[2].x = (newTurnLen0); SetEndPt( TempEndPt(0), points[0], 270.0 ); SetEndPt( TempEndPt(1), points[1], 90.0 ); SetEndPt( TempEndPt(2), points[2], 90.0-angle0 ); break; case NTO_CURVED: TempEndPtsSet( 3 ); if ( !ComputeCurve( &points[3], &points[4], &radii[0], (newTurnLen0), fabs(newTurnOff0), angle0 ) ) { return NULL; } if ( !ComputeCurve( &points[5], &points[6], &radii[1], (newTurnLen1), fabs(newTurnOff1), angle1 ) ) { return NULL; } d = points[3].x - points[5].x; if ( d < -MIN_TRACK_LENGTH ) { pp = &Crv3Schema; } else if ( d > MIN_TRACK_LENGTH ) { pp = &Crv2Schema; } else { pp = &Crv1Schema; } radii[0] = - radii[0]; radii[1] = - radii[1]; points[0].x = points[0].y = 0.0; points[1].y = fabs(newTurnOff0); points[1].x = (newTurnLen0); points[2].y = fabs(newTurnOff1); points[2].x = (newTurnLen1); SetEndPt( TempEndPt(0), points[0], 270.0 ); SetEndPt( TempEndPt(2), points[1], 90.0-angle0 ); SetEndPt( TempEndPt(1), points[2], 90.0-angle1 ); break; #ifndef MKTURNOUT case NTO_CORNU: TempEndPtsSet( 3 ); radii[0] = fabs(newTurnRad2); /*Toe*/ radii[1] = fabs(newTurnRad0); /*Inner*/ radii[2] = fabs(newTurnRad1); /*Outer*/ angles[0] = 0.0; /*Base*/ angles[1] = angle0; /*Inner*/ angles[2] = angle1; /*Outer*/ pp = &CornuSchema; points[0].x = points[0].y = 0.0; points[1].y = (newTurnOff0); points[1].x = (newTurnLen0); /*Inner*/ points[2].y = (newTurnOff1); points[2].x = (newTurnLen1); /*Outer*/ SetEndPt( TempEndPt(0), points[0], 270.0 ); SetEndPt( TempEndPt(2), points[1], 90.0-angles[1] ); SetEndPt( TempEndPt(1), points[2], 90.0-angles[2] ); break; #endif case NTO_WYE: case NTO_3WAY: TempEndPtsSet( (dp->type==NTO_3WAY)?4:3 ); if ( !ComputeCurve( &points[3], &points[4], &radii[0], (newTurnLen0), fabs(newTurnOff0), angle0 ) ) { return NULL; } if ( !ComputeCurve( &points[5], &points[6], &radii[1], (newTurnLen1), fabs(newTurnOff1), angle1 ) ) { return NULL; } points[5].y = - points[5].y; points[6].y = - points[6].y; radii[0] = - radii[0]; points[0].x = points[0].y = 0.0; points[1].y = fabs(newTurnOff0); points[1].x = (newTurnLen0); points[2].y = -fabs(newTurnOff1); points[2].x = (newTurnLen1); points[7].y = 0; points[7].x = (newTurnLen2); d = points[3].x - points[5].x; if ( d < -MIN_TRACK_LENGTH ) { pp = (dp->type==NTO_3WAY ? &Tri3Schema : &Wye3Schema ); } else if ( d > MIN_TRACK_LENGTH ) { pp = (dp->type==NTO_3WAY ? &Tri2Schema : &Wye2Schema ); } else { pp = (dp->type==NTO_3WAY ? &Tri1Schema : &Wye1Schema ); } SetEndPt( TempEndPt(0), points[0], 270.0 ); SetEndPt( TempEndPt(1), points[1], 90.0-angle0 ); SetEndPt( TempEndPt(2), points[2], 90.0+angle1 ); if (dp->type == NTO_3WAY) { SetEndPt( TempEndPt(3), points[7], 90.0 ); } break; #ifndef MKTURNOUT case NTO_CORNUWYE: case NTO_CORNU3WAY: TempEndPtsSet( (dp->type==NTO_CORNU3WAY)?4:3 ); /* * Construct Wye and 3 Way Turnouts with Cornu curves * 1. Establish where the joint(s) (Toes) are by using the main curve * 2. Rebuild the segments into a single set using those points * 3. Build Path statements to suit the segments * --------------------------------------------------------------------------------------------- * 7 CornuData. Cheat Sheet - segment array parts * =============+ Note - 6-7 is at Toe2 and 8-9 at Toe1 if RH comes before LH * // Toe 2 - Toe2 and Toe1 are the same (no 2-3) if co-incident * 0 6+ 3 4 5 - Toe2, 2-3 and 4-5 all only exist for 3WAY not WYE * +=====+ +=====+ +==================+ - If zero radius at 0, curve starts at Toe 1 * 1 2 8+ * Toe 1 \\ 9 * =========+ * * --------------------------------------------------------------------------------------------- */ radii[0] = (newTurnRad2); /*Base*/ radii[1] = (newTurnRad0); /*Left*/ radii[2] = (newTurnRad1); /*Right*/ radii[3] = (newTurnRad3); /*Center*/ angles[0] = 0.0; /*Base*/ angles[1] = angle0; /*Left*/ angles[2] = angle1; /*Right*/ angles[3] = angle3; /*Center*/ points[0].x = points[0].y = 0.0; /*Base*/ points[1].y = (newTurnOff0); /* Left */ points[1].x = (newTurnLen0); points[2].y = -(newTurnOff1); /* Right */ points[2].x = (newTurnLen1); if (dp->type==NTO_CORNU3WAY) { points[3].y = (newTurnOff3); /* Center */ points[3].x = (newTurnLen3); } pp = (dp->type==NTO_CORNU3WAY ? &CornuTriSchema : &CornuWyeSchema ); SetEndPt( TempEndPt(0), points[0], 270.0 ); if (newTurnRad0<0.0) { SetEndPt( TempEndPt(1), points[1], 90.0+angles[1] ); } else { SetEndPt( TempEndPt(1), points[1], 90.0-angles[1] ); } if (newTurnRad1<0.0) { SetEndPt( TempEndPt(2), points[2], 90.0-angles[2] ); } else { SetEndPt( TempEndPt(2), points[2], 90.0+angles[2] ); } if (dp->type == NTO_CORNU3WAY) { if (newTurnRad3<0.0) { SetEndPt( TempEndPt(3), points[3], 90.0+angles[3] ); } else { SetEndPt( TempEndPt(3), points[3], 90.0-angles[3] ); } } DIST_T end_length = MIN_TRACK_LENGTH; for (int i=0; i<((dp->type==NTO_CORNU3WAY)?4:3); i++) { if (radii[i] == 0.0) { if (i==2) { Translate(&end_points[i], points[i], NormalizeAngle(90.0+angles[i]+180), end_length); } else { Translate(&end_points[i], points[i], NormalizeAngle(90.0-angles[i]+(i==0?0.0:180.0)), end_length); } end_angles[i] = angles[i]; } else { if (i!=2) { if (((i==0) && radii[0]>0.0) || ((i==1 || i==3) && radii[i]>0.0)) { Translate(&end_centers[i], points[i], -angles[i], fabs(radii[i])); } else { Translate(&end_centers[i], points[i], angles[i]+180, fabs(radii[i])); } end_arcs[i] = (radii[i]>=0?1:-1)*R2D(end_length/fabs(radii[i])); } else { if (radii[2]>0.0) { Translate(&end_centers[i], points[i], angles[i]+180, fabs(radii[i])); } else { Translate(&end_centers[i], points[i], -angles[i], fabs(radii[i])); } end_arcs[i] = (radii[i]>=0?-1:1)*R2D(end_length/fabs(radii[i])); } end_points[i] = points[i]; Rotate(&end_points[i],end_centers[i],end_arcs[i]); end_angles[i] = angles[i]+end_arcs[i]; } LOG( log_cornuturnoutdesigner, 1, ( "ctoDes0-%d: EP(%f,%f) NEP(%f,%f) EA(%f) NEA(%f) R(%f) ARC(%f) EC(%f,%f) \n", \ i+1,points[i].x,points[i].y,end_points[i].x,end_points[i].y,angles[i], end_angles[i],radii[i],end_arcs[i], \ end_centers[i].x,end_centers[i].y) ); } wBool_t LH_main = TRUE, LH_first = TRUE; cornuData.pos[0] = end_points[0]; /*Start*/ if (dp->type == NTO_CORNU3WAY) { if (newTurnToeR < newTurnToeL) { LH_first = FALSE; } cornuData.pos[1] = end_points[3]; /*Center for First Time */ cornuData.pos[5] = end_points[3]; /*Center for last time*/ } else if (newTurnRad1>=0.0) { cornuData.pos[1] = end_points[1]; /*Left is dominant curve */ newTurnToeR = newTurnToeL; } else { cornuData.pos[1] = end_points[2]; /*Right is dominant */ newTurnToeR = newTurnToeL; LH_main = FALSE; } cornuData.pos[7] = end_points[1]; /*Left*/ cornuData.pos[9] = end_points[2]; /*Right*/ if (dp->type == NTO_CORNU3WAY) { cornuData.pos[5] = end_points[3]; /*Center */ } if (radii[0] == 0.0) { /* Base */ cornuData.center[0] = zero; } else { cornuData.center[0].x = end_points[0].x; cornuData.center[0].y = end_points[0].y + radii[0]; } if (radii[1] == 0.0) { /* Left */ cornuData.center[7] = zero; } else if (radii[1] >0.0) { Translate(&cornuData.center[7], cornuData.pos[7], -end_angles[1], radii[1]); } else { Translate(&cornuData.center[7], cornuData.pos[7], 180.0+end_angles[1], radii[1]); } if (radii[2] == 0.0) { /* Right */ cornuData.center[9] = zero; } else if (radii[2] >0.0) { Translate(&cornuData.center[9], cornuData.pos[9], 180.0+end_angles[2], radii[2]); } else { Translate(&cornuData.center[9], cornuData.pos[9], -end_angles[2], radii[2]); } if (dp->type == NTO_CORNU3WAY) { if (radii[3] == 0.0) { /* Center */ cornuData.center[5] = zero; } else if (radii[3] >0.0) { Translate(&cornuData.center[5], cornuData.pos[5], -end_angles[3], radii[3]); } else { Translate(&cornuData.center[5], cornuData.pos[5], 180.0+end_angles[3], radii[3]); } } /* Set up for calculation of Toe(s) */ if (dp->type == NTO_CORNU3WAY) { cornuData.center[1] = cornuData.center[5]; /*For Toe1 calc always use center */ cornuData.center[3] = cornuData.center[5]; /*For Toe2 calc always use center*/ } else if (LH_main) { cornuData.center[1] = cornuData.center[7]; /* Dominant Curve Left */ } else { cornuData.center[1] = cornuData.center[9]; /* Right */ } cornuData.angle[0] = 270.0; /*Always*/ if (dp->type == NTO_CORNU3WAY) { cornuData.angle[1] = 90.0-end_angles[3]; cornuData.angle[3] = 90.0-end_angles[3]; cornuData.angle[5] = 90.0-end_angles[3]; /* Only used for 3way */ } else if (LH_main) { cornuData.angle[1] = 90.0-end_angles[1]; } else { cornuData.angle[1] = 90.0+end_angles[2]; } cornuData.angle[7] = 90.0-end_angles[1]; /*Left*/ cornuData.angle[9] = 90.0+end_angles[2]; /*Right*/ cornuData.radius[0] = fabs(radii[0]); if (dp->type == NTO_CORNU3WAY) { cornuData.radius[1] = fabs(radii[3]); cornuData.radius[3] = fabs(radii[3]); cornuData.radius[5] = fabs(radii[3]); } else if (LH_main) { cornuData.radius[1] = fabs(radii[1]); } else { cornuData.radius[1] = fabs(radii[2]); } cornuData.radius[7] = fabs(radii[1]); /*Left*/ cornuData.radius[9] = fabs(radii[2]); /*Right*/ /* Ready to find Toe points */ DYNARR_RESET( trkSeg_t, tempSegs_da ); DIST_T radius = 0.0; coOrd center; ANGLE_T angle; int inx,subSeg; wBool_t back, neg; /* Override if a "Y" has zero radius at base to be a straight until the Toe * We set the start of the curve to be at the Toe position */ if (cornuData.radius[0] == 0.0) { pos.x = end_points[0].x+(LH_first?newTurnToeL:newTurnToeR)-MIN_TRACK_LENGTH; pos.y = end_points[0].y; angle = 90.0; radius = 0.0; center = zero; } else { /*Find Toe 1 from curve */ CallCornu0(&cornuData.pos[0],&cornuData.center[0],&cornuData.angle[0], &cornuData.radius[0],&tempSegs_da, FALSE); /*Get ToeAngle/Radius/Center for first toe */ pos.x = end_points[0].x+(LH_first?newTurnToeL:newTurnToeR); pos.y = end_points[0].y; /* This will be close to but not on the curve */ angle = GetAngleSegs(tempSegs_da.cnt,&tempSegs(0),&pos,&inx, NULL,&back,&subSeg,&neg); segPtr = &DYNARR_N(trkSeg_t, tempSegs_da, inx); if (segPtr->type == SEG_BEZTRK) { segPtr = &DYNARR_N(trkSeg_t,segPtr->bezSegs,subSeg); } if (segPtr->type == SEG_STRTRK) { radius = 0.0; center = zero; } else if (segPtr->type == SEG_CRVTRK) { center = segPtr->u.c.center; radius = fabs(segPtr->u.c.radius); } } /* Set up 2-3 even if we don't use it */ cornuData.pos[1] = pos; cornuData.center[1] = center; cornuData.angle[1] = angle; cornuData.radius[1] = radius; cornuData.pos[2] = pos; cornuData.center[2] = center; cornuData.angle[2] = NormalizeAngle(180.0+angle); cornuData.radius[2] = radius; if ((dp->type == NTO_CORNU3WAY) && (newTurnToeR!=newTurnToeL)) { if (LH_first) { cornuData.pos[6] = pos; cornuData.center[6] = center; cornuData.angle[6] = NormalizeAngle(180.0+angle); cornuData.radius[6] = radius; } else { cornuData.pos[8] = pos; cornuData.center[8] = center; cornuData.angle[8] = NormalizeAngle(180.0+angle); cornuData.radius[8] = radius; } } else { /* Just one toe */ cornuData.pos[8] = pos; cornuData.center[8] = center; cornuData.angle[8] = NormalizeAngle(180.0+angle); cornuData.radius[8] = radius; cornuData.pos[6] = pos; cornuData.center[6] = center; cornuData.angle[6] = NormalizeAngle(180.0+angle); cornuData.radius[6] = radius; } if (dp->type == NTO_CORNU3WAY) { if (newTurnToeR!=newTurnToeL) { /* Second Toe */ if (cornuData.radius[0] == 0.0) { pos.x = end_points[0].x+(LH_first?newTurnToeR:newTurnToeL)-MIN_TRACK_LENGTH; pos.y = 0.0; angle = 90.0; radius = 0.0; center = zero; } else { pos.x = end_points[0].x+(LH_first?newTurnToeR:newTurnToeL); pos.y = end_points[0].y; /* This will be close to but not on the curve */ angle = GetAngleSegs(tempSegs_da.cnt,&tempSegs(0),&pos,&inx, NULL,&back,&subSeg,&neg); segPtr = &DYNARR_N(trkSeg_t, tempSegs_da, inx); if (segPtr->type == SEG_BEZTRK) { segPtr = &DYNARR_N(trkSeg_t,segPtr->bezSegs,subSeg); } if (segPtr->type == SEG_STRTRK) { radius = 0.0; center = zero; } else if (segPtr->type == SEG_CRVTRK) { center = segPtr->u.c.center; radius = fabs(segPtr->u.c.radius); } } cornuData.pos[3] = pos; cornuData.center[3] = center; cornuData.angle[3] = angle; cornuData.radius[3] = radius; cornuData.pos[4] = pos; cornuData.center[4] = center; cornuData.angle[4] = NormalizeAngle(180.0+angle); cornuData.radius[4] = radius; if (LH_first) { cornuData.pos[8] = pos; cornuData.center[8] = center; cornuData.angle[8] = NormalizeAngle(180.0+angle); cornuData.radius[8] = radius; cornuData.pos[4] = pos; cornuData.center[4] = center; cornuData.angle[4] = NormalizeAngle(180.0+angle); cornuData.radius[4] = radius; } else { cornuData.pos[6] = pos; cornuData.center[6] = center; cornuData.angle[6] = NormalizeAngle(180.0+angle); cornuData.radius[6] = radius; cornuData.pos[4] = pos; cornuData.center[4] = center; cornuData.angle[4] = NormalizeAngle(180.0+angle); cornuData.radius[4] = radius; } } else { //Set next center start to same place cornuData.pos[4] = pos; cornuData.center[4] = center; cornuData.angle[4] = NormalizeAngle(180.0+angle); cornuData.radius[4] = radius; } } static dynArr_t cornuSegs_da; ClearSegs(&tempSegs_da); ClearSegs(&cornuSegs_da); int Toe1Seg = 0, Toe2Seg = 0, CenterEndSeg = 0, LeftEndSeg = 0, RightEndSeg = 0; /* Override if at zero radius at base don't compute end */ if (cornuData.radius[0] == 0.0) { DYNARR_APPEND(trkSeg_t,tempSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = zero; temp_p->u.l.pos[1] = cornuData.pos[0]; LOG( log_cornuturnoutdesigner, 1, ( "ctoDes1: P0(%f,%f) P1(%f,%f) \n", \ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x, temp_p->u.l.pos[1].y ) ); } else { DYNARR_APPEND(trkSeg_t,tempSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da); temp_p->type = SEG_CRVTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.c.radius = fabs(radii[0]);; if (radii[0]>0.0) { temp_p->u.c.a0 = FindAngle(end_centers[0],end_points[0]); } else { temp_p->u.c.a0 = FindAngle(end_centers[0],points[0]); } temp_p->u.c.a1 = fabs(end_arcs[0]); temp_p->u.c.center = end_centers[0]; coOrd rp0,rp1; Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius); Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1, temp_p->u.c.radius); LOG( log_cornuturnoutdesigner, 1, ( "ctoDes1: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f), EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n", \ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x, temp_p->u.c.center.y, \ points[0].x,points[0].y,end_points[0].x,end_points[0].y, \ rp0.x,rp0.y,rp1.x,rp1.y) ) ; } //If Radius zero, just a straight to the First Toe if offset if (cornuData.radius[0] == 0.0) { if ((cornuData.pos[0].x != cornuData.pos[1].x) || (cornuData.pos[0].y != cornuData.pos[1].y)) { DYNARR_APPEND(trkSeg_t,tempSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = cornuData.pos[0]; temp_p->u.l.pos[1] = cornuData.pos[1]; } } else if ((cornuData.pos[0].x != cornuData.pos[1].x) || (cornuData.pos[0].y != cornuData.pos[1].y) ) { CallCornuNoBez(&cornuData.pos[0],&cornuData.center[0],&cornuData.angle[0], &cornuData.radius[0],&tempSegs_da); } Toe1Seg = tempSegs_da.cnt; if (dp->type == NTO_CORNU3WAY) { if (newTurnToeR!=newTurnToeL) { /* Toe1 to Toe2 in tempSegs array */ if (cornuData.radius[0] == 0.0) { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = cornuData.pos[2]; temp_p->u.l.pos[1] = cornuData.pos[3]; } else if ((cornuData.pos[2].x != cornuData.pos[3].x) || (cornuData.pos[2].y != cornuData.pos[3].y) ) { CallCornuNoBez(&cornuData.pos[2],&cornuData.center[2],&cornuData.angle[2], &cornuData.radius[2],&cornuSegs_da); } Toe2Seg = cornuSegs_da.cnt+Toe1Seg; /* Add to second cornu to tempSegs array */ AppendSegs(&tempSegs_da,&cornuSegs_da); /* Get ready to reuse cornuSegs array*/ ClearSegs(&cornuSegs_da); } else { Toe2Seg = Toe1Seg; //No Toe2 } /* Toe2 to Center in cornuSegs array */ CallCornuNoBez(&cornuData.pos[4],&cornuData.center[4],&cornuData.angle[4], &cornuData.radius[4],&cornuSegs_da); if (cornuData.radius[5] == 0.0) { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = cornuData.pos[5]; temp_p->u.l.pos[1] = points[3]; LOG( log_cornuturnoutdesigner, 1, ( "ctoDes2: P0(%f,%f) P1(%f,%f) \n", \ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x, temp_p->u.l.pos[1].y )) ; } else { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_CRVTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.c.radius = -radii[3]; //Assumed Left if (radii[3]>0) { temp_p->u.c.a0 = FindAngle(end_centers[3],points[3]); } else { temp_p->u.c.a0 = FindAngle(end_centers[3],end_points[3]); } temp_p->u.c.a1 = fabs(end_arcs[3]); temp_p->u.c.center = end_centers[3]; coOrd rp0,rp1; Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius); Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1, temp_p->u.c.radius); LOG( log_cornuturnoutdesigner, 1, ( "ctoDes2: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n", \ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x, temp_p->u.c.center.y, \ points[3].x,points[3].y,end_points[3].x,end_points[3].y, \ rp0.x,rp0.y,rp1.x,rp1.y) ); } CenterEndSeg = cornuSegs_da.cnt+Toe2Seg; /* Add to second cornu to tempSegs array */ AppendSegs(&tempSegs_da,&cornuSegs_da); /* Get ready to reuse cornuSegs array*/ ClearSegs(&cornuSegs_da); } else { CenterEndSeg = Toe2Seg = Toe1Seg; //No Toe2, No Center } /* Left in cornuSegs array*/ CallCornuNoBez(&cornuData.pos[6],&cornuData.center[6],&cornuData.angle[6], &cornuData.radius[6],&cornuSegs_da); if (cornuData.radius[7] == 0.0) { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = cornuData.pos[7]; temp_p->u.l.pos[1] = points[1]; LOG( log_cornuturnoutdesigner, 1, ( "ctoDes2: P0(%f,%f) P1(%f,%f) \n", \ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x, temp_p->u.l.pos[1].y ) ); } else { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_CRVTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.c.radius = -radii[1]; //Negative relative to left if (radii[1]>0) { temp_p->u.c.a0 = FindAngle(end_centers[1],points[1]); } else { temp_p->u.c.a0 = FindAngle(end_centers[1],end_points[1]); } temp_p->u.c.a1 = fabs(end_arcs[1]); temp_p->u.c.center = end_centers[1]; coOrd rp0,rp1; Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius); Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1, temp_p->u.c.radius); LOG( log_cornuturnoutdesigner, 1, ( "ctoDes2: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n", \ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x, temp_p->u.c.center.y, \ points[1].x,points[1].y,end_points[1].x,end_points[1].y, \ rp0.x,rp0.y,rp1.x,rp1.y) ); } LeftEndSeg = cornuSegs_da.cnt+CenterEndSeg; /* Add to second cornu to tempSegs array */ AppendSegs(&tempSegs_da,&cornuSegs_da); /* Get ready to reuse cornuSegs array*/ ClearSegs(&cornuSegs_da); /* Right in cornuSegs array*/ CallCornuNoBez(&cornuData.pos[8],&cornuData.center[8],&cornuData.angle[8], &cornuData.radius[8],&cornuSegs_da); if (cornuData.radius[9] == 0.0) { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = cornuData.pos[9]; temp_p->u.l.pos[1] = points[2]; LOG( log_cornuturnoutdesigner, 1, ( "ctoDes2: P0(%f,%f) P1(%f,%f) \n", \ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x, temp_p->u.l.pos[1].y ) ); } else { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_CRVTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.c.radius = radii[2]; if (radii[2]>0) { temp_p->u.c.a0 = FindAngle(end_centers[2],cornuData.pos[9]); } else { temp_p->u.c.a0 = FindAngle(end_centers[2],end_points[2]); } temp_p->u.c.a1 = fabs(end_arcs[2]); temp_p->u.c.center = end_centers[2]; coOrd rp0,rp1; Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius); Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1, temp_p->u.c.radius); LOG( log_cornuturnoutdesigner, 1, ( "ctoDes2: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n", \ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x, temp_p->u.c.center.y, \ points[2].x,points[2].y,end_points[2].x,end_points[2].y, \ rp0.x,rp0.y,rp1.x,rp1.y) ); } RightEndSeg = cornuSegs_da.cnt+LeftEndSeg; /*Add Third Part to tempSegs Array */ AppendSegs(&tempSegs_da,&cornuSegs_da); /* Safety - clear out cornu Array */ ClearSegs(&cornuSegs_da); if (tempSegs_da.cnt >128 ) { NoticeMessage( MSG_TODSGN_CORNU_TOO_COMPLEX, _("Ok"), NULL ); return NULL; } /* Generate Paths */ static char pathChar[512]; if (dp->type == NTO_CORNU3WAY) { strcpy(pathChar,"Normal"); /* Also resets array */ pathLen = (wIndex_t)strlen(pathChar)+1; for (uint8_t i=0; itype == NTO_CORNU3WAY) && !LH_first && (newTurnToeR != newTurnToeL)) { for (uint8_t i=Toe1Seg; itype == NTO_CORNU3WAY) && LH_first && (newTurnToeR != newTurnToeL)) { for (uint8_t i=Toe1Seg; ipaths = (signed char *)pathChar; segCnt = tempSegs_da.cnt; break; #endif case NTO_D_SLIP: case NTO_S_SLIP: case NTO_CROSSING: if (dp->type == NTO_D_SLIP) { if (newTurnSlipMode == 1) { pp = &DoubleSlipSchema2; } else { pp = &DoubleSlipSchema; } } TempEndPtsSet( 4 ); points[0].x = points[0].y = points[1].y = 0.0; points[1].x = (newTurnLen0); pos.y = 0; pos.x = (newTurnLen0)/2.0; coOrd cpos = pos; Translate( &points[3], pos, 90.0+angle0, (newTurnLen1)/2.0 ); points[2].y = - points[3].y; points[2].x = pos.x-(points[3].x-pos.x); if (dp->type != NTO_CROSSING) { Translate( &pos, points[3], 90.0+angle0, -newTurnTrackGauge ); if (!ComputeCurve( &points[4], &points[5], &radii[0], pos.x, fabs(pos.y), angle0 )) { /*???*/ return NULL; } radii[1] = - radii[0]; points[5].y = - points[5].y; points[6].y = 0; points[6].x = cpos.x-(points[4].x-cpos.x); points[7].y = -points[5].y; points[7].x = cpos.x-(points[5].x-cpos.x); } SetEndPt( TempEndPt(0), points[0], 270.0 ); SetEndPt( TempEndPt(1), points[1], 90.0 ); SetEndPt( TempEndPt(2), points[2], 270.0+angle0 ); SetEndPt( TempEndPt(3), points[3], 90.0+angle0 ); break; case NTO_R_CROSSOVER: case NTO_L_CROSSOVER: case NTO_D_CROSSOVER: TempEndPtsSet( 4 ); d = (newTurnLen0)/2.0 - newTurnTrackGauge; if (d < 0.0) { NoticeMessage( MSG_TODSGN_CROSSOVER_TOO_SHORT, _("Ok"), NULL ); return NULL; } angle0 = R2D( atan2( fabs(newTurnOff0), d ) ); points[0].y = 0.0; points[0].x = 0.0; points[1].y = 0.0; points[1].x = (newTurnLen0); points[2].y = fabs(newTurnOff0); points[2].x = 0.0; points[3].y = fabs(newTurnOff0); points[3].x = (newTurnLen0); if (!ComputeCurve( &points[4], &points[5], &radii[1], (newTurnLen0)/2.0, fabs(newTurnOff0)/2.0, angle0 ) ) { return NULL; } radii[0] = - radii[1]; points[6].y = 0.0; points[6].x = (newTurnLen0)-points[4].x; points[7].y = points[5].y; points[7].x = (newTurnLen0)-points[5].x; points[8].y = fabs(newTurnOff0); points[8].x = points[4].x; points[9].y = fabs(newTurnOff0)-points[5].y; points[9].x = points[5].x; points[10].y = fabs(newTurnOff0); points[10].x = points[6].x; points[11].y = points[9].y; points[11].x = points[7].x; SetEndPt( TempEndPt(0), points[0], 270.0 ); SetEndPt( TempEndPt(1), points[1], 90.0 ); SetEndPt( TempEndPt(2), points[2], 270.0 ); SetEndPt( TempEndPt(3), points[3], 90.0 ); break; case NTO_STR_SECTION: TempEndPtsSet( 2 ); points[0].y = points[0].x = 0; points[1].y = 0/*(newTurnOff1)*/; points[1].x = (newTurnLen0); SetEndPt( TempEndPt(0), points[0], 270.0 ); SetEndPt( TempEndPt(1), points[1], 90.0 ); break; case NTO_CRV_SECTION: TempEndPtsSet( 2 ); points[0].y = points[0].x = 0; points[1].y = (newTurnLen0) * (1.0 - cos( D2R(angle0) ) ); points[1].x = (newTurnLen0) * sin( D2R(angle0) ); radii[0] = -(newTurnLen0); SetEndPt( TempEndPt(0), points[0], 270.0 ); SetEndPt( TempEndPt(1), points[1], 90.0-angle0 ); break; case NTO_BUMPER: TempEndPtsSet( 1 ); points[0].y = points[0].x = 0; points[1].y = 0/*(newTurnOff1)*/; points[1].x = (newTurnLen0); SetEndPt( TempEndPt(0), points[0], 270.0 ); break; default: ; } } else { switch (dp->type) { case NTO_CURVED: d = points[3].x - points[5].x; if ( d < -MIN_TRACK_LENGTH ) { pp = &Crv3Schema; } else if ( d > MIN_TRACK_LENGTH ) { pp = &Crv2Schema; } else { pp = &Crv1Schema; } break; } } #ifndef MKTURNOUT if(dp->type == NTO_CORNU) { DIST_T end_length = MIN_TRACK_LENGTH; // Adjust end_points to impose small fixed end segments for (int i=0; i<3; i++) { if (radii[i] == 0.0) { Translate(&end_points[i], points[i], 90-angles[i]+(i==0?0:180), end_length); end_angles[i] = angles[i]; } else { Translate(&end_centers[i], points[i], -angles[i], radii[i]); end_arcs[i] = (radii[i]>=0?1:-1)*R2D(end_length/fabs(radii[i])); end_points[i] = points[i]; Rotate(&end_points[i],end_centers[i],(i>0?1:-1)*end_arcs[i]); end_angles[i] = angles[i]-(i>0?1:-1)*end_arcs[i]; } LOG( log_cornuturnoutdesigner, 1, ( "ctoDes0-%d: EP(%f,%f) NEP(%f,%f) EA(%f) NEA(%f) R(%f) ARC(%f) EC(%f,%f) \n", \ i+1,points[i].x,points[i].y,end_points[i].x,end_points[i].y,angles[i], end_angles[i],radii[i],end_arcs[i], \ end_centers[i].x,end_centers[i].y) ); } cornuData.pos[0] = end_points[0]; /*Start*/ cornuData.pos[1] = end_points[2]; /*Outer*/ cornuData.pos[3] = end_points[2]; /*Outer for second time*/ cornuData.pos[5] = end_points[1]; /*Inner*/ if (radii[0] == 0.0) { /* Toe */ cornuData.center[0] = zero; } else { cornuData.center[0].x = end_points[0].x; cornuData.center[0].y = end_points[0].y + radii[0]; } if (radii[1] == 0.0) { /* Inner */ cornuData.center[5] = zero; } else { Translate(&cornuData.center[5], cornuData.pos[5], -end_angles[1], radii[1]); } if (radii[2] == 0.0) { /* Outer */ cornuData.center[1] = zero; } else { Translate(&cornuData.center[1], cornuData.pos[1], -end_angles[2], radii[2]); } cornuData.center[3] = cornuData.center[1]; cornuData.angle[0] = 270.0; cornuData.angle[1] = 90.0-end_angles[2]; cornuData.angle[3] = 90.0-end_angles[2]; cornuData.angle[5] = 90.0-end_angles[1]; /*Inner*/ cornuData.radius[0] = fabs(radii[0]); cornuData.radius[1] = fabs(radii[2]); cornuData.radius[3] = fabs(radii[2]); cornuData.radius[5] = fabs(radii[1]); /*Inner*/ DYNARR_RESET( trkSeg_t, tempSegs_da ); /*Map out the full outer curve */ CallCornu0(&cornuData.pos[0],&cornuData.center[0],&cornuData.angle[0], &cornuData.radius[0],&tempSegs_da, FALSE); /*Get ToeAngle/Radius/Center */ int inx,subSeg; wBool_t back, neg; DIST_T radius = 0.0; coOrd center; pos.x = end_points[0].x+newTurnToeL-MIN_TRACK_LENGTH; pos.y = end_points[0].y; /* This will be close to but not on the curve */ ANGLE_T angle = GetAngleSegs(tempSegs_da.cnt,&tempSegs(0),&pos, &inx,NULL,&back,&subSeg,&neg); segPtr = &DYNARR_N(trkSeg_t, tempSegs_da, inx); if (segPtr->type == SEG_BEZTRK) { segPtr = &DYNARR_N(trkSeg_t,segPtr->bezSegs,subSeg); } if (segPtr->type == SEG_STRTRK) { radius = 0.0; center = zero; } else if (segPtr->type == SEG_CRVTRK) { center = segPtr->u.c.center; radius = fabs(segPtr->u.c.radius); } cornuData.pos[1] = pos; cornuData.center[1] = center; cornuData.angle[1] = angle; cornuData.radius[1] = radius; cornuData.pos[2] = pos; cornuData.center[2] = center; cornuData.angle[2] = NormalizeAngle(180.0+angle); cornuData.radius[2] = radius; cornuData.pos[4] = pos; cornuData.center[4] = center; cornuData.angle[4] = NormalizeAngle(180.0+angle); cornuData.radius[4] = radius; static dynArr_t cornuSegs_da; ClearSegs(&tempSegs_da); ClearSegs(&cornuSegs_da); /* Override if at zero radius at base don't compute end */ if (cornuData.radius[0] == 0.0) { DYNARR_APPEND(trkSeg_t,tempSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = zero; temp_p->u.l.pos[1] = cornuData.pos[1]; LOG( log_cornuturnoutdesigner, 1, ( "ctoDes1: P0(%f,%f) P1(%f,%f) \n", \ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x, temp_p->u.l.pos[1].y ) ); } else { DYNARR_APPEND(trkSeg_t,tempSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,tempSegs_da); temp_p->type = SEG_CRVTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.c.radius = -radii[0]; if (radii[0]>0.0) { temp_p->u.c.a0 = FindAngle(end_centers[0],end_points[0]); } else { temp_p->u.c.a0 = FindAngle(end_centers[0],points[0]); } temp_p->u.c.a1 = fabs(end_arcs[0]); temp_p->u.c.center = end_centers[0]; coOrd rp0,rp1; Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius); Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1, temp_p->u.c.radius); LOG( log_cornuturnoutdesigner, 1, ( "ctoDes1: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f), EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n", \ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x, temp_p->u.c.center.y, \ points[0].x,points[0].y,end_points[0].x,end_points[0].y, \ rp0.x,rp0.y,rp1.x,rp1.y) ); /* Base to Toe in tempSegs array */ CallCornuNoBez(&cornuData.pos[0],&cornuData.center[0],& cornuData.angle[0], &cornuData.radius[0],&tempSegs_da); } int ToeSeg = tempSegs_da.cnt; /* Toe to Outer in cornuSegs array */ CallCornuNoBez(&cornuData.pos[2],&cornuData.center[2],&cornuData.angle[2], &cornuData.radius[2],&cornuSegs_da); if (cornuData.radius[3] == 0.0) { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = cornuData.pos[3]; temp_p->u.l.pos[1] = end_points[2]; LOG( log_cornuturnoutdesigner, 1, ( "ctoDes2: P0(%f,%f) P1(%f,%f) \n", \ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x, temp_p->u.l.pos[1].y ) ); } else { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_CRVTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.c.radius = -radii[2]; if (radii[2]>0) { temp_p->u.c.a0 = FindAngle(end_centers[2],points[2]); } else { temp_p->u.c.a0 = FindAngle(end_centers[2],end_points[2]); } temp_p->u.c.a1 = fabs(end_arcs[2]); temp_p->u.c.center = end_centers[2]; coOrd rp0,rp1; Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius); Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1, temp_p->u.c.radius); LOG( log_cornuturnoutdesigner, 1, ( "ctoDes2: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n", \ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x, temp_p->u.c.center.y, \ points[2].x,points[2].y,end_points[2].x,end_points[2].y, \ rp0.x,rp0.y,rp1.x,rp1.y) ); } int OuterEndSeg = cornuSegs_da.cnt + ToeSeg; /* Add to second cornu to tempSegs array */ AppendSegs(&tempSegs_da,&cornuSegs_da); /* Get ready to reuse cornuSegs array*/ ClearSegs(&cornuSegs_da); /* Toe to Inner in cornuSegs array*/ CallCornuNoBez(&cornuData.pos[4],&cornuData.center[4],&cornuData.angle[4], &cornuData.radius[4],&cornuSegs_da); if (cornuData.radius[5] == 0.0) { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_STRTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.l.pos[0] = cornuData.pos[5]; temp_p->u.l.pos[1] = points[1]; LOG( log_cornuturnoutdesigner, 1, ( "ctoDes3: P0(%f,%f) P1(%f,%f) \n", \ temp_p->u.l.pos[0].x,temp_p->u.l.pos[0].y,temp_p->u.l.pos[1].x, temp_p->u.l.pos[1].y ) ); } else { DYNARR_APPEND(trkSeg_t,cornuSegs_da,1); trkSeg_p temp_p = &DYNARR_LAST(trkSeg_t,cornuSegs_da); temp_p->type = SEG_CRVTRK; temp_p->color = wDrawColorBlack; temp_p->lineWidth = 0.0; temp_p->u.c.radius = -radii[1]; if (radii[1]>0) { temp_p->u.c.a0 = FindAngle(end_centers[1],points[1]); } else { temp_p->u.c.a0 = FindAngle(end_centers[1],end_points[1]); } temp_p->u.c.a1 = fabs(end_arcs[1]); temp_p->u.c.center = end_centers[1]; coOrd rp0,rp1; Translate(&rp0,temp_p->u.c.center,temp_p->u.c.a0,temp_p->u.c.radius); Translate(&rp1,temp_p->u.c.center,temp_p->u.c.a0+temp_p->u.c.a1, temp_p->u.c.radius); LOG( log_cornuturnoutdesigner, 1, ( "ctoDes3: R(%f) A0(%f) A1(%f) C(%f,%f) P(%f,%f) EP(%f,%f) RP0(%f,%f) RP1(%f,%f)\n", \ temp_p->u.c.radius,temp_p->u.c.a0,temp_p->u.c.a1,temp_p->u.c.center.x, temp_p->u.c.center.y, \ points[1].x,points[1].y,end_points[1].x,end_points[1].y, \ rp0.x,rp0.y,rp1.x,rp1.y) ); } int InnerEndSeg = cornuSegs_da.cnt + OuterEndSeg; /*Add Third Part to tempSegs Array */ AppendSegs(&tempSegs_da,&cornuSegs_da); /* Safety - clear out cornu Array */ ClearSegs(&cornuSegs_da); if (tempSegs_da.cnt >128 ) { NoticeMessage( MSG_TODSGN_CORNU_TOO_COMPLEX, _("Ok"), NULL ); return NULL; } static char pathChar[512]; strcpy(pathChar,"Normal"); /* Also resets array */ pathLen = (wIndex_t)strlen(pathChar)+1; for (uint8_t i=0; ipaths = (signed char *)pathChar; segCnt = tempSegs_da.cnt; } #endif if (!( (dp->type== NTO_CORNU) || (dp->type == NTO_CORNUWYE) || (dp->type == NTO_CORNU3WAY))) { segOrder = pp->segOrder; segCnt = (wIndex_t)strlen( segOrder ); CHECKMSG( segCnt%3 == 0, ( "%s", dp->label ) ); segCnt /= 3; DYNARR_SET( trkSeg_t, tempSegs_da, segCnt ); memset( &tempSegs(0), 0, segCnt * sizeof tempSegs(0) ); for ( s=0; scolor = wDrawColorBlack; if (*segOrder <= '9') { p0 = *segOrder++ - '0'; } else { p0 = *segOrder++ - 'A' + 10; } if (*segOrder <= '9') { p1 = *segOrder++ - '0'; } else { p1 = *segOrder++ - 'A' + 10; } p = *segOrder++ - '0'; if (p == 3) { /* cornu */ } else if (p != 0) { segPtr->type = SEG_CRVTRK; ComputeCurvedSeg( segPtr, radii[p-1], points[p0], points[p1] ); } else { segPtr->type = SEG_STRTRK; segPtr->u.l.pos[0] = points[p0]; segPtr->u.l.pos[1] = points[p1]; } } } AddRoadbed(); #ifndef MKTURNOUT if ( CheckPaths( segCnt, &tempSegs(0), pp->paths, dp->label ) < 0 ) { return NULL; } #endif return pp; } #ifndef MKTURNOUT static void CopyNonTracks( turnoutInfo_t * to ) { trkSeg_p sp0; for ( sp0=to->segs; sp0<&to->segs[to->segCnt]; sp0++ ) { if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK && sp0->type != SEG_BEZTRK ) { DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 ); tempSegs(tempSegs_da.cnt-1) = *sp0; } } } static void NewTurnPrint( void * junk ) { coOrd pos, p0, p1; WDOUBLE_T px, py; int i, j, ii, jj, p; EPINX_T ep; wFont_p fp; coOrd orig, size; toDesignSchema_t * pp; POS_T tmp; FLOAT_T tmpR; static drawCmd_t newTurnout_d = { NULL, &printDrawFuncs, DC_PRINT, 1.0, 0.0, { 0.0, 0.0 }, { 0.0, 0.0 }, Pix2CoOrd, CoOrd2Pix }; if ((pp=LoadSegs( curDesign, TRUE )) == NULL) { return; } if (includeNontrackSegments && customTurnout1) { CopyNonTracks( customTurnout1 ); } GetSegBounds( zero, 0.0, tempSegs_da.cnt, &tempSegs(0), &orig, &size ); tmp = orig.x; orig.x = orig.y; orig.y = tmp; #ifdef LATER size.x = 0.0; size.y = 0.0; orig.x = 0.0; orig.y = 0.0; for ( i=0; itype) { case SEG_STRLIN: case SEG_STRTRK: pos[0] = segPtr->u.l.pos[0]; pos[1] = segPtr->u.l.pos[1]; break; case SEG_CRVTRK: case SEG_CRVLIN: PointOnCircle( &pos[0], segPtr->u.c.center, segPtr->u.c.radius, segPtr->u.c.a0 ); PointOnCircle( &pos[1], segPtr->u.c.center, segPtr->u.c.radius, segPtr->u.c.a0+segPtr->u.c.a1 ); } for ( ep=0; ep<2; ep++ ) { if (pos[ep].x < orig.x) { orig.x = pos[ep].x; } if (pos[ep].x > size.x) { size.x = pos[ep].x; } if (pos[ep].y < orig.y) { orig.y = pos[ep].y; } if (pos[ep].y > size.y) { size.y = pos[ep].y; } } } size.x -= orig.x; size.y -= orig.y; #endif fp = wStandardFont( F_TIMES, FALSE, FALSE ); wPrintGetPageSize( &px, &py ); newTurnout_d.size.x = px; newTurnout_d.size.y = py; ii = (int)(size.y/newTurnout_d.size.x)+1; jj = (int)(size.x/newTurnout_d.size.y)+1; if ( !wPrintDocStart( sTurnoutDesignerW, ii*jj, NULL ) ) { return; } #ifdef LATER orig.x -= (0.5); orig.y -= (jj*newTurnout_d.size.y-size.y)/2.0; #endif orig.x = - ( size.y + orig.x + newTurnTrackGauge/2.0 + 0.5 ); orig.y -= (0.5); coOrd strPos; for ( i=0, newTurnout_d.orig.x=orig.x; ilabel) ); strPos.y -= 0.5; DrawString( &newTurnout_d, strPos, 0.0, message, fp, 20, wDrawColorBlack ); sprintf( message, _("%s %d x %d (of %d x %d)"), _("Page"), i+1, j+1, ii, jj ); strPos.y -= 0.5; DrawString( &newTurnout_d, strPos, 0.0, message, fp, 20, wDrawColorBlack ); strPos.y -= 0.10; for ( p=0; pfloatCnt; p++ ) { tmpR = *(FLOAT_T*)(turnDesignPLs[curDesign->floats[p].index].valueP); sprintf( message, "%s: %s", (curDesign->floats[p].mode!=Frog_e ||newTurnAngleMode!=0)?_(curDesign->floats[p].printLabel):_("Frog Number"), curDesign->floats[p].mode==Dim_e? FormatDistance(tmpR): FormatFloat(tmpR) ); strPos.y -= 0.25; DrawString( &newTurnout_d, strPos, 0.0, message, fp, 16, wDrawColorBlack ); } if (newTurnLeftDesc[0] || newTurnLeftPartno[0]) { sprintf( message, "%s %s %s", newTurnManufacturer, newTurnLeftPartno, newTurnLeftDesc ); strPos.y -= 0.25; DrawString( &newTurnout_d, strPos, 0.0, message, fp, 16, wDrawColorBlack ); } if (newTurnRightDesc[0] || newTurnRightPartno[0]) { sprintf( message, "%s %s %s", newTurnManufacturer, newTurnRightPartno, newTurnRightDesc ); strPos.y -= 0.25; DrawString( &newTurnout_d, strPos, 0.0, message, fp, 16, wDrawColorBlack ); } DrawRectangle( &newTurnout_d, newTurnout_d.orig, newTurnout_d.size, wDrawColorBlack, DRAW_CLOSED ); DrawSegsDA( &newTurnout_d, NULL, zero, 270.0, &tempSegs_da, newTurnTrackGauge, wDrawColorBlack, 0 ); for ( ep=0; epstrCnt >= 1 && newTurnLeftDesc[0] == 0) || // (curDesign->strCnt >= 2 && newTurnRightDesc[0] == 0) ) { // NoticeMessage( MSG_TODSGN_DESC_NONBLANK, _("Ok"), NULL ); // return; // } BuildTrimedTitle( message, "\t", newTurnManufacturer, newTurnLeftDesc, newTurnLeftPartno ); #ifndef MKTURNOUT if ( customTurnout1 == NULL && ( foundR || FindCompound( FIND_TURNOUT, newTurnScaleName, message ) ) ) { if ( !NoticeMessage( MSG_TODSGN_REPLACE, _("Yes"), _("No") ) ) { return; } } SetCLocale(); #endif f = OpenCustom("a"); sprintf( tempCustom, "\"%s\" \"%s\" \"", curDesign->label, "" ); cp = tempCustom + strlen(tempCustom); cp = Strcpytrimed( cp, newTurnManufacturer, TRUE ); strcpy( cp, "\" \"" ); cp += 3; cp = Strcpytrimed( cp, newTurnLeftDesc, TRUE ); strcpy( cp, "\" \"" ); cp += 3; cp = Strcpytrimed( cp, newTurnLeftPartno, TRUE ); strcpy( cp, "\"" ); cp += 1; if (curDesign->type == NTO_REGULAR || curDesign->type == NTO_CURVED || curDesign->type == NTO_CORNU ) { strcpy( cp, " \"" ); cp += 2; cp = Strcpytrimed( cp, newTurnRightDesc, TRUE ); strcpy( cp, "\" \"" ); cp += 3; cp = Strcpytrimed( cp, newTurnRightPartno, TRUE ); strcpy( cp, "\"" ); cp += 1; } CHECK( cp-tempCustom <= sizeof tempCustom ); for ( i=0; ifloatCnt; i++ ) { flt = *(FLOAT_T*)(turnDesignPLs[curDesign->floats[i].index].valueP); switch( curDesign->floats[i].mode ) { case Dim_e: flt = ( flt ); break; case Frog_e: if (newTurnAngleMode == 0 && flt > 0.0) { flt = R2D(asin(1.0/flt)); } break; case Angle_e: break; case Rad_e: break; } sprintf( cp, " %0.6f", flt ); cp += strlen(cp); } sprintf( cp, " %0.6f %0.6f %ld", newTurnRoadbedWidth, newTurnRoadbedLineWidth, wDrawGetRGB(newTurnRoadbedColor) ); customInfoP = MyStrdup( tempCustom ); strcpy( tempCustom, message ); long options = 0; if ( curDesign->type == NTO_D_SLIP && newTurnSlipMode == 1) { options |= COMPOUND_OPTION_PATH_NOCOMBINE; } #ifndef MKTURNOUT if (includeNontrackSegments && customTurnout1) { CopyNonTracks( customTurnout1 ); } if ( customTurnout1 ) { customTurnout1->segCnt = 0; } // DIST_T * radii_ends = NULL; if ((curDesign->type == NTO_CORNU) || (curDesign->type == NTO_CORNUWYE) || (curDesign->type == NTO_CORNU3WAY)) { // radii_ends = &radii[0]; } to = CreateNewTurnout( newTurnScaleName, tempCustom, tempSegs_da.cnt, &tempSegs(0), pp->paths, TempEndPtsCount(), TempEndPt(0), FALSE, options ); to->customInfo = customInfoP; #endif if (f) { fprintf( f, "TURNOUT %s \"%s\" %ld\n", newTurnScaleName, PutTitle(tempCustom), options ); #ifdef MKTURNOUT if (doCustomInfoLine) #endif fprintf( f, "\tU %s\n", customInfoP ); WriteCompoundPathsEndPtsSegs( f, pp->paths, tempSegs_da.cnt, &tempSegs(0), TempEndPtsCount(), TempEndPt(0) ); } switch (curDesign->type) { case NTO_REGULAR: points[2].y = - points[2].y; points[3].y = - points[3].y; points[4].y = - points[4].y; radii[0] = - radii[0]; LoadSegs( curDesign, FALSE ); pos = GetEndPtPos(TempEndPt(2)); angle = GetEndPtAngle(TempEndPt(2)); pos.y = - pos.y; angle = 180.0 - angle; SetEndPt(TempEndPt(2), pos, angle ); BuildTrimedTitle( tempCustom, "\t", newTurnManufacturer, newTurnRightDesc, newTurnRightPartno ); #ifndef MKTURNOUT if (includeNontrackSegments && customTurnout2) { CopyNonTracks( customTurnout2 ); } if ( customTurnout2 ) { customTurnout2->segCnt = 0; } to = CreateNewTurnout( newTurnScaleName, tempCustom, tempSegs_da.cnt, &tempSegs(0), pp->paths, TempEndPtsCount(), TempEndPt(0), FALSE, options ); to->customInfo = customInfoP; #endif if (f) { fprintf( f, "TURNOUT %s \"%s\" %ld\n", newTurnScaleName, PutTitle(tempCustom), options ); #ifdef MKTURNOUT if (doCustomInfoLine) #endif fprintf( f, "\tU %s\n", customInfoP ); WriteCompoundPathsEndPtsSegs( f, pp->paths, tempSegs_da.cnt, &tempSegs(0), TempEndPtsCount(), TempEndPt(0) ); } break; case NTO_CURVED: case NTO_CORNU: points[2].y = - points[2].y; points[1].y = - points[1].y; points[3].y = - points[3].y; points[4].y = - points[4].y; points[5].y = - points[5].y; points[6].y = - points[6].y; radii[0] = -radii[0]; radii[1] = -radii[1]; radii[2] = -radii[2]; radii[3] = -radii[3]; radii[4] = -radii[4]; radii[5] = -radii[5]; radii[6] = -radii[6]; angles[0] = -angles[0]; angles[1] = -angles[1]; angles[2] = -angles[2]; angles[3] = -angles[3]; angles[4] = -angles[4]; angles[5] = -angles[5]; angles[6] = -angles[6]; LoadSegs( curDesign, FALSE ); pos = GetEndPtPos(TempEndPt(1)); angle = GetEndPtAngle(TempEndPt(1)); pos.y = - pos.y; angle = 180.0 - angle; SetEndPt( TempEndPt(1), pos, angle ); pos = GetEndPtPos(TempEndPt(2)); angle = GetEndPtAngle(TempEndPt(2)); pos.y = - pos.y; angle = 180.0 - angle; SetEndPt( TempEndPt(2), pos, angle ); BuildTrimedTitle( tempCustom, "\t", newTurnManufacturer, newTurnRightDesc, newTurnRightPartno ); #ifndef MKTURNOUT if (includeNontrackSegments && customTurnout2) { CopyNonTracks( customTurnout2 ); } if ( customTurnout2 ) { customTurnout2->segCnt = 0; } to = CreateNewTurnout( newTurnScaleName, tempCustom, tempSegs_da.cnt, &tempSegs(0), pp->paths, TempEndPtsCount(), TempEndPt(0), FALSE, options ); to->customInfo = customInfoP; #endif if (f) { fprintf( f, "TURNOUT %s \"%s\" %ld\n", newTurnScaleName, PutTitle(tempCustom), options ); #ifdef MKTURNOUT if (doCustomInfoLine) #endif fprintf( f, "\tU %s\n", customInfoP ); WriteCompoundPathsEndPtsSegs( f, pp->paths, tempSegs_da.cnt, &tempSegs(0), TempEndPtsCount(), TempEndPt(0) ); } break; default: ; } tempCustom[0] = '\0'; #ifndef MKTURNOUT if (f) { fclose(f); } SetUserLocale(); includeNontrackSegments = TRUE; wHide( newTurnW ); DoChangeNotification( CHANGE_PARAMS ); #endif } #ifndef MKTURNOUT static void NewTurnCancel( wWin_p win ) { wHide( newTurnW ); includeNontrackSegments = TRUE; } static wWinPix_t turnDesignWidth; static wWinPix_t turnDesignHeight; static void TurnDesignLayout( paramData_t * pd, int index, wWinPix_t colX, wWinPix_t * w, wWinPix_t * h ) { wIndex_t inx; if ( curDesign == NULL ) { return; } if ( index >= I_TO_FIRST_FLOAT && index <= I_TO_LAST_FLOAT ) { for ( inx=0; inxfloatCnt; inx++ ) { if ( index == curDesign->floats[inx].index ) { *w = curDesign->floats[inx].pos.x; *h = curDesign->floats[inx].pos.y; return; } } CHECKMSG( FALSE, ( "turnDesignLayout: bad index = %d", index ) ); } else if ( index == I_TOMANUF ) { *h = turnDesignHeight + 10; } } static void SetupTurnoutDesignerW( toDesignDesc_t * newDesign ) { static wWinPix_t partnoWidth; int inx; wWinPix_t w, h, ctlH; if ( newTurnW == NULL ) { partnoWidth = wLabelWidth( "999-99999-9999" ); turnDesignPLs[I_TOLDESC+1].winData = turnDesignPLs[I_TORDESC+1].winData = I2VP(partnoWidth); partnoWidth += wLabelWidth( " # " ); newTurnW = ParamCreateDialog( &turnDesignPG, _("Turnout Designer"), _("Print"), NewTurnPrint, NewTurnCancel, TRUE, TurnDesignLayout, F_BLOCK, NULL ); for ( inx=0; inxlineC = wLineCreate( turnDesignPG.win, NULL, designDescs[inx]->lineCnt, designDescs[inx]->lines ); wControlShow( (wControl_p)designDescs[inx]->lineC, FALSE ); } } if ( curDesign != newDesign ) { if ( curDesign ) { wControlShow( (wControl_p)curDesign->lineC, FALSE ); } curDesign = newDesign; sprintf( message, _("%s %s Designer"), sProdName, _(curDesign->label) ); wWinSetTitle( newTurnW, message ); for ( inx=I_TO_FIRST_FLOAT; inx<=I_TO_LAST_FLOAT; inx++ ) { turnDesignPLs[inx].option |= PDO_DLGIGNORE; wControlShow( turnDesignPLs[inx].control, FALSE ); } for ( inx=0; inxfloatCnt; inx++ ) { turnDesignPLs[curDesign->floats[inx].index].option &= ~PDO_DLGIGNORE; wControlSetLabel( turnDesignPLs[curDesign->floats[inx].index].control, _(curDesign->floats[inx].winLabel) ); wControlShow( turnDesignPLs[curDesign->floats[inx].index].control, TRUE ); } wControlShow( turnDesignPLs[I_TORDESC+0].control, curDesign->strCnt>1 ); wControlShow( turnDesignPLs[I_TORDESC+1].control, curDesign->strCnt>1 ); wControlShow( (wControl_p)curDesign->lineC, TRUE ); turnDesignWidth = turnDesignHeight = 0; for (inx=0; inxlineCnt; inx++) { if (curDesign->lines[inx].x0 > turnDesignWidth) { turnDesignWidth = curDesign->lines[inx].x0; } if (curDesign->lines[inx].x1 > turnDesignWidth) { turnDesignWidth = curDesign->lines[inx].x1; } if (curDesign->lines[inx].y0 > turnDesignHeight) { turnDesignHeight = curDesign->lines[inx].y0; } if (curDesign->lines[inx].y1 > turnDesignHeight) { turnDesignHeight = curDesign->lines[inx].y1; } } ctlH = wControlGetHeight( turnDesignPLs[I_TO_FIRST_FLOAT].control ); for ( inx=0; inxfloatCnt; inx++ ) { w = curDesign->floats[inx].pos.x + 80; h = curDesign->floats[inx].pos.y + ctlH; if (turnDesignWidth < w) { turnDesignWidth = w; } if (turnDesignHeight < h) { turnDesignHeight = h; } } if ( curDesign->strCnt > 1 ) { w = wLabelWidth( _("Right Description") ); wControlSetLabel( turnDesignPLs[I_TOLDESC].control, _("Left Description") ); turnDesignPLs[I_TOLDESC].winLabel = N_("Left Description"); turnDesignPLs[I_TORDESC+0].option &= ~PDO_DLGIGNORE; turnDesignPLs[I_TORDESC+1].option &= ~PDO_DLGIGNORE; } else { w = wLabelWidth( _("Manufacturer") ); wControlSetLabel( turnDesignPLs[I_TOLDESC].control, _("Description") ); turnDesignPLs[I_TOLDESC].winLabel = N_("Description"); turnDesignPLs[I_TORDESC+0].option |= PDO_DLGIGNORE; turnDesignPLs[I_TORDESC+1].option |= PDO_DLGIGNORE; } if ( curDesign->angleModeCnt > 0 ) { turnDesignPLs[I_TOANGMODE].option &= ~PDO_DLGIGNORE; wControlShow( turnDesignPLs[I_TOANGMODE].control, TRUE ); } else { turnDesignPLs[I_TOANGMODE].option |= PDO_DLGIGNORE; wControlShow( turnDesignPLs[I_TOANGMODE].control, FALSE ); } if (curDesign->type == NTO_D_SLIP) { turnDesignPLs[I_TOSLIPMODE].option &= ~PDO_DLGIGNORE; wControlShow( turnDesignPLs[I_TOSLIPMODE].control, TRUE ); } else { turnDesignPLs[I_TOSLIPMODE].option |= PDO_DLGIGNORE; wControlShow( turnDesignPLs[I_TOSLIPMODE].control, FALSE ); } w = turnDesignWidth-w; wStringSetWidth( (wString_p)turnDesignPLs[I_TOMANUF].control, w ); w -= partnoWidth; wStringSetWidth( (wString_p)turnDesignPLs[I_TOLDESC].control, w ); wStringSetWidth( (wString_p)turnDesignPLs[I_TORDESC].control, w ); if ( curDesign->type == NTO_CORNU || curDesign->type == NTO_CORNUWYE || curDesign->type == NTO_CORNU3WAY ) { turnDesignPLs[I_TOOFFSET+0].winData = turnDesignPLs[I_TOOFFSET+1].winData = turnDesignPLs[I_TOOFFSET+2].winData = turnDesignPLs[I_TOOFFSET+3].winData = &r_10000_10000; turnDesignPLs[I_TOANGLE+0].winData = turnDesignPLs[I_TOANGLE+1].winData = turnDesignPLs[I_TOANGLE+2].winData = turnDesignPLs[I_TOANGLE+3].winData = &r_90_90; } else { turnDesignPLs[I_TOOFFSET+0].winData = turnDesignPLs[I_TOOFFSET+1].winData = turnDesignPLs[I_TOOFFSET+2].winData = turnDesignPLs[I_TOOFFSET+3].winData = &r0d001_10000; turnDesignPLs[I_TOANGLE+0].winData = turnDesignPLs[I_TOANGLE+1].winData = turnDesignPLs[I_TOANGLE+2].winData = turnDesignPLs[I_TOANGLE+3].winData = &r0d001_90; } ParamLayoutDialog( &turnDesignPG ); } } static void ShowTurnoutDesigner( void * context ) { wBool_t sameTurnout = FALSE; if (recordF) { fprintf( recordF, TURNOUTDESIGNER " SHOW %s\n", ((toDesignDesc_t*)context)->label ); } newTurnScaleName = curScaleName; newTurnTrackGauge = trackGauge; if (context && (curDesign == context)) { sameTurnout = TRUE; } SetupTurnoutDesignerW( (toDesignDesc_t*)context ); if (!sameTurnout) { /* Clear Values unless same as last time */ newTurnRightDesc[0] = '\0'; newTurnRightPartno[0] = '\0'; newTurnLeftDesc[0] = '\0'; newTurnLeftPartno[0] = '\0'; newTurnOff0 = newTurnLen0 = newTurnAngle0 = newTurnRad0 = newTurnOff1 = newTurnLen1 = newTurnAngle1 = newTurnRad1 = newTurnOff2 = newTurnLen2 = newTurnAngle2 = newTurnRad2 = newTurnOff3 = newTurnLen3 = newTurnAngle3 = newTurnRad3 = newTurnToeL = newTurnToeR = 0.0; } ParamLoadControls( &turnDesignPG ); ParamGroupRecord( &turnDesignPG ); customTurnout1 = NULL; customTurnout2 = NULL; wShow( newTurnW ); } static BOOL_T NotClose( DIST_T d ) { return d < -0.001 || d > 0.001; } EXPORT void EditCustomTurnout( turnoutInfo_t * to, turnoutInfo_t * to1 ) { int i; toDesignDesc_t * dp; char * type, * name, *cp, *mfg, *descL, *partL, *descR, *partR; long rgb; trkSeg_p sp0, sp1; BOOL_T segsDiff; LWIDTH_T lineWidth; if ( ! GetArgs( to->customInfo, "qqqqqc", &type, &name, &mfg, &descL, &partL, &cp ) ) { return; } for ( i=0; ilabel ) == 0 ) { break; } } if ( i >= COUNT( designDescs ) ) { return; } SetupTurnoutDesignerW(dp); newTurnTrackGauge = GetScaleTrackGauge( to->scaleInx ); newTurnScaleName = GetScaleName( to->scaleInx ); strcpy( newTurnManufacturer, mfg ); strcpy( newTurnLeftDesc, descL ); strcpy( newTurnLeftPartno, partL ); if (dp->type == NTO_REGULAR || dp->type == NTO_CURVED || dp->type == NTO_CORNU) { if ( ! GetArgs( cp, "qqc", &descR, &partR, &cp )) { return; } strcpy( newTurnRightDesc, descR ); strcpy( newTurnRightPartno, partR ); } else { descR = partR = ""; } for ( i=0; ifloatCnt; i++ ) { if ( ! GetArgs( cp, "fc", turnDesignPLs[dp->floats[i].index].valueP, &cp ) ) { return; } switch (dp->floats[i].mode) { case Dim_e: /* *dp->floats[i].valueP = PutDim( *dp->floats[i].valueP ); */ break; case Frog_e: if (newTurnAngleMode == 0) { if ( *(FLOAT_T*)(turnDesignPLs[dp->floats[i].index].valueP) > 0.0 ) { *(FLOAT_T*)(turnDesignPLs[dp->floats[i].index].valueP) = 1.0/sin(D2R(* (FLOAT_T*)(turnDesignPLs[dp->floats[i].index].valueP))); } } break; case Angle_e: break; case Rad_e: break; } } rgb = 0; if ( cp && GetArgs( cp, "ffl", &newTurnRoadbedWidth, &lineWidth, &rgb ) ) { newTurnRoadbedColor = wDrawFindColor(rgb); newTurnRoadbedLineWidth = lineWidth; } else { newTurnRoadbedWidth = 0; newTurnRoadbedLineWidth = 0; newTurnRoadbedColor = wDrawColorBlack; } customTurnout1 = to; customTurnout2 = to1; segsDiff = FALSE; if ( to ) { LoadSegs( dp, TRUE ); segsDiff = FALSE; if ( to->segCnt == tempSegs_da.cnt ) { for ( sp0=to->segs,sp1=&tempSegs(0); (!segsDiff) && sp0<&to->segs[to->segCnt]; sp0++,sp1++ ) { switch (sp0->type) { case SEG_STRLIN: if (sp0->type != sp1->type || sp0->color != sp1->color || NotClose(sp0->lineWidth-lineWidth) || NotClose(sp0->u.l.pos[0].x-sp1->u.l.pos[0].x) || NotClose(sp0->u.l.pos[0].y-sp1->u.l.pos[0].y) || NotClose(sp0->u.l.pos[1].x-sp1->u.l.pos[1].x) || NotClose(sp0->u.l.pos[1].y-sp1->u.l.pos[1].y) ) { segsDiff = TRUE; } break; case SEG_CRVLIN: if (sp0->type != sp1->type || sp0->color != sp1->color || NotClose(sp0->lineWidth-lineWidth) || NotClose(sp0->u.c.center.x-sp1->u.c.center.x) || NotClose(sp0->u.c.center.y-sp1->u.c.center.y) || NotClose(sp0->u.c.radius-sp1->u.c.radius) || NotClose(sp0->u.c.a0-sp1->u.c.a0) || NotClose(sp0->u.c.a1-sp1->u.c.a1) ) { segsDiff = TRUE; } break; case SEG_STRTRK: case SEG_CRVTRK: case SEG_BEZTRK: break; default: segsDiff = TRUE; } } } else { for ( sp0=to->segs; (!segsDiff) && sp0<&to->segs[to->segCnt]; sp0++ ) { if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK && sp0->type != SEG_BEZTRK) { segsDiff = TRUE; } } } } if ( (!segsDiff) && to1 && (dp->type==NTO_REGULAR||dp->type==NTO_CURVED ||dp->type == NTO_CORNU) ) { if ( dp->type==NTO_REGULAR ) { points[2].y = - points[2].y; radii[0] = - radii[0]; } else if (dp->type == NTO_CURVED) { points[1].y = - points[1].y; points[2].y = - points[2].y; radii[0] = - radii[0]; radii[1] = - radii[1]; } else { points[2].y = - points[2].y; points[1].y = - points[1].y; angles[1] = -angles[1]; angles[2] = -angles[2]; radii[0] = - radii[0]; radii[1] = - radii[1]; } LoadSegs( dp, FALSE ); if ( dp->type==NTO_REGULAR ) { points[2].y = - points[2].y; radii[0] = - radii[0]; } else if (dp->type == NTO_CURVED) { points[1].y = - points[1].y; points[2].y = - points[2].y; radii[0] = - radii[0]; radii[1] = - radii[1]; } else { points[2].y = - points[2].y; points[1].y = - points[1].y; angles[1] = -angles[1]; angles[2] = -angles[2]; radii[0] = - radii[0]; radii[1] = - radii[1]; } segsDiff = FALSE; if ( to1->segCnt == tempSegs_da.cnt ) { for ( sp0=to1->segs,sp1=&tempSegs(0); (!segsDiff) && sp0<&to1->segs[to1->segCnt]; sp0++,sp1++ ) { switch (sp0->type) { case SEG_STRLIN: if (sp0->type != sp1->type || sp0->color != sp1->color || NotClose(sp0->lineWidth-lineWidth) || NotClose(sp0->u.l.pos[0].x-sp1->u.l.pos[0].x) || NotClose(sp0->u.l.pos[0].y-sp1->u.l.pos[0].y) || NotClose(sp0->u.l.pos[1].x-sp1->u.l.pos[1].x) || NotClose(sp0->u.l.pos[1].y-sp1->u.l.pos[1].y) ) { segsDiff = TRUE; } break; case SEG_CRVLIN: if (sp0->type != sp1->type || sp0->color != sp1->color || NotClose(sp0->lineWidth-lineWidth) || NotClose(sp0->u.c.center.x-sp1->u.c.center.x) || NotClose(sp0->u.c.center.y-sp1->u.c.center.y) || NotClose(sp0->u.c.radius-sp1->u.c.radius) || NotClose(sp0->u.c.a0-sp1->u.c.a0) || NotClose(sp0->u.c.a1-sp1->u.c.a1) ) { segsDiff = TRUE; } break; case SEG_STRTRK: case SEG_CRVTRK: case SEG_BEZTRK: break; default: segsDiff = TRUE; } } } else { for ( sp0=to1->segs; (!segsDiff) && sp0<&to1->segs[to1->segCnt]; sp0++ ) { if ( sp0->type != SEG_STRTRK && sp0->type != SEG_CRVTRK && sp0->type != SEG_BEZTRK) { segsDiff = TRUE; } } } } includeNontrackSegments = TRUE; if ( segsDiff ) { if ( NoticeMessage( MSG_SEGMENTS_DIFFER, _("Yes"), _("No") ) <= 0 ) { includeNontrackSegments = FALSE; } } else { includeNontrackSegments = FALSE; } /*if (recordF) fprintf( recordF, TURNOUTDESIGNER " SHOW %s\n", dp->label );*/ ParamLoadControls( &turnDesignPG ); ParamGroupRecord( &turnDesignPG ); wShow( newTurnW ); } EXPORT void InitNewTurn( wMenu_p m ) { int i; ParamRegister( &turnDesignPG ); for ( i=0; ilabel), 0, ShowTurnoutDesigner, designDescs[i] ); sprintf( message, "%s SHOW %s", TURNOUTDESIGNER, designDescs[i]->label ); AddPlaybackProc( message, (playbackProc_p)ShowTurnoutDesigner, designDescs[i] ); } newTurnRoadbedColor = wDrawColorBlack; includeNontrackSegments = TRUE; log_cornuturnoutdesigner = LogFindIndex( "cornuturnoutdesigner" ); } #endif #ifdef MKTURNOUT char message[STR_HUGE_SIZE]; char * curScaleName; double trackGauge; long units = 0; wDrawColor drawColorBlack; long newTurnRoadbedColorRGB = 0; EXPORT const char * AbortMessage( const char * sFormat, ... ) { static char sMessage[STR_SIZE]; if ( sFormat == NULL ) { return ""; } va_list ap; va_start(ap, sFormat); vsnprintf(sMessage, sizeof sMessage, sFormat, ap); va_end(ap); return sMessage; } EXPORT void AbortProg( const char * sCond, const char * sFileName, int iLineNumber, const char * sMsg ) { fprintf( stderr, "%s: %s:%d %s", sCond, sFileName, iLineNumber, sMsg ); abort(); } void * MyRealloc( void * ptr, size_t size ) { return realloc( ptr, size ); } EXPORT char * MyStrdup( const char * str ) { char * ret; ret = (char*)malloc( strlen( str ) + 1 ); strcpy( ret, str ); return ret; } EXPORT void LogPrintf( const char * format, ... ) { } int NoticeMessage( const char * msg, const char * yes, const char * no, ... ) { /*fprintf( stderr, "%s\n", msg );*/ return 0; } FILE * OpenCustom( char * mode) { return stdout; } void wPrintSetup( wPrintSetupCallBack_p notused ) { } EXPORT void ComputeCurvedSeg( trkSeg_p s, DIST_T radius, coOrd p0, coOrd p1 ) { DIST_T d; ANGLE_T a, aa, aaa; s->u.c.radius = radius; d = FindDistance( p0, p1 )/2.0; a = FindAngle( p0, p1 ); if (radius > 0) { aa = R2D(asin( d/radius )); aaa = a + (90.0 - aa); Translate( &s->u.c.center, p0, aaa, radius ); s->u.c.a0 = NormalizeAngle( aaa + 180.0 ); s->u.c.a1 = aa*2.0; } else { aa = R2D(asin( d/(-radius) )); aaa = a - (90.0 - aa); Translate( &s->u.c.center, p0, aaa, -radius ); s->u.c.a0 = NormalizeAngle( aaa + 180.0 - aa *2.0 ); s->u.c.a1 = aa*2.0; } } EXPORT char * Strcpytrimed( char * dst, const char * src, BOOL_T double_quotes ) { const char * cp; while (*src && isspace((unsigned char)*src) ) { src++; } if (!*src) { return dst; } cp = src+strlen(src)-1; while ( cp>src && isspace((unsigned char)*cp) ) { cp--; } while ( src<=cp ) { if (*src == '"' && double_quotes) { *dst++ = '"'; } *dst++ = *src++; } *dst = '\0'; return dst; } EXPORT char * PutTitle( char * cp ) { static char title[STR_SIZE]; char * tp = title; while (*cp) { if (*cp == '\"') { *tp++ = '\"'; *tp++ = '\"'; } else { *tp++ = *cp; } cp++; } *tp = '\0'; return title; } long wDrawGetRGB( wDrawColor color ) { return newTurnRoadbedColorRGB; } EXPORT BOOL_T WriteSegs( FILE * f, wIndex_t segCnt, trkSeg_p segs ) { int i, j; BOOL_T rc = TRUE; for ( i=0; i0; break; case SEG_CRVTRK: case SEG_CRVLIN: rc &= fprintf( f, "\t%c %ld %0.6f %0.6f %0.6f %0.6f %0.6f %0.6f\n", segs[i].type, (segs[i].type==SEG_CRVTRK?0:newTurnRoadbedColorRGB), segs[i].lineWidth, fabs(segs[i].u.c.radius), segs[i].u.c.center.x, segs[i].u.c.center.y, segs[i].u.c.a0, segs[i].u.c.a1 )>0; break; case SEG_FILCRCL: rc &= fprintf( f, "\t%c %ld %0.6f %0.6f %0.6f %0.6f\n", segs[i].type, newTurnRoadbedColorRGB, segs[i].lineWidth, fabs(segs[i].u.c.radius), segs[i].u.c.center.x, segs[i].u.c.center.y )>0; break; case SEG_POLY: case SEG_FILPOLY: rc &= fprintf( f, "\t%c %ld %0.6f %d\n", segs[i].type, newTurnRoadbedColorRGB, segs[i].lineWidth, segs[i].u.p.cnt )>0; for ( j=0; j0; break; } } rc &= fprintf( f, "\t%s\n", END_SEGS )>0; return rc; } BOOL_T WriteCompoundPathsEndPtsSegs( FILE * f, PATHPTR_T paths, wIndex_t segCnt, trkSeg_p segs, EPINX_T endPtCnt, trkEndPt_p endPts ) { int i; PATHPTR_T pp; BOOL_T rc = TRUE; for ( pp=paths; *pp; pp+=2 ) { rc &= fprintf( f, "\tP \"%s\"", (char*)pp )>0; for ( pp+=strlen((char*)pp)+1; pp[0]!=0||pp[1]!=0; pp++ ) { rc &= fprintf( f, " %d", *pp )>0; } rc &= fprintf( f, "\n" )>0; } for ( i=0; i0; #ifdef MKTURNOUT if ( specialLine[0] ) { rc &= fprintf( f, "%s\n", specialLine ); } #endif rc &= WriteSegs( f, segCnt, segs ); return rc; } void Usage( int argc, char **argv ) { int inx; for (inx=1; inx B # Create bumper\n" " S # Create straight track\n" " J # Create adjustable track\n" " C # Create curved track\n" " R # Create Regular Turnout\n" " Q # Create Radial Turnout\n" " V # Create Curved Turnout\n" " W # Create Radial Curved Turnout\n" " Y # Create Wye Turnout\n" " 3 # Create 3-Way Turnout\n" " X # Create Crossing\n" " 1 # Create Single Slipswitch\n" " 2 # Create Double Slipswitch\n" " D # Create Double Crossover\n" " T # Create TurnTable\n" ); exit(1); } struct { char * scale; double trackGauge; } scaleMap[] = { { "N", 0.3531 }, { "HO", 0.6486 }, { "O", 1.1770 }, { "HOm", 0.472440 }, { "G", 1.770 } }; int main ( int argc, char * argv[] ) { // char * cmd; double radius, radius2; int inx, cnt; double ang, x0, y0, x1, y1; char **argv0; int argc0; argc0 = argc; argv0 = argv; doCustomInfoLine = FALSE; argv++; if (argc < 7) { Usage(argc0,argv0); } while ( argv[0][0] == '-' ) { switch (argv[0][1]) { case 'm': units = UNITS_METRIC; break; case 'u': doCustomInfoLine = TRUE; break; case 'r': doRoadBed = TRUE; if (argv[0][2] == '\0') { Usage(argc0,argv0); } newTurnRoadbedWidth = atof(&argv[0][2]); newTurnRoadbedColorRGB = 0; newTurnRoadbedColor = 0; newTurnRoadbedLineWidth = 0; break; case 'c': newTurnRoadbedColorRGB = atol(&argv[0][2]); break; case 'l': newTurnRoadbedLineWidth = atol(&argv[0][2]); break; default: fprintf( stderr, "Unknown option: %s\n", argv[0] ); } argv++; argc--; } newTurnScaleName = curScaleName = *argv++; trackGauge = 0.0; for ( inx=0; inx