/** \file elev.c * */ /* 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 "ccurve.h" #include "tbezier.h" #include "tcornu.h" #include "cundo.h" #include "param.h" #include "shrtpath.h" #include "track.h" #include "common-ui.h" /** @logcmd @showrefby fillElev=n elev.c */ static int log_fillElev = 0; /** @logcmd @showrefby dumpElev=n elev.c */ static int log_dumpElev = 0; static BOOL_T log_fillElev_initted; static int checkTrk = 0; static char * elevPrefix; static void SetTrkOnElevPath( track_p trk, int mode, DIST_T elev ); typedef struct { track_p trk; EPINX_T ep; DIST_T len; } elist_t; static dynArr_t elist_da; #define elist(N) DYNARR_N( elist_t, elist_da, N ) #define elistAppend( T, E, L ) \ { DYNARR_APPEND( elist_t, elist_da, 10 );\ elist(elist_da.cnt-1).trk = T; elist(elist_da.cnt-1).len = L; elist(elist_da.cnt-1).ep = E; } EPINX_T GetNextTrkOnPath( track_p trk, EPINX_T ep ) { /* Get next track on Path: 1 - there is only 1 connected (not counting ep) 2 - there are >1 but only 1 on Path 3 - one of them is PST:PSE or PET:PEE */ EPINX_T ep2; track_p trkN; int epCnt = GetTrkEndPtCnt(trk); for ( ep2=0; ep2= 0 ) { trk1 = GetTrkEndTrk( trk, ep2 ); ep1 = GetEndPtConnectedToMe( trk1, trk ); } else { trk1 = NULL; } } else { ep2 = GetNextTrk( trk, ep, &trk1, &ep1, GNTignoreIgnore ); } if (ep2 < 0) { if (trk1) { /* more than one branch */ return FDE_UDF; } else { /* end of the line */ return FDE_END; } } dist += GetTrkLength( trk, ep, ep2 ); trk = trk1; ep = ep1; if (trk == trk0) return FDE_UDF; } } BOOL_T ComputeElev( track_p trk, EPINX_T ep, BOOL_T onpath, DIST_T *elevR, DIST_T *gradeR, BOOL_T force ) { DIST_T grade = 0.0; DIST_T elev0; BOOL_T rc = FALSE; track_p trk1; EPINX_T ep1; rc = TRUE; if ( EndPtIsDefinedElev(trk,ep) ) { elev0 = GetTrkEndElevHeight(trk,ep); rc = FALSE; } else if (force || (!GetTrkEndElevCachedHeight(trk,ep,&elev0,&grade))) { trk1 = GetTrkEndTrk( trk, ep ); if (trk1!=NULL) { // Compute weighted average of the 2 track elevation ep1 = GetEndPtConnectedToMe(trk1,trk); if (force || (!GetTrkEndElevCachedHeight(trk1,ep1,&elev0,&grade))) { // Not cached, need to compute DIST_T elev1, dist0, dist1; elev0 = GetElevation( trk ); dist0 = GetTrkLength( trk, ep, -1 ); elev1 = GetElevation( trk1 ); dist1 = GetTrkLength( trk1, ep1, -1 ); if (dist0+dist1>0.1) { grade = (elev1-elev0)/(dist0+dist1); elev0 += grade*dist0; } else { elev0 = (elev0+elev1)/2.0; rc = FALSE; } SetTrkEndElevCachedHeight(trk,ep,elev0,grade); SetTrkEndElevCachedHeight(trk1,ep1,elev0,-grade); } else { // flip grade from connected EP grade = - grade; } } else { // Not connected - use track elevation elev0 = GetElevation( trk ); SetTrkEndElevCachedHeight(trk,ep,elev0,0.0); } } if ( elevR ) *elevR = elev0; if ( gradeR ) *gradeR = grade; return rc; } /* * DYNAMIC ELEVATION COMPUTATION * * Step 1: Find DefElev's marking the border of the area of interest (or all of them) */ typedef struct { track_p trk; EPINX_T ep; DIST_T elev; } defelev_t; static dynArr_t defelev_da; #define defelev(N) DYNARR_N( defelev_t, defelev_da, N ) static void FindDefElev( void ) { track_p trk; EPINX_T ep, cnt; defelev_t * dep; long time0 = wGetTimer(); DYNARR_RESET( defelev_t, defelev_da ); trk = NULL; while ( TrackIterate( &trk ) ) { cnt = GetTrkEndPtCnt( trk ); for ( ep = 0; ep < cnt; ep++ ) { if ( !EndPtIsDefinedElev( trk, ep ) ) continue; DYNARR_APPEND( defelev_t, defelev_da, 10 ); dep = &defelev( defelev_da.cnt-1 ); dep->trk = trk; dep->ep = ep; dep->elev = GetTrkEndElevHeight(trk,ep); } } LOG( log_fillElev, 1, ( "%s: findDefElev [%d] (%ld)\n", elevPrefix, defelev_da.cnt, wGetTimer()-time0 ) ) } static int foundNewDefElev; static void FindAttachedDefElev( track_p trk, BOOL_T remove ) /* Find all DefElev's attached (directly or not) to this trk * if 'remove' then clr ELEVPATH bit * Working: * elist_da * Outputs: * defelev_da - list of DefElev * foundNewDefElev - found a DefElev not already on ElevPath */ { int i1; track_p trk1; EPINX_T ep, cnt; defelev_t * dep; foundNewDefElev = FALSE; DYNARR_RESET( elist_t, elist_da ); elistAppend( trk, 0, 0 ); SetTrkBits( trk, TB_PROCESSED ); if (remove) ClrTrkBits( trk, TB_ELEVPATH ); for ( i1=0; i1trk = trk; dep->ep = ep; dep->elev = GetTrkEndElevHeight(trk,ep); if ( !(GetTrkBits(trk)&TB_ELEVPATH) ) { foundNewDefElev = TRUE; } } else { trk1 = GetTrkEndTrk(trk,ep); if (trk1) { #ifdef LATER if ( defElevOnIsland == FALSE && (GetTrkBits(trk1)&TB_ELEVPATH) ) { /* so far this island is only connected to forks */ DYNARR_APPEND( fork_t, fork_da, 10 ); n = &fork(fork_da.cnt-1); n->trk = trk1; n->ep = ep; n->dist = dist; n->elev = dep->elev; n->ntrk = dep->trk; n->nep = dep->ep; } #endif if ( !(GetTrkBits(trk1)&TB_PROCESSED) ) { elistAppend( trk1, 0, 0 ); SetTrkBits( trk1, TB_PROCESSED ); if (remove) ClrTrkBits( trk1, TB_ELEVPATH ); } } } } } } static int FindObsoleteElevs( void ) { track_p trk; int cnt; long time0 = wGetTimer(); ClrAllTrkBits( TB_PROCESSED ); DYNARR_RESET( defelev_t, defelev_da ); cnt = 0; trk = NULL; while ( TrackIterate( &trk ) ) { if ( (!(GetTrkBits(trk)&(TB_ELEVPATH|TB_PROCESSED))) && IsTrack(trk) ) { cnt++; FindAttachedDefElev( trk, TRUE ); } } LOG( log_fillElev, 1, ( "%s: findObsoleteElevs [%d] (%ld)\n", elevPrefix, cnt, wGetTimer()-time0 ) ) return cnt; } /* * DYNAMIC ELEVATION COMPUTATION * * Step 2: Find Forks on Shortest Path between the DefElev's found in Step 1 */ typedef struct { track_p trk; EPINX_T ep; EPINX_T ep2; DIST_T dist; DIST_T elev; } fork_t; static dynArr_t fork_da; #define fork(N) DYNARR_N( fork_t, fork_da, N ) static int FillElevShortestPathFunc( SPTF_CMD cmd, track_p trk, EPINX_T ep, EPINX_T ep2, DIST_T dist, void * data ) { defelev_t * dep = (defelev_t *)data; track_p trk1; EPINX_T ep1, cnt, epRc; fork_t * n; switch ( cmd ) { case SPTC_MATCH: /*if ( (GetTrkBits(trk)&TB_PROCESSED) ) epRc = 0; else*/ if ( (dep->trk!=trk || dep->ep!=ep) && EndPtIsDefinedElev(trk,ep)) epRc = 1; else epRc = 0; break; case SPTC_MATCHANY: cnt = GetTrkEndPtCnt( trk ); epRc = -1; /*if ( (GetTrkBits(trk)&TB_PROCESSED) ) break;*/ for ( ep1=0; ep1 DefElev\n", GetTrkIndex(trk), ep, dist ) ) LOG( log_shortPath, 4, ( "DefElev " ) ) } else if ( GetNextTrk( trk, ep, &trk1, &ep1, GNTignoreIgnore ) < 0 && trk1 != NULL ) { if (log_shortPath<=0||logTable(log_shortPath).level<4) LOG( log_fillElev, 4, ( " ADD_TRK: T%d:%d D=%0.3f E=%0.3f -> Fork[%d]\n", GetTrkIndex(trk), ep, dist, dep->elev, fork_da.cnt ) ) LOG( log_shortPath, 4, ( "E:%0.3f Fork[%d] ", dep->elev, fork_da.cnt ) ) DYNARR_APPEND( fork_t, fork_da, 10 ); n = &fork(fork_da.cnt-1); n->trk = trk; n->ep = ep; n->ep2 = ep2; n->dist = dist; n->elev = dep->elev; #ifdef LATER n->ntrk = dep->trk; n->nep = dep->ep; #endif } else { LOG( log_shortPath, 4, ( "Normal " ) ) } } else { LOG( log_shortPath, 4, ( "Processed " ) ) } return 0; case SPTC_TERMINATE: epRc = 0; break; case SPTC_IGNNXTTRK: if ( EndPtIsIgnoredElev(trk,ep2) ) { LOG( log_shortPath, 4, ( "2 Ignore " ) ) epRc = 1; } else if ( (!EndPtIsDefinedElev(trk,ep)) && GetTrkEndTrk(trk,ep)==NULL ) { LOG( log_shortPath, 4, ( "1 Null && !DefElev " ) ) epRc = 1; } else { epRc = 0; } break; case SPTC_VALID: epRc = (GetTrkBits(trk)&TB_PROCESSED)==0?1:0; break; default: epRc = 0; break; } return epRc; } static void FindForks( void ) /* Find the Shortest Path between all DevElev's (in defelev_da) * and record all Forks (Turnouts with >2 connections) with distance to and elevation of the DefElev * Inputs: * defelev_da - list of DefElev to consider * Outputs: * fork_da - list of distances btw Forks and DefElev (plus other info) */ { int i; defelev_t * dep; int rc; long time0 = wGetTimer(); DYNARR_RESET( fork_t, fork_da ); for ( i=0; itrk), dep->ep ) ) rc = FindShortestPath( dep->trk, dep->ep, FALSE, FillElevShortestPathFunc, dep ); } ClrAllTrkBits( TB_PROCESSED ); LOG( log_fillElev, 1, ( "%s: findForks [%d] (%ld)\n", elevPrefix, fork_da.cnt, wGetTimer()-time0 ) ) } /* * DYNAMIC ELEVATION COMPUTATION * * Step 3: Compute the elevation of each Fork based on the weighted sum of the elevations * of the DefElev's that it is connected to. */ typedef struct { DIST_T elev; DIST_T dist; } elevdist_t; static dynArr_t elevdist_da; #define elevdist(N) DYNARR_N( elevdist_t, elevdist_da, N ); static DIST_T ComputeWeightedElev( DIST_T totalDist ) /* Compute weighted elevation * Inputs: * totalDist - total distance of all tracks between DevElev's * elevdist_da - elev + dist to DefElev from current node * Outputs: * elev (returned) */ { int i2; DIST_T d2; elevdist_t * w; DIST_T e; /* Compute inverse weighted Distance (d2) */ d2 = 0; for ( i2=0; i2dist < 0.001) { e = w->elev; LOG( log_fillElev, 3, ( " computeWeightedElev: close! D%0.3f E%0.3f\n", w->dist, e ) ) return e; } d2 += totalDist/w->dist; } /* Compute weighted elevation (e) */ e = 0; for ( i2=0; i2dist)/d2)*w->elev; } if (log_fillElev >= 4) { for ( i2=0; i2elev, w->dist ); } } LOG( log_fillElev, 3, ( " computeWeightedElev: E%0.3f\n", e ) ) return e; } static int forkCnt; static void ComputeForkElev( void ) /* Compute elevations of all Forks * Inputs: * fork_da - fork distance/elev data (overwritten) * Outputs: * fork_da - just .trk used for forks * forkCnt - numer of forks found */ { int i1, i2; fork_t * n1, * n2, * n3; track_p trk, trk1; EPINX_T ep, cnt; DIST_T d1, e; elevdist_t * w; BOOL_T singlePath; long time0 = wGetTimer(); forkCnt = 0; for (i1=0; i1trk)) { cnt = GetTrkEndPtCnt(n1->trk); if (cnt<=0) continue; /* collect dist/elev to connected DefElev points */ d1 = 0; DYNARR_RESET( elevdist_t, elevdist_da ); singlePath = TRUE; for (i2=i1; i2trk) { DYNARR_APPEND( elevdist_t, elevdist_da, 10 ); w = &elevdist(elevdist_da.cnt-1); w->dist = n2->dist; w->elev = n2->elev; w->dist += GetTrkLength( n2->trk, n2->ep, -1 ); n2->trk = NULL; d1 += w->dist; if ( ! ( ( n1->ep == n2->ep && n1->ep2 == n2->ep2 ) || ( n1->ep == n2->ep2 && n1->ep2 == n2->ep ) ) ) singlePath = FALSE; } } /* Also check my EPs */ for (ep=0; eptrk && ep==n2->ep) break; } if (i2 >= fork_da.cnt) { DYNARR_APPEND( elevdist_t, elevdist_da, 10 ); w = &elevdist(elevdist_da.cnt-1); w->elev = GetTrkEndElevHeight(trk,ep); w->dist = GetTrkLength( trk, ep, -1 ); d1 += w->dist; singlePath = FALSE; } } n3 = &fork(forkCnt); n3->trk = trk; if ( singlePath == TRUE ) { /* only 2 EP are connected to DefElevs, treat other EPs as ignored */ n3->ep = n1->ep; n3->ep2 = n1->ep2; } else { e = ComputeWeightedElev( d1 ); SetTrkOnElevPath( trk, ELEV_FORK, e ); /* 3 or more EPs are to DefElevs */ n3->ep = -1; LOG( log_fillElev, 2, ( " 1 T%d E%0.3f\n", GetTrkIndex(trk), e ) ) } forkCnt++; } } LOG( log_fillElev, 1, ( "%s: computeForkElev [%d] (%ld)\n", elevPrefix, forkCnt, wGetTimer()-time0 ) ) } /* * DYNAMIC ELEVATION COMPUTATION * * Step 4: Compute the elevation of tracks on the Shortest Path between Forks and DefElev's */ static void RedrawCompGradeElev( track_p trk, EPINX_T ep ) { int mode; coOrd pos; track_p trk1; mode = GetTrkEndElevMode( trk, ep ); if ( mode == ELEV_COMP || mode == ELEV_GRADE ) { pos = GetTrkEndPos( trk, ep ); if (!OFF_MAIND( pos, pos ) ) { trk1 = GetTrkEndTrk( trk, ep ); if ( (trk1=GetTrkEndTrk(trk,ep)) && GetTrkIndex(trk1)trk && n1->ep >= 0 ) { /* no: make sure we are on the path */ if ( n1->ep == ep1 ) ep2 = n1->ep2; else if ( n1->ep2 == ep1 ) ep2 = n1->ep; else return; trkN = GetTrkEndTrk(trk1,ep2); epN = GetEndPtConnectedToMe( trkN, trk1 ); break; } } if ( i2 >= forkCnt ) return; } d2 = GetTrkLength( trk1, ep1, ep2 )/2.0; d1 += d2; elistAppend( trk1, ep1, d1 ); d1 += d2; trk1 = trkN; ep1 = epN; } nextStep: ASSERT(d1>0.0); e1 = (e1-e)/d1; trk1 = NULL; i3 = elist_da.cnt; for (i2=0; i2ep >= 0 ) continue; trk = n1->trk; GetTrkOnElevPath( trk, &e ); cnt = GetTrkEndPtCnt(trk); for (ep=0; eptrk, &e )) /* propogateForkElevs beat us to it */ continue; e = GetTrkEndElevHeight( dep->trk, dep->ep ); PropogateForkElev( dep->trk, dep->ep, 0, e ); } LOG( log_fillElev, 1, ( "%s: propogateDefElevs [%d] (%ld)\n", elevPrefix, defelev_da.cnt, wGetTimer()-time0 ) ) } /* * DYNAMIC ELEVATION COMPUTATION * * Step 5: Remaining tracks form either Islands connected to zero or more DefElev, Forks * or Branches (Pivots). The elevation of these tracks is determined by the distance to * the Pivots. Tracks which are not connected to Pivots are labeled 'Alone' and have no * elevation. */ typedef struct { track_p trk; coOrd pos; DIST_T elev; } pivot_t; static dynArr_t pivot_da; #define pivot(N) DYNARR_N(pivot_t, pivot_da, N) static void SurveyIsland( track_p trk, BOOL_T stopAtElevPath ) /* Find the tracks in this island and the pivots of this island * Outputs: * elist_da - tracks in the island * pivot_da - pivots connecting island to tracks with some elev */ { int i1; track_p trk1; EPINX_T ep, cnt; pivot_t * pp; coOrd hi, lo; DIST_T elev; DYNARR_RESET( elist_t, elist_da ); DYNARR_RESET( pivot_t, pivot_da ); ClrAllTrkBits( TB_PROCESSED ); elistAppend( trk, 0, 0 ); SetTrkBits( trk, TB_PROCESSED ); for ( i1=0; i1 < elist_da.cnt; i1++ ) { trk = elist(i1).trk; if ( GetTrkIndex(trk) == checkTrk ) printf( "found in island\n" ); cnt = GetTrkEndPtCnt(trk); for ( ep=0; eptrk = trk; pp->pos = GetTrkEndPos(trk,ep); pp->elev = GetTrkEndElevHeight(trk,ep); } else if ( stopAtElevPath && trk1 && GetTrkOnElevPath(trk1, &elev) ) { DYNARR_APPEND( pivot_t, pivot_da, 10 ); pp = &pivot(pivot_da.cnt-1); pp->trk = trk1; GetBoundingBox( trk1, &hi, &lo ); pp->pos.x = (hi.x+lo.x)/2.0; pp->pos.y = (hi.y+lo.y)/2.0; pp->elev = elev; } else if ( trk1 && !(GetTrkBits(trk1)&TB_PROCESSED) ) { SetTrkBits( trk1, TB_PROCESSED ); elistAppend( trk1, 0, 0 ); } } } ClrAllTrkBits( TB_PROCESSED ); } static void ComputeIslandElev( track_p trk ) /* Compute elev of tracks connected to 'trk' * An island is the set of tracks bounded by a DefElev EP or a track already on ElevPath * Inputs: * Working: * elist_da * Outputs: * pivot_da - list of tracks on boundary of Island */ { int i1, i2; coOrd hi, lo, pos; pivot_t * pp; DIST_T elev; DIST_T totalDist; elevdist_t * w; int mode; EPINX_T ep, epCnt; SurveyIsland( trk, TRUE ); for ( i1=0; i1 < elist_da.cnt; i1++ ) { trk = elist(i1).trk; if ( !IsTrack(trk) ) continue; mode = ELEV_ISLAND; if (pivot_da.cnt == 0) { elev = 0; mode = ELEV_ALONE; } else if (pivot_da.cnt == 1) { elev = pivot(0).elev; } else { if ( !GetCurveMiddle( trk, &pos ) ) { GetBoundingBox( trk, &hi, &lo ); pos.x = (hi.x+lo.x)/2.0; pos.y = (hi.y+lo.y)/2.0; } DYNARR_RESET( elevdist_t, elevdist_da ); totalDist = 0; for ( i2=0; i2elev = pp->elev; w->dist = FindDistance( pos, pp->pos ); totalDist += w->dist; } elev = ComputeWeightedElev( totalDist ); } SetTrkOnElevPath( trk, mode, elev ); LOG( log_fillElev, 1, ( " 3 T%d E%0.3f\n", GetTrkIndex(trk), elev ) ) } for ( i1=0; i1 0 ) { track_p trk; DIST_T elev; for ( trk=NULL; TrackIterate( &trk ); ) { printf( "T%4.4d = ", GetTrkIndex(trk) ); if ( GetTrkOnElevPath( trk, &elev ) ) printf( "%d:%0.2f\n", GetTrkElevMode(trk), elev ); else printf( "noelev\n" ); EPINX_T ep; int mode; for ( ep=0; ep0.1) ErrorMessage( MSG_JOIN_DIFFER_ELEV, PutDim(diff) ); } else if (mode0 == ELEV_DEF) { mode0 = GetTrkEndElevUnmaskedMode( trk0, ep0 ); elev = GetTrkEndElevHeight( trk0, ep0 ); } else if (mode1 == ELEV_DEF) { mode1 = GetTrkEndElevUnmaskedMode( trk1, ep1 ); elev = GetTrkEndElevHeight( trk1, ep1 ); } else if (mode0 == ELEV_STATION) { station = GetTrkEndElevStation( trk0, ep0 ); } else if (mode1 == ELEV_STATION) { station = GetTrkEndElevStation( trk1, ep1 ); mode0 = mode1; } else if (mode0 == ELEV_GRADE) { ; } else if (mode1 == ELEV_GRADE) { mode0 = mode1; } else if (mode0 == ELEV_COMP) { ; } else if (mode1 == ELEV_COMP) { mode0 = mode1; } else { ; } SetTrkEndElev( trk0, ep0, mode0, elev, station ); SetTrkEndElev( trk1, ep1, mode0, elev, station ); } if (update) { needElevUpdate = TRUE; ClrTrkElev( trk0 ); ClrTrkElev( trk1 ); } } EXPORT void UpdateTrkEndElev( track_p trk, EPINX_T ep, int newMode, DIST_T newElev, char * newStation ) { int oldMode; DIST_T oldElev; char * oldStation; BOOL_T changed = TRUE; track_p trk1; EPINX_T ep1; oldMode = GetTrkEndElevUnmaskedMode( trk, ep ); if ( (oldMode&ELEV_MASK) == (newMode&ELEV_MASK) ) { switch ( (oldMode&ELEV_MASK) ) { case ELEV_DEF: oldElev = GetTrkEndElevHeight( trk, ep ); if ( oldElev == newElev ) { if ( oldMode == newMode ) return; changed = FALSE; } break; case ELEV_STATION: oldStation = GetTrkEndElevStation( trk, ep ); if ( strcmp( oldStation, newStation ) == 0 ) { return; } break; default: return; } } else { changed = TRUE; if ( (newMode&ELEV_MASK)==ELEV_DEF || (oldMode&ELEV_MASK)==ELEV_DEF || (newMode&ELEV_MASK)==ELEV_IGNORE || (oldMode&ELEV_MASK)==ELEV_IGNORE ) changed = TRUE; } UndoModify( trk ); if ( (trk1 = GetTrkEndTrk( trk, ep )) ) { UndoModify( trk1 ); } DrawEndPt2( &mainD, trk, ep, drawColorWhite ); SetTrkEndElev( trk, ep, newMode, newElev, newStation ); DrawEndPt2( &mainD, trk, ep, drawColorBlack ); if ( changed ) { ClrTrkElev( trk ); if ( trk1 ) { ep1 = GetEndPtConnectedToMe( trk1, trk ); ClrTrkElev( trk1 ); } UpdateAllElevations(); } } static void SetTrkOnElevPath( track_p trk, int mode, DIST_T elev ) { BOOL_T redraw = FALSE; int oldMode = GetTrkElevMode( trk ); DIST_T oldElev; coOrd hi, lo; if ( !GetTrkOnElevPath( trk, &oldElev ) ) oldElev = 0.0; GetBoundingBox( trk, &hi, &lo ); if ((labelEnable&LABELENABLE_TRACK_ELEV) && labelScale >= mainD.scale && (! OFF_MAIND( lo, hi ) ) && (GetTrkVisible(trk) || drawTunnel!=0/*DRAW_TUNNEL_NONE*/) && GetLayerVisible(GetTrkLayer(trk)) ) redraw = TRUE; if ( (GetTrkBits(trk)&TB_ELEVPATH) && (oldElev == elev && oldMode == mode) ) return; if ( redraw && (GetTrkBits(trk)&TB_ELEVPATH)) DrawTrackElev( trk, &mainD, FALSE ); SetTrkElev( trk, mode, elev ); if ( redraw ) DrawTrackElev( trk, &mainD, TRUE ); } EXPORT void DrawTrackElev( track_cp trk, drawCmd_p d, BOOL_T drawIt ) { coOrd pos; wFont_p fp; wDrawColor color=(wDrawColor)0; DIST_T elev; coOrd lo, hi; if ( (!IsTrack(trk)) || (!(labelEnable&LABELENABLE_TRACK_ELEV)) || (d == &mapD) || (labelScale < d->scale) || (!GetTrkOnElevPath( trk, &elev )) || ((GetTrkBits(trk)&TB_ELEVPATH) == 0) || (d->options & DC_SIMPLE) != 0 ) return; if ( !GetCurveMiddle( trk, &pos ) && !GetCornuMiddle(trk, &pos) && !GetBezierMiddle(trk, &pos)) { GetBoundingBox( trk, &hi, &lo ); pos.x = (hi.x+lo.x)/2.0; pos.y = (hi.y+lo.y)/2.0; } if ( d==&mainD && OFF_MAIND( pos, pos ) ) return; switch ( GetTrkElevMode(trk) ) { case ELEV_FORK: color = drawColorBlue; break; case ELEV_BRANCH: color = drawColorPurple; break; case ELEV_ISLAND: color = drawColorGold; break; case ELEV_ALONE: return; } if ( !drawIt ) color = wDrawColorWhite; sprintf( message, "%s", FormatDistance(elev)); fp = wStandardFont( F_HELV, FALSE, FALSE ); DrawBoxedString( BOX_INVERT, d, pos, message, fp, (wFontSize_t)descriptionFontSize, color, 0 ); }