From 7b358424ebad9349421acd533c2fa1cbf6cf3e3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Wed, 28 Dec 2016 16:52:56 +0100 Subject: Initial import of xtrkcad version 1:4.0.2-2 --- app/bin/cprofile.c | 1357 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1357 insertions(+) create mode 100644 app/bin/cprofile.c (limited to 'app/bin/cprofile.c') diff --git a/app/bin/cprofile.c b/app/bin/cprofile.c new file mode 100644 index 0000000..245bb58 --- /dev/null +++ b/app/bin/cprofile.c @@ -0,0 +1,1357 @@ +/* + * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cprofile.c,v 1.4 2008-03-06 19:35:06 m_fischer Exp $ + */ + +/* XTrkCad - Model Railroad CAD + * Copyright (C) 2005 Dave Bullis + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "track.h" +#include "cselect.h" +#include +#include "shrtpath.h" +#include "i18n.h" + + +/* + + PROFILE COMMAND TEST CASE +(use 0testprof.xtc - 6 tracks connected 0:0:1 1:0:1 2:0:1 3:0:1 4:0:1 5:0:1 6:0:1) + + PreCond Action PostCond + +/ empty -> creating single pt +A1 - - 10 10 - +A2 - - 20 20 11 +A3 - - 11 11 20 + +/ single pt -> delete +B1 10 - 10 - - +B2 20 11 20 - - +B3 20 11 11 - - + +/ single pt at EOT - extend +C1 10 - 11 10 11 {1} +C2 10 - 20 10 11 {1} +C3 10 - 41 10 41 {1234} +C4 10 - 50 10 41 {1234} + +/ single pt at mid track - extend +D1 31 40 11 31 20 {32} +D2 31 40 20 31 20 {32} +D3 31 40 51 40 51 {45} +D4 31 40 61 40 61 {456} +D5 31 40 10 31 10 {321} + +/ length=2, delete end +E1 30 41 30 40 41 {4} +E2 30 41 21 40 41 {4} +E3 30 41 41 30 31 {3} +E4 30 41 50 30 31 {3} + +/ length=1, delete end +F1 30 31 30 31 - +F2 30 31 21 31 - +F3 30 31 31 30 - +F4 30 31 40 30 - + +/ length=1, extend +G1 30 31 11 20 31 {23} +G2 30 31 10 10 31 {123} +G3 30 31 51 30 51 {345} +G4 30 31 60 30 51 {345} +G5 30 31 61 30 61 {3456} + +/ length=2, extend +H1 30 41 11 20 41 {234} +H2 30 41 10 10 41 {1234} +H3 30 41 51 30 51 {345} +H4 30 41 60 30 51 {345} +H5 30 41 61 30 61 {3456} +*/ + +/***************************************************************************** + * + * PROFILE WINDOW + * + */ + +static wDrawColor profileColorDefinedProfile; +static wDrawColor profileColorUndefinedProfile; +static wDrawColor profileColorFill; +static wFontSize_t screenProfileFontSize = 12; +static wFontSize_t printProfileFontSize = 6; +static BOOL_T printVert = TRUE; +static wMenu_p profilePopupM; +static track_p profilePopupTrk; +static EPINX_T profilePopupEp; +static wMenuToggle_p profilePopupToggles[3]; + +static int log_profile = 0; + +#define LABELH (labelH*fontSize/screenProfileFontSize) +#define PBB(FS) (2.0*(labelH*(FS)/screenProfileFontSize+3.0/mainD.dpi)) +#define PBT (10.0/mainD.dpi) +#define PBR (30.0/mainD.dpi) +#define PBL (20.0/mainD.dpi) +static FLOAT_T labelH; + + +track_p pathStartTrk; +EPINX_T pathStartEp; +track_p pathEndTrk; +EPINX_T pathEndEp; + +#define PASSERT( F, X, R ) if ( ! (X) ) { ErrorMessage( MSG_PASSERT, F, __LINE__, #X ); return R; } +#define NOP + +typedef struct { + track_p trk; + EPINX_T ep; + DIST_T elev; + DIST_T dist; + BOOL_T defined; /* from prev PE to current */ + } profElem_t, *profElem_p; +static dynArr_t profElem_da; +#define profElem(N) DYNARR_N( profElem_t, profElem_da, N ) + +typedef struct { + DIST_T dist; + char * name; + } station_t, *station_p; +static dynArr_t station_da; +#define station(N) DYNARR_N( station_t, station_da, N ) + + +struct { + DIST_T totalD, minE; + int minC, maxC, incrC; + DIST_T scaleX, scaleY; + } prof; +static void DrawProfile( drawCmd_p D, wFontSize_t fontSize, BOOL_T printVert ) +{ + coOrd pl, pt, pb; + int inx; + DIST_T grade; + wFont_p fp; + static dynArr_t points_da; +#define points(N) DYNARR_N( coOrd, points_da, N ) + wDrawWidth lw; + station_p ps; + coOrd textsize; + + lw = (wDrawWidth)(D->dpi*2.0/mainD.dpi); + fp = wStandardFont( F_HELV, FALSE, FALSE ); + DYNARR_RESET( coOrd, points_da ); + + pb.x = pt.x = 0; + pb.y = prof.minE; pt.y = GetDim(prof.maxC); + DrawLine( D, pb, pt, 0, snapGridColor ); + pb.x = pt.x = prof.totalD; + DrawLine( D, pb, pt, 0, snapGridColor ); + pb.x = 0; + pt.x = prof.totalD; + for (inx=prof.minC; inx<=prof.maxC; inx+=prof.incrC) { + pt.y = pb.y = GetDim(inx); + DrawLine( D, pb, pt, 0, snapGridColor ); + pl.x = -(PBL-3.0/mainD.dpi)/prof.scaleX*D->scale; + pl.y = pb.y-LABELH/2/prof.scaleY*D->scale; + sprintf( message, "%d", inx ); + DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); + } + if ( profElem_da.cnt <= 0 ) + return; + + for (inx=0; inx 1 ) { + DYNARR_APPEND( coOrd, points_da, 10 ); + pt.x = prof.totalD; + points(points_da.cnt-1) = pt; + DYNARR_APPEND( coOrd, points_da, 10 ); + pb.x = 0; + points(points_da.cnt-1) = pb; + DrawFillPoly( D, points_da.cnt, &points(0), profileColorFill ); + DrawLine( D, pb, pt, lw, borderColor ); + } + + pt.y = prof.minE-(2*LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale; + for (inx=0; inxname, fp, fontSize, FALSE, &textsize ); + pt.x = ps->dist - textsize.x/2.0/prof.scaleX*D->scale; + if (pt.x < -PBR) + pt.x = -(PBR-3/mainD.dpi)/prof.scaleX*D->scale; + else if (pt.x+textsize.x > prof.totalD) + pt.x = prof.totalD-(textsize.x-3/mainD.dpi)/prof.scaleX*D->scale; + DrawString( D, pt, 0.0, ps->name, fp, fontSize*D->scale, borderColor ); + } + + pb.x = 0.0; pb.y = prof.minE; + pt = points(0); + DrawLine( D, pb, pt, lw, borderColor ); + sprintf( message, "%0.1f", PutDim(profElem(0).elev) ); + if (printVert) { + pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale; + pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale; + DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor ); + } else { + pl.x = pt.x+2.0/mainD.dpi/prof.scaleX*D->scale; + pl.y = pt.y; + if (profElem_da.cnt>1 && profElem(0).elev < profElem(1).elev ) + pl.y -= LABELH/prof.scaleY*D->scale; + DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); + } + pl = pt; + + for (inx=1; inx 0.1) { + grade = fabs(profElem(inx).elev-profElem(inx-1).elev)/ + (profElem(inx).dist-profElem(inx-1).dist); + sprintf( message, "%0.1f%%", grade*100.0 ); + DrawTextSize( &mainD, message, fp, fontSize, FALSE, &textsize ); + pl.x = (points(inx).x+points(inx-1).x)/2.0; + pl.y = (points(inx).y+points(inx-1).y)/2.0; + if (printVert) { + pl.x += (LABELH/2)/prof.scaleX*D->scale; + pl.y += ((LABELH/2)*grade/prof.scaleX + 2.0/mainD.dpi/prof.scaleY)*D->scale; + DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor ); + } else { + pl.x -= (textsize.x/2)/prof.scaleX*D->scale; + pl.y += (textsize.x/2)*grade/prof.scaleX*D->scale; + DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); + } + } + if (units==UNITS_ENGLISH) { + if (prof.totalD > 240) + sprintf( message, "%d'", ((int)floor(profElem(inx).dist)+6)/12 ); + else + sprintf( message, "%d'%d\"", ((int)floor(profElem(inx).dist+0.5))/12, ((int)floor(profElem(inx).dist+0.5))%12 ); + } else { + if (PutDim(prof.totalD) > 10000) + sprintf( message, "%0.0fm", (PutDim(profElem(inx).dist)+50)/100.0 ); + else if (PutDim(prof.totalD) > 100) + sprintf( message, "%0.1fm", (PutDim(profElem(inx).dist)+5)/100.0 ); + else + sprintf( message, "%0.2fm", (PutDim(profElem(inx).dist)+0.5)/100.0 ); + } + DrawTextSize( &mainD, message, fp, fontSize, FALSE, &textsize ); + pl.x = pb.x-(textsize.x/2)/prof.scaleX*D->scale; + pl.y = prof.minE-(LABELH+3.0/mainD.dpi)/prof.scaleY*D->scale; + DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); + sprintf( message, "%0.1f", PutDim(profElem(inx).elev) ); + if (printVert) { + pl.x = pt.x + LABELH/2.0/prof.scaleX*D->scale; + pl.y = pt.y + 2.0/mainD.dpi/prof.scaleY*D->scale; + DrawString( D, pl, 270.0, message, fp, fontSize*D->scale, borderColor ); + } else { + pl.x = pt.x + 2.0/mainD.dpi/prof.scaleX*D->scale; + pl.y = pt.y; + if ( inx != profElem_da.cnt-1 && profElem(inx).elev < profElem(inx+1).elev ) + pl.y -= LABELH/prof.scaleY*D->scale; + DrawString( D, pl, 0.0, message, fp, fontSize*D->scale, borderColor ); + } + pl = pt; + } +} + + + +static void ProfilePix2CoOrd( drawCmd_p, wPos_t, wPos_t, coOrd * ); +static void ProfileCoOrd2Pix( drawCmd_p, coOrd, wPos_t*, wPos_t* ); +static drawCmd_t screenProfileD = { + NULL, + &screenDrawFuncs, + DC_NOCLIP, + 1.0, + 0.0, + {0.0,0.0}, {0.0,0.0}, + ProfilePix2CoOrd, ProfileCoOrd2Pix }; + +static void ProfilePix2CoOrd( + drawCmd_p d, + wPos_t xx, + wPos_t yy, + coOrd * pos ) +{ + pos->x = (xx/d->dpi+d->orig.x)/prof.scaleX; + pos->y = (yy/d->dpi+d->orig.y)/prof.scaleY+prof.minE; +} + +static void ProfileCoOrd2Pix( + drawCmd_p d, + coOrd pos, + wPos_t *xx, + wPos_t *yy ) +{ + wPos_t x, y; + x = (wPos_t)((((pos.x*prof.scaleX)/d->scale-d->orig.x)*d->dpi+0.5)); + y = (wPos_t)(((((pos.y-prof.minE)*prof.scaleY)/d->scale-d->orig.y)*d->dpi+0.5)); + if ( d->angle == 0 ) { + *xx = x; + *yy = y; + } else if ( d->angle == -90.0 ) { + /* L->P */ + *xx = y; + *yy = -x; + } else { + /* P->L */ + *xx = -y; + *yy = x; + } +} + + +static void RedrawProfileW( void ) +{ + wPos_t ww, hh; + coOrd size; + int inx, divC; + DIST_T maxE, rngE; + profElem_t *p; + wFont_p fp; + POS_T w; + coOrd textsize; + + wDrawClear( screenProfileD.d ); + wDrawGetSize( screenProfileD.d, &ww, &hh ); + screenProfileD.size.x = (ww)/screenProfileD.dpi; + screenProfileD.size.y = (hh)/screenProfileD.dpi; + screenProfileD.orig.x = -PBL; + screenProfileD.orig.y = -PBB(screenProfileFontSize); + + /* Calculate usable dimension of canvas */ + size = screenProfileD.size; + size.x -= (PBL); + size.y -= (PBB(screenProfileFontSize)); +#ifdef WINDOWS + if (printVert) { + size.x -= PBR/4.0; + size.y -= PBT; + } else +#endif + { + size.x -= PBR; + size.y -= PBT; + } + if ( size.x < 0.1 || size.y < 0.1 ) + return; + + /* Calculate range of data values */ + if (profElem_da.cnt<=0) { + prof.totalD = 0.0; + prof.minE = 0.0; + maxE = 1.0; + } else { + maxE = prof.minE = profElem(0).elev; + prof.totalD = profElem(profElem_da.cnt-1).dist; + for (inx=1; inxelevelev; + if (p->elev>maxE) + maxE = p->elev; + } + } + + /* Calculate number of grid lines */ + prof.minC = (int)floor(PutDim(prof.minE)); + prof.maxC = (int)ceil(PutDim(maxE)); + if ( prof.maxC-prof.minC <= 0 ) + prof.maxC = prof.minC+1; + divC = (int)floor(size.y/labelH); + if ( divC < 1 ) + divC = 1; + prof.incrC = (prof.maxC-prof.minC+divC-1)/divC; + if ( prof.incrC < 1 ) + prof.incrC = 1; + prof.maxC = prof.minC + (prof.maxC-prof.minC+prof.incrC-1)/prof.incrC * prof.incrC; + + /* Reset bounds based on intergal values */ + prof.minE = GetDim(prof.minC); + rngE = GetDim(prof.maxC) - prof.minE; + if (rngE < 1.0) + rngE = 1.0; + + /* Compute vert scale */ + prof.scaleY = size.y/rngE; + sprintf( message, "%0.2f", maxE ); + fp = wStandardFont( F_HELV, FALSE, FALSE ); + DrawTextSize( &mainD, message, fp, screenProfileFontSize, FALSE, &textsize ); + w = textsize.x; + w -= PBT; + w += 4.0/screenProfileD.dpi; + w -= (GetDim(prof.maxC)-maxE)*prof.scaleY; + if (w > 0) { + size.y -= w; + prof.scaleY = size.y/rngE; + } + + /* Compute horz scale */ + if (prof.totalD <= 0.1) { + prof.totalD = size.x; + } + prof.scaleX = size.x/prof.totalD; + +#ifdef LATER + D->size.x /= prof.scaleX; + D->size.x -= D->orig.x; + D->size.y /= prof.scaleY; + D->size.y -= D->orig.y; + D->size.y += prof.minE; +#endif + + DrawProfile( &screenProfileD, screenProfileFontSize, +#ifdef WINDOWS + printVert +#else + FALSE +#endif + ); +} + + +static drawCmd_t printProfileD = { + NULL, + &printDrawFuncs, + DC_PRINT|DC_NOCLIP, + 1.0, + 0.0, + {0.0,0.0}, {1.0,1.0}, + ProfilePix2CoOrd, ProfileCoOrd2Pix }; +static void DoProfilePrint( void * junk ) +{ + coOrd size, p[4]; + int copies; + WDOUBLE_T w, h, screenRatio, printRatio, titleH; + wFont_p fp; + coOrd screenSize; + coOrd textsize; + + if (!wPrintDocStart( _("Profile"), 1, &copies )) + return; + printProfileD.d = wPrintPageStart(); + if (printProfileD.d == NULL) + return; + printProfileD.dpi = wDrawGetDPI( printProfileD.d ); + wPrintGetPageSize( &w, &h ); + printProfileD.orig.x = -PBL; + printProfileD.orig.y = -PBB(printProfileFontSize); + printProfileD.angle = 0.0; + screenRatio = screenProfileD.size.y/screenProfileD.size.x; + screenSize.x = prof.totalD*prof.scaleX; + screenSize.y = GetDim(prof.maxC-prof.minC)*prof.scaleY; + screenRatio = screenSize.y/screenSize.x; + printProfileD.size.x = w; + printProfileD.size.y = h; + sprintf( message, _("%s Profile: %s"), sProdName, Title1 ); + fp = wStandardFont( F_TIMES, FALSE, FALSE ); + DrawTextSize( &mainD, message, fp, 24, FALSE, &textsize ); + titleH = textsize.y + 6.0/mainD.dpi; + if (screenRatio < 1.0 && w < h ) { + /* Landscape -> Portrait */ + printProfileD.angle = -90.0; + printProfileD.orig.x += h; + size.x = h; + size.y = w; + } else if (screenRatio > 1.0 && w > h ) { + /* Portrait -> Landscape */ + printProfileD.angle = 90.0; + printProfileD.orig.y += w; + size.x = h; + size.y = w; + } else { + size.x = w; + size.y = h; + } + size.y -= titleH+(printVert?PBT*2:PBT)+PBB(printProfileFontSize); + size.x -= 4.0/mainD.dpi+PBL+(printVert?PBR/4.0:PBR); + printRatio = size.y/size.x; + if (printRatio < screenRatio) { + printProfileD.scale = screenSize.y/size.y; + size.x = screenSize.x/printProfileD.scale; + } else { + printProfileD.scale = screenSize.x/size.x; + printProfileD.orig.y -= size.y; + size.y = screenSize.y/printProfileD.scale; + printProfileD.orig.y += size.y; + } +#define PRINT_ABS2PAGEX(X) (((X)*printProfileD.scale)/prof.scaleX) +#define PRINT_ABS2PAGEY(Y) (((Y)*printProfileD.scale)/prof.scaleY+prof.minE) + p[0].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT)+0.05); + p[0].x = PRINT_ABS2PAGEX((size.x-textsize.x)/2.0); + if ( p[0].x < 0 ) + p[0].x = 0; + DrawString( &printProfileD, p[0], 0, message, fp, 24*printProfileD.scale, borderColor ); + p[0].x = p[3].x = PRINT_ABS2PAGEX((-PBL)+2.0/mainD.dpi); + p[0].y = p[1].y = PRINT_ABS2PAGEY(-PBB(printProfileFontSize)); + p[1].x = p[2].x = PRINT_ABS2PAGEX(size.x+(printVert?PBR/4.0:PBR)); + p[2].y = p[3].y = PRINT_ABS2PAGEY(size.y+(printVert?PBT*2:PBT)); + DrawLine( &printProfileD, p[0], p[1], 0, drawColorBlack ); + DrawLine( &printProfileD, p[1], p[2], 0, drawColorBlack ); + DrawLine( &printProfileD, p[2], p[3], 0, drawColorBlack ); + DrawLine( &printProfileD, p[3], p[0], 0, drawColorBlack ); + + DrawProfile( &printProfileD, printProfileFontSize, printVert ); + wPrintPageEnd( printProfileD.d ); + wPrintDocEnd(); +} + + + +/************************************************************************** + * + * Window Handlers + * + **************************************************************************/ + +static wWin_p profileW; + + +static BOOL_T profileUndo = FALSE; +static void DoProfileDone( void * ); +static void DoProfileClear( void * ); +static void DoProfilePrint( void * ); +static void DoProfileChangeMode( void * ); +static void SelProfileW( wIndex_t, coOrd ); + +static paramDrawData_t profileDrawData = { 300, 150, (wDrawRedrawCallBack_p)RedrawProfileW, SelProfileW, &screenProfileD }; +static paramData_t profilePLs[] = { + { PD_DRAW, NULL, "canvas", PDO_DLGRESIZE, &profileDrawData }, +#define I_PROFILEMSG (1) + { PD_MESSAGE, NULL, NULL, PDO_DLGIGNOREX, (void*)300 }, + { PD_BUTTON, (void*)DoProfileClear, "clear", PDO_DLGCMDBUTTON, NULL, N_("Clear") }, + { PD_BUTTON, (void*)DoProfilePrint, "print", 0, NULL, N_("Print") } }; +static paramGroup_t profilePG = { "profile", 0, profilePLs, sizeof profilePLs/sizeof profilePLs[0] }; + + +static void ProfileTempDraw( int inx, DIST_T elev ) +{ + coOrd p0, p1; +#ifdef LATER + p0.x = profElem(inx).dist*prof.scaleX; + p0.y = (elev-prof.minE)*prof.scaleY; + screenProfileD.funcs = &tempDrawFuncs; + if (inx > 0) { + p1.x = profElem(inx-1).dist*prof.scaleX; + p1.y = (profElem(inx-1).elev-prof.minE)*prof.scaleY; + DrawLine( &screenProfileD, p0, p1, 2, borderColor ); + } + if (inx < profElem_da.cnt-1) { + p1.x = profElem(inx+1).dist*prof.scaleX; + p1.y = (profElem(inx+1).elev-prof.minE)*prof.scaleY; + DrawLine( &screenProfileD, p0, p1, 2, borderColor ); + } + screenProfileD.funcs = &screenDrawFuncs; +#endif + p0.x = profElem(inx).dist; + p0.y = elev; + screenProfileD.funcs = &tempDrawFuncs; + if (inx > 0) { + p1.x = profElem(inx-1).dist; + p1.y = profElem(inx-1).elev; + DrawLine( &screenProfileD, p0, p1, 2, borderColor ); + } + if (inx < profElem_da.cnt-1) { + p1.x = profElem(inx+1).dist; + p1.y = profElem(inx+1).elev; + DrawLine( &screenProfileD, p0, p1, 2, borderColor ); + } + screenProfileD.funcs = &screenDrawFuncs; +} + + +static void SelProfileW( + wIndex_t action, + coOrd pos ) +{ + DIST_T dist; + static DIST_T oldElev; + static int inx; + DIST_T elev; + + if (profElem_da.cnt <= 0) + return; + + dist = pos.x; + elev = pos.y; + +#ifdef LATER + if (recordF) + RecordMouse( "PROFILEMOUSE", action, dist, elev ); +#endif + + switch (action&0xFF) { + case C_DOWN: + for (inx=0; inx dist-profElem(inx-1).dist) + inx--; + break; + } + } + if (inx >= profElem_da.cnt) + inx = profElem_da.cnt-1; + sprintf(message, _("Elev = %0.1f"), PutDim(elev) ); + ParamLoadMessage( &profilePG, I_PROFILEMSG, message ); + oldElev = elev; + ProfileTempDraw( inx, elev ); + break; + case C_MOVE: + if ( inx < 0 ) + break; + ProfileTempDraw( inx, oldElev ); + if (profElem_da.cnt == 1 ) { + sprintf(message, _("Elev = %0.1f"), PutDim(elev) ); + } else if (inx == 0) { + sprintf( message, _("Elev=%0.2f %0.1f%%"), + PutDim(elev), + fabs( profElem(inx+1).elev-elev ) / (profElem(inx+1).dist-profElem(inx).dist) * 100.0 ); + } else if (inx == profElem_da.cnt-1) { + sprintf( message, _("%0.1f%% Elev = %0.2f"), + fabs( profElem(inx-1).elev-elev ) / (profElem(inx).dist-profElem(inx-1).dist) * 100.0, + PutDim(elev) ); + } else { + sprintf( message, _("%0.1f%% Elev = %0.2f %0.1f%%"), + fabs( profElem(inx-1).elev-elev ) / (profElem(inx).dist-profElem(inx-1).dist) * 100.0, + PutDim(elev), + fabs( profElem(inx+1).elev-elev ) / (profElem(inx+1).dist-profElem(inx).dist) * 100.0 ); + } + ParamLoadMessage( &profilePG, I_PROFILEMSG, message ); + oldElev = elev; + ProfileTempDraw( inx, oldElev ); + break; + case C_UP: + if (profileUndo == FALSE) { + UndoStart( _("Profile Command"), "Profile - set elevation" ); + profileUndo = TRUE; + } + if (profElem(inx).trk) { + UpdateTrkEndElev( profElem(inx).trk, profElem(inx).ep, ELEV_DEF|ELEV_VISIBLE, oldElev, NULL ); + } + profElem(inx).elev = oldElev; + RedrawProfileW(); + ParamLoadMessage( &profilePG, I_PROFILEMSG, _("Drag to change Elevation") ); + inx = -1; + break; + default: + break; + } +} + + +#ifdef LATER +static BOOL_T ProfilePlayback( char * line ) +{ + int action; + wPos_t x, y; + coOrd pos; + + if ( !GetArgs( line, "dp", &action, &pos ) ) { + return FALSE; + } else { + x = (wPos_t)(((pos.x*prof.scaleX)-screenProfileD.orig.x)*screenProfileD.dpi+0.5); + y = (wPos_t)((((pos.y-prof.minE)*prof.scaleY)-screenProfileD.orig.y)*screenProfileD.dpi+0.5); + PlaybackMouse( selProfileW, &screenProfileD, (wAction_t)action, x, y, drawColorBlack ); + } + return TRUE; +} +#endif + + + +static void HilightProfileElevations( BOOL_T show ) +{ + /*if ( profElem_da.cnt <= 0 ) {*/ + HilightElevations( show ); + /*} else { + }*/ +} + + +static void DoProfileDone( void * junk ) +{ +#ifdef LATER + HilightProfileElevations( FALSE ); + wHide( profileW ); + ClrAllTrkBits( TB_PROFILEPATH ); + MainRedraw(); +#endif + Reset(); +} + + +static void DoProfileClear( void * junk ) +{ + profElem_da.cnt = 0; + station_da.cnt = 0; + if (ClrAllTrkBits( TB_PROFILEPATH )) + MainRedraw(); + pathStartTrk = pathEndTrk = NULL; + RedrawProfileW(); +} + + +static void DoProfileChangeMode( void * junk ) +{ + if (profElem_da.cnt<=0) { + InfoMessage( _("Select a Defined Elevation to start Profile") ); + } else { + InfoMessage( _("Select a Defined Elevation to extend Profile") ); + } +} + +/************************************************************************** + * + * Find Shortest Path + * + **************************************************************************/ + +static BOOL_T PathListEmpty( void ) +{ + return pathStartTrk == NULL; +} + +static BOOL_T PathListSingle( void ) +{ + return pathStartTrk != NULL && + ( pathEndTrk == NULL || + ( GetTrkEndTrk(pathEndTrk,pathEndEp) == pathStartTrk && + GetTrkEndTrk(pathStartTrk,pathStartEp) == pathEndTrk ) ); +} + + +static int profileShortestPathMatch; +static DIST_T profileShortestPathDist; + +static int ProfileShortestPathFunc( + SPTF_CMD cmd, + track_p trk, + EPINX_T ep, + EPINX_T ep0, + DIST_T dist, + void * data ) +{ + track_p trkN; + EPINX_T epN; + int rc0=0; + int pathMatch; + + switch (cmd) { + case SPTC_TERMINATE: + rc0 = 1; + break; + + case SPTC_MATCH: + if ( EndPtIsIgnoredElev(trk,ep) ) + break; + if ( PathListSingle() ) { + if ( trk == pathStartTrk && ep == pathStartEp ) { + pathMatch = 2; + } else if ( trk == pathEndTrk && ep == pathEndEp ) { + pathMatch = 3; + } else { + break; + } + } else if ( ( trkN = GetTrkEndTrk(trk,ep) ) == NULL ) { + break; + } else { + epN = GetEndPtConnectedToMe( trkN, trk ); + if ( trkN == pathStartTrk && epN == pathStartEp ) { + pathMatch = 1; + } else if ( trkN == pathEndTrk && epN == pathEndEp ) { + pathMatch = 2; + } else if ( trkN == pathStartTrk && trkN == pathEndTrk ) { + pathMatch = 2; + } else if ( trkN == pathStartTrk ) { + pathMatch = 1; + } else if ( trkN == pathEndTrk ) { + pathMatch = 2; + } else { + break; + } + } + if ( profileShortestPathMatch < 0 || profileShortestPathDist > dist ) { +LOG( log_shortPath, 4, ( " Match=%d", pathMatch ) ) + profileShortestPathMatch = pathMatch; + profileShortestPathDist = dist; + } + rc0 = 1; + break; + + case SPTC_MATCHANY: + rc0 = -1; + break; + + case SPTC_IGNNXTTRK: + if ( EndPtIsIgnoredElev(trk,ep) ) + rc0 = 1; + else if ( (GetTrkBits(trk)&TB_PROFILEPATH)!=0 ) + rc0 = 1; + else if ( (!EndPtIsDefinedElev(trk,ep)) && GetTrkEndTrk(trk,ep)==NULL ) + rc0 = 1; + else + rc0 = 0; + break; + + case SPTC_ADD_TRK: +if (log_shortPath<=0||logTable(log_shortPath).level<4) LOG( log_profile, 4, ( " ADD_TRK T%d:%d", GetTrkIndex(trk), ep ) ) + SetTrkBits( trk, TB_PROFILEPATH ); + DrawTrack( trk, &mainD, profilePathColor ); + rc0 = 0; + break; + + case SPTC_VALID: + rc0 = 1; + break; + + default: + break; + } + return rc0; +} + +static int FindProfileShortestPath( + track_p trkN, + EPINX_T epN ) +{ +LOG( log_profile, 4, ( "Searching from T%d:%d to T%d:%d or T%d:%d\n", + GetTrkIndex(trkN), epN, + pathStartTrk?GetTrkIndex(pathStartTrk):-1, pathStartTrk?pathStartEp:-1, + pathEndTrk?GetTrkIndex(pathEndTrk):-1, pathEndTrk?pathEndEp:-1 ) ) + profileShortestPathMatch = -1; + return FindShortestPath( trkN, epN, TRUE, ProfileShortestPathFunc, NULL ); +} + + +/************************************************************************** + * + * Main Window Handler + * + **************************************************************************/ + + +#define ONPATH_NOT (1<<0) +#define ONPATH_END (1<<1) +#define ONPATH_MID (1<<2) +#define ONPATH_BRANCH (1<<3) +static int OnPath( track_p trk, EPINX_T ep ) +{ + track_p trk0; + if ( GetTrkBits(trk)&TB_PROFILEPATH ) { + trk0 = GetTrkEndTrk( profilePopupTrk, profilePopupEp ); + if ( trk0 && (GetTrkBits(trk0)&TB_PROFILEPATH) ) { + return ONPATH_MID; + } + if ( ( trk == pathStartTrk && ep == pathStartEp ) || + ( trk == pathStartTrk && ep == pathStartEp ) ) { + return ONPATH_END; + } + return ONPATH_BRANCH; + } + return ONPATH_NOT; +} + + +static BOOL_T PathListCheck( void ) +{ + track_p trk; + if (PathListEmpty() || PathListSingle()) + return TRUE; + if (!(GetTrkBits(pathStartTrk)&TB_PROFILEPATH)) { + ErrorMessage( MSG_PST_NOT_ON_PATH ); + return FALSE; + } + if (!(GetTrkBits(pathEndTrk)&TB_PROFILEPATH)) { + ErrorMessage( MSG_PET_NOT_ON_PATH ); + return FALSE; + } + trk = GetTrkEndTrk(pathStartTrk,pathStartEp); + if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) { + ErrorMessage( MSG_INV_PST_ON_PATH ); + return FALSE; + } + trk = GetTrkEndTrk(pathEndTrk,pathEndEp); + if (trk && (GetTrkBits(trk)&TB_PROFILEPATH)) { + ErrorMessage( MSG_INV_PET_ON_PATH ); + return FALSE; + } + return TRUE; +} + + +static void RemoveTracksFromPath( + track_p *Rtrk, + EPINX_T *Rep, + track_p trkEnd, + EPINX_T epEnd ) +{ + EPINX_T ep2; + track_p trk = *Rtrk, trkN; + EPINX_T ep = *Rep; + + PASSERT( "removeTracksFromPath", trk, NOP ); + PASSERT( "removeTracksFromPath", !PathListSingle(), NOP ); + while (1) { + DrawTrack( trk, &mainD, drawColorWhite ); + ClrTrkBits( trk, TB_PROFILEPATH ); + DrawTrack( trk, &mainD, drawColorBlack ); + + if (trk == trkEnd) { + pathStartTrk = trkEnd; + pathStartEp = epEnd; + pathEndTrk = GetTrkEndTrk(pathStartTrk,pathStartEp); + if (pathEndTrk) + pathEndEp = GetEndPtConnectedToMe(pathEndTrk,pathStartTrk); + return; + } + + ep2 = GetNextTrkOnPath( trk, ep ); + PASSERT( "removeTracksFromPath", ep2 >= 0,NOP ); + trkN = GetTrkEndTrk(trk,ep2); + PASSERT( "removeTracksFromPath", trkN != NULL, NOP ); + ep = GetEndPtConnectedToMe(trkN,trk); + trk = trkN; + if (EndPtIsDefinedElev(trk,ep)) { + *Rtrk = trk; + *Rep = ep; + return; + } + } +} + + +static void ChkElev( track_p trk, EPINX_T ep, EPINX_T ep2, DIST_T dist, BOOL_T * defined ) +{ + profElem_p p; + station_p s; + EPINX_T epDefElev = -1, ep1; + int mode; + BOOL_T undefined; + + mode = GetTrkEndElevMode( trk, ep ); + if (mode == ELEV_DEF) { + epDefElev = ep; + } else if (mode == ELEV_STATION) { + DYNARR_APPEND( station_t, station_da, 10 ); + s = &station(station_da.cnt-1); + s->dist = dist; + s->name = GetTrkEndElevStation(trk,ep); + } + undefined = FALSE; + if (epDefElev<0) { + if ( (trk == pathStartTrk && ep == pathStartEp) || + (trk == pathEndTrk && ep == pathEndEp) ) { + epDefElev = ep; + } + } + if (epDefElev<0) { + if (ep == ep2 || + GetTrkEndElevMode(trk,ep2) != ELEV_DEF ) + for ( ep1=0; ep1=0) { + DYNARR_APPEND( profElem_t, profElem_da, 10 ); + p = &profElem(profElem_da.cnt-1); + p->trk = trk; + p->ep = epDefElev; + p->dist = dist; + if (GetTrkEndElevMode(trk,epDefElev) == ELEV_DEF) + p->elev = GetTrkEndElevHeight(trk,epDefElev); + else + ComputeElev( trk, epDefElev, TRUE, &p->elev, NULL ); + p->defined = *defined; + *defined = TRUE; + } else if (undefined) { + *defined = FALSE; + } +} + + +static void ComputeProfElem( void ) +{ + track_p trk = pathStartTrk, trkN; + EPINX_T ep = pathStartEp, ep2; + BOOL_T go; + DIST_T dist; + BOOL_T defined; + + profElem_da.cnt = 0; + station_da.cnt = 0; + dist = 0; + defined = TRUE; + if (PathListEmpty()) + return; + ChkElev( trk, ep, ep, dist, &defined ); + if (PathListSingle()) + return; + go = TRUE; + while ( go ) { + if (trk == pathEndTrk) { + go = FALSE; + ep2 = pathEndEp; + } else { + ep2 = GetNextTrkOnPath( trk, ep ); + PASSERT( "computeProfElem", ep2 >= 0, NOP ); + } + dist += GetTrkLength( trk, ep, ep2 ); + ChkElev( trk, ep2, ep, dist, &defined ); + if (!go) + break; + trkN = GetTrkEndTrk(trk,ep2); + ep = GetEndPtConnectedToMe(trkN,trk); + trk = trkN; + } +} + + +static void DumpProfElems( void ) +{ + track_p trk, trkN; + EPINX_T ep, ep2; + BOOL_T go; + + trk = pathStartTrk; + ep = pathStartEp; + + if (pathStartTrk==NULL) lprintf( "s--:- e--:-" ); + else if (pathEndTrk == NULL) lprintf( "sT%d:%d e--:-", GetTrkIndex(pathStartTrk), pathStartEp ); + else lprintf( "sT%d:%d eT%d:%d", GetTrkIndex(pathStartTrk), pathStartEp, GetTrkIndex(pathEndTrk), pathEndEp ); + lprintf( " { " ); + go = TRUE; + if (!PathListSingle()) + while ( trk ) { + if (trk==pathEndTrk) { + ep2 = pathEndEp; + go = FALSE; + } else { + ep2 = GetNextTrkOnPath( trk, ep ); + PASSERT( "computeProfElem", ep2 >= 0, NOP ); + } + lprintf( "T%d:%d:%d ", GetTrkIndex(trk), ep, ep2 ); + if (!go) + break; + trkN = GetTrkEndTrk(trk,ep2); + ep = GetEndPtConnectedToMe(trkN,trk); + trk = trkN; + } + lprintf( "}" ); +} + + +static void ProfileSelect( track_p trkN, EPINX_T epN ) +{ + track_p trkP; + EPINX_T epP=-1; + int rc; + +if (log_profile>=1) { + DumpProfElems(); + lprintf( " @ T%d:%d ", GetTrkIndex(trkN), epN ); + if (log_profile>=2) lprintf("\n"); + } + +#ifdef LATER + if (!EndPtIsDefinedElev(trkN, epN)) { + ErrorMessage( MSG_EP_NOT_DEP ); + return; + } +#endif + + trkP = GetTrkEndTrk( trkN, epN ); + if (trkP) + epP = GetEndPtConnectedToMe( trkP, trkN ); + + if (!PathListCheck()) + return; + + HilightProfileElevations( FALSE ); + + if ( PathListEmpty() ) { + pathStartTrk = trkN; + pathStartEp = epN; + pathEndTrk = trkP; + pathEndEp = epP; +LOG( log_profile, 2, ("Adding first element\n") ) + + } else if ( PathListSingle() && + ( ( trkN == pathStartTrk && epN == pathStartEp ) || + ( trkP && trkP == pathStartTrk && epP == pathStartEp ) ) ) { + pathStartTrk = pathEndTrk = NULL; +LOG( log_profile, 2, ("Clearing list\n") ) + + } else if ( (trkN == pathStartTrk && epN == pathStartEp ) || + (trkP && trkP == pathStartTrk && epP == pathStartEp) ) { + RemoveTracksFromPath( &pathStartTrk, &pathStartEp, pathEndTrk, pathEndEp ); +LOG( log_profile, 2, ("Removing first element\n") ) + + } else if ( (trkN == pathEndTrk && epN == pathEndEp) || + (trkP && trkP == pathEndTrk && epP == pathEndEp) ) { + RemoveTracksFromPath( &pathEndTrk, &pathEndEp, pathStartTrk, pathStartEp ); +LOG( log_profile, 2, ("Removing last element\n") ) + + } else if ( (GetTrkBits(trkN)&TB_PROFILEPATH) || (trkP && (GetTrkBits(trkP)&TB_PROFILEPATH)) ) { + ErrorMessage( MSG_EP_ON_PATH ); + HilightProfileElevations( TRUE ); + return; + + } else if ( ( rc = FindProfileShortestPath( trkN, epN ) ) > 0 ) { + if (!(GetTrkBits(trkN)&TB_PROFILEPATH)) { + PASSERT( "profileSelect", trkP != NULL, NOP ); + trkN = trkP; + epN = epP; +LOG( log_profile, 2, ("Invert selected EP\n") ) + } + + switch (profileShortestPathMatch) { + case 1: + /* extend Start */ + pathStartTrk = trkN; + pathStartEp = epN; +LOG( log_profile, 2, ( "Prepending Path\n" ) ) + break; + case 2: + /* extend End */ + pathEndTrk = trkN; + pathEndEp = epN; +LOG( log_profile, 2, ( "Appending Path\n" ) ) + break; + case 3: + /* need to flip */ + pathStartTrk = pathEndTrk; + pathStartEp = pathEndEp; + pathEndTrk = trkN; + pathEndEp = epN; +LOG( log_profile, 2, ( "Flip/Appending Path\n" ) ) + break; + default: + AbortProg( "findPaths:1" ); + } + + } else { + ErrorMessage( MSG_NO_PATH_TO_EP ); + HilightProfileElevations( TRUE ); + return; + } + + HilightProfileElevations( TRUE ); + ComputeProfElem(); + RedrawProfileW(); + DoProfileChangeMode( NULL ); +if (log_profile>=1) { + lprintf( " = " ); + DumpProfElems(); + lprintf( "\n" ); + } + PathListCheck(); +} + + + +static void ProfileSubCommand( wBool_t set, void* pcmd ) +{ + long cmd = (long)pcmd; + int mode; + coOrd pos = oldMarker; + DIST_T elev; + DIST_T radius; + + if ((profilePopupTrk = OnTrack( &pos, TRUE, TRUE )) == NULL || + (profilePopupEp = PickEndPoint( pos, profilePopupTrk )) < 0) + return; + if (profileUndo==0) { + profileUndo = TRUE; + UndoStart(_("Profile Command"), "Profile"); + } + radius = 0.05*mainD.scale; + if ( radius < trackGauge/2.0 ) + radius = trackGauge/2.0; + pos = GetTrkEndPos( profilePopupTrk, profilePopupEp ); + mode = GetTrkEndElevMode( profilePopupTrk, profilePopupEp ); + if ( (mode&ELEV_MASK)==ELEV_DEF || (mode&ELEV_MASK)==ELEV_IGNORE ) + DrawFillCircle( &tempD, pos, radius, + ((mode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore)); + if ( (mode&ELEV_MASK)==ELEV_DEF ) + + DrawEndPt2( &mainD, profilePopupTrk, profilePopupEp, drawColorWhite ); + elev = 0.0; + switch (cmd) { + case 0: + /* define */ + ComputeElev( profilePopupTrk, profilePopupEp, TRUE, &elev, NULL ); + mode = ELEV_DEF|ELEV_VISIBLE; + break; + case 1: + /* ignore */ + mode = ELEV_IGNORE|ELEV_VISIBLE; + break; + case 2: + default: + /* none */ + mode = ELEV_NONE; + break; + } + UpdateTrkEndElev( profilePopupTrk, profilePopupEp, mode, elev, NULL ); + if ( (mode&ELEV_MASK)==ELEV_DEF || (mode&ELEV_MASK)==ELEV_IGNORE ) + DrawFillCircle( &tempD, pos, radius, + ((mode&ELEV_MASK)==ELEV_DEF?elevColorDefined:elevColorIgnore)); + ComputeProfElem(); + RedrawProfileW(); +} + + +static STATUS_T CmdProfile( wAction_t action, coOrd pos ) +{ + track_p trk0; + EPINX_T ep0; + coOrd textsize; + + switch (action) { + case C_START: + if ( profileW == NULL ) { + profileColorDefinedProfile = drawColorBlue; + profileColorUndefinedProfile = drawColorRed; + profileColorFill = drawColorAqua; + DrawTextSize( &mainD, "999", wStandardFont( F_HELV, FALSE, FALSE ), screenProfileFontSize, FALSE, &textsize ); + labelH = textsize.y; + profileW = ParamCreateDialog( &profilePG, MakeWindowTitle(_("Profile")), _("Done"), DoProfileDone, (paramActionCancelProc)Reset, TRUE, NULL, F_RESIZE, NULL ); + } + ParamLoadControls( &profilePG ); + ParamGroupRecord( &profilePG ); + wShow( profileW ); + ParamLoadMessage( &profilePG, I_PROFILEMSG, _("Drag to change Elevation") ); + HilightProfileElevations( TRUE ); + profElem_da.cnt = 0; + station_da.cnt = 0; + RedrawProfileW(); + if ( ClrAllTrkBits( TB_PROFILEPATH ) ) + MainRedraw(); + pathStartTrk = NULL; + SetAllTrackSelect( FALSE ); + profileUndo = FALSE; + InfoMessage( _("Select a Defined Elevation to start profile") ); + return C_CONTINUE; + case C_LCLICK: + InfoMessage( "" ); + if ((trk0 = OnTrack( &pos, TRUE, TRUE )) != NULL) { + ep0 = PickEndPoint( pos, trk0 ); + if ( ep0 >= 0 ) { + ProfileSelect( trk0, ep0 ); + } + } + return C_CONTINUE; + case C_CMDMENU: + if ((profilePopupTrk = OnTrack( &pos, TRUE, TRUE )) != NULL ) { + profilePopupEp = PickEndPoint( pos, profilePopupTrk ); + if (profilePopupEp >= 0) { + int mode; + mode = GetTrkEndElevMode( profilePopupTrk, profilePopupEp ); + if (mode != ELEV_DEF && mode != ELEV_IGNORE && mode != ELEV_NONE ) { + ErrorMessage( MSG_CHANGE_ELEV_MODE ); + } else { + wMenuToggleEnable( profilePopupToggles[1], TRUE ); + if ( OnPath( profilePopupTrk, profilePopupEp ) & (ONPATH_END|ONPATH_MID) ) + wMenuToggleEnable( profilePopupToggles[1], FALSE ); + wMenuToggleSet( profilePopupToggles[0], mode == ELEV_DEF ); + wMenuToggleSet( profilePopupToggles[1], mode == ELEV_IGNORE ); + wMenuToggleSet( profilePopupToggles[2], mode == ELEV_NONE ); + wMenuPopupShow( profilePopupM ); + } + } + } +#ifdef LATER + InfoMessage( "" ); + if ((trk0 = OnTrack( &pos, TRUE, TRUE )) == NULL) + return C_CONTINUE; + ep0 = PickEndPoint( pos, trk0 ); + if (ep0 < 0) + return C_CONTINUE; + if (profileMode == 0) { + ; + } else { + ProfileIgnore( trk0, ep0 ); + } + DoProfileChangeMode( NULL ); +#endif + return C_CONTINUE; + case C_OK: + DoProfileDone(NULL); + return C_TERMINATE; + case C_CANCEL: + wHide(profileW); + HilightProfileElevations( FALSE ); + if (ClrAllTrkBits(TB_PROFILEPATH)) + MainRedraw(); + return C_TERMINATE; + case C_REDRAW: + if ( wWinIsVisible(profileW) ) { + HilightProfileElevations( wWinIsVisible(profileW) ); + /*RedrawProfileW();*/ + } + return C_CONTINUE; + } + return C_CONTINUE; +} + + +static void ProfileChange( long changes ) +{ + if ( (changes & CHANGE_UNITS) && screenProfileD.d ) + RedrawProfileW(); +} + + +#include "bitmaps/profile.xpm" + +EXPORT void InitCmdProfile( wMenu_p menu ) +{ + log_profile = LogFindIndex( "profile" ); + ParamRegister( &profilePG ); +#ifdef LATER + AddPlaybackProc( "PROFILEMOUSE", (playbackProc_p)profilePlayback, NULL ); +#endif + AddMenuButton( menu, CmdProfile, "cmdProfile", _("Profile"), wIconCreatePixMap(profile_xpm), LEVEL0_50, IC_LCLICK|IC_CMDMENU|IC_POPUP2, ACCL_PROFILE, NULL ); + profilePopupM = MenuRegister( "Profile Mode" ); + profilePopupToggles[0] = wMenuToggleCreate( profilePopupM, "", _("Define"), 0, FALSE, ProfileSubCommand, (void*)0 ); + profilePopupToggles[1] = wMenuToggleCreate( profilePopupM, "", _("Ignore"), 0, FALSE, ProfileSubCommand, (void*)1 ); + profilePopupToggles[2] = wMenuToggleCreate( profilePopupM, "", _("None"), 0, FALSE, ProfileSubCommand, (void*)2 ); + RegisterChangeNotification( ProfileChange ); +} -- cgit v1.2.3