/** \file misc2.c * Management of information about scales and gauges plus rprintf. */ /* 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 #include #ifndef WINDOWS #include #include #endif #ifdef HAVE_MALLOC_H #include #endif #include #include #include #include #include #include "cjoin.h" #include "common.h" #include "compound.h" #include "custom.h" #include "draw.h" #include "fileio.h" #include "i18n.h" #include "layout.h" #include "messages.h" #include "misc.h" #include "param.h" #include "track.h" #include "utility.h" EXPORT long units = 0; /**< measurement units: 0 = English, 1 = metric */ EXPORT long checkPtInterval = 10; EXPORT long autosaveChkPoints = 2; EXPORT DIST_T curScaleRatio; EXPORT char * curScaleName; EXPORT DIST_T trackGauge; EXPORT long labelScale = 8; EXPORT long labelEnable = (LABELENABLE_ENDPT_ELEV|LABELENABLE_CARS); EXPORT long labelWhen = 2; EXPORT long colorTrack = 0; EXPORT long colorDraw = 0; EXPORT long constrainMain = 0; EXPORT long hideSelectionWindow = 0; EXPORT long angleSystem = 0; EXPORT DIST_T minLength = 0.1; EXPORT DIST_T connectDistance = 0.1; EXPORT ANGLE_T connectAngle = 1.0; EXPORT long twoRailScale = 16; EXPORT long mapScale = 64; EXPORT long liveMap = 0; EXPORT long preSelect = 0; /**< default command 0 = Describe 1 = Select */ EXPORT long listLabels = 7; EXPORT long layoutLabels = 1; EXPORT long descriptionFontSize = 72; EXPORT long enableListPrices = 1; EXPORT void ScaleLengthEnd(void); static BOOL_T SetScaleDescGauge(SCALEINX_T scaleInx); /**************************************************************************** * * RPRINTF * */ #define RBUFF_SIZE (8192) static char rbuff[RBUFF_SIZE+1]; static int roff; static int rbuff_record = 0; EXPORT void Rdump( FILE * outf ) { fprintf( outf, "Record Buffer:\n" ); rbuff[RBUFF_SIZE] = '\0'; fprintf( outf, "%s", rbuff+roff ); rbuff[roff] = '\0'; fprintf( outf, "%s", rbuff ); memset( rbuff, 0, sizeof rbuff ); roff = 0; } EXPORT void Rprintf( char * format, ... ) { static char buff[STR_SIZE]; char * cp; va_list ap; va_start( ap, format ); vsprintf( buff, format, ap ); va_end( ap ); if (rbuff_record >= 1) lprintf( buff ); for ( cp=buff; *cp; cp++ ) { rbuff[roff] = *cp; roff++; if (roff>=RBUFF_SIZE) roff=0; } } /**************************************************************************** * * CHANGE NOTIFICATION * */ static changeNotificationCallBack_t changeNotificationCallBacks[20]; static int changeNotificationCallBackCnt = 0; EXPORT void RegisterChangeNotification( changeNotificationCallBack_t action ) { changeNotificationCallBacks[changeNotificationCallBackCnt] = action; changeNotificationCallBackCnt++; } EXPORT void DoChangeNotification( long changes ) { int inx; for (inx=0;inxscale; } EXPORT DIST_T GetScaleTrackGauge( SCALEINX_T si ) { return scaleInfo(si).gauge; } EXPORT DIST_T GetScaleRatio( SCALEINX_T si ) { return scaleInfo(si).ratio; } EXPORT char * GetScaleName( SCALEINX_T si ) { if ( si == -1 ) return "DEMO"; if ( si == SCALE_ANY ) return "*"; else if ( si < 0 || si >= scaleInfo_da.cnt ) return "Unknown"; else return scaleInfo(si).scale; } EXPORT void GetScaleEasementValues( DIST_T * R, DIST_T * L ) { wIndex_t i; for (i=0;i<3;i++) { *R++ = curScale->R[i]; *L++ = curScale->L[i]; } } EXPORT tieData_p GetScaleTieData( SCALEINX_T si ) { scaleInfo_p s; DIST_T defLength; if ( si == -1 ) return &tieData_demo; else if ( si < 0 || si >= scaleInfo_da.cnt ) return &tieData_demo; s = &scaleInfo(si); if ( !s->tieDataValid ) { sprintf( message, "tiedata-%s", s->scale ); defLength = (96.0-54.0)/s->ratio+s->gauge; wPrefGetFloat( message, "length", &s->tieData.length, defLength ); wPrefGetFloat( message, "width", &s->tieData.width, 16.0/s->ratio ); wPrefGetFloat( message, "spacing", &s->tieData.spacing, 2*s->tieData.width ); } return &scaleInfo(si).tieData; } EXPORT char *GetScaleDesc( SCALEDESCINX_T inx ) { return scaleDesc(inx).scaleDesc; } EXPORT char *GetGaugeDesc( SCALEDESCINX_T scaleInx, GAUGEINX_T gaugeInx ) { scaleDesc_t s; gaugeInfo_p g; s = scaleDesc(scaleInx); g = &(DYNARR_N(gaugeInfo_t, s.gauges_da, gaugeInx)); return g->gauge; } void SetScaleGauge(SCALEDESCINX_T desc, GAUGEINX_T gauge) { dynArr_t gauges_da; gauges_da = (scaleDesc(desc)).gauges_da; SetLayoutCurScale(((gaugeInfo_p)gauges_da.ptr)[gauge].scale); } static BOOL_T SetScaleDescGauge(SCALEINX_T scaleInx) { int i, j; char *scaleName = GetScaleName(scaleInx); DIST_T scaleRatio = GetScaleRatio(scaleInx); dynArr_t gauges_da; for (i = 0; i < scaleDesc_da.cnt; i++) { char *t = strchr(scaleDesc(i).scaleDesc, ' '); /* are the first characters (which describe the scale) identical? */ if (!strncmp(scaleDesc(i).scaleDesc, scaleName, t - scaleDesc(i).scaleDesc)) { /* if yes, are we talking about the same ratio */ if (scaleInfo(scaleDesc(i).scale).ratio == scaleRatio) { /* yes, we found the right scale descriptor, so now look for the gauge */ SetLayoutCurScaleDesc( i ); gauges_da = scaleDesc(i).gauges_da; SetLayoutCurGauge(0); for (j = 0; j < gauges_da.cnt; j++) { gaugeInfo_p ptr = &(DYNARR_N(gaugeInfo_t, gauges_da, j)); if (scaleInfo(ptr->scale).gauge == GetScaleTrackGauge(scaleInx)) { SetLayoutCurGauge( j ); break; } } break; } } } return TRUE; } EXPORT SCALEINX_T LookupScale( const char * name ) { wIndex_t si; DIST_T gauge; if ( strcmp( name, "*" ) == 0 ) return SCALE_ANY; for ( si=0; siscale).gauge == GetScaleTrackGauge( scaleInx )) { *gaugeInx = j; break; } } break; } } } return TRUE; } /** * Setup XTrkCad for the newly selected scale/gauge combination. * * \param newScaleInx IN the index of the selected scale/gauge combination */ static void SetScale( SCALEINX_T newScaleInx ) { if (newScaleInx < 0 && newScaleInx >= scaleInfo_da.cnt) { NoticeMessage( MSG_BAD_SCALE_INDEX, _("Ok"), NULL, (int)newScaleInx ); return; } SetLayoutCurScale((SCALEINX_T)newScaleInx ); curScale = &scaleInfo(newScaleInx); trackGauge = curScale->gauge; curScaleRatio = curScale->ratio; curScaleName = curScale->scale; SetLayoutCurScaleDesc( 0 ); SetScaleDescGauge((SCALEINX_T)newScaleInx); if (!inPlayback) wPrefSetString( "misc", "scale", curScaleName ); // now load the minimum radius for the newly selected scale LoadLayoutMinRadiusPref(curScaleName, curScale->R[0]); } /** * Check the new scale value and update the program if a valid scale was passed * * \param newScale IN the name of the new scale * \returns TRUE if valid, FALSE otherwise */ EXPORT BOOL_T DoSetScale( char * newScale ) { SCALEINX_T scale; char * cp; BOOL_T found = FALSE; if ( newScale != NULL ) { cp = newScale+strlen(newScale)-1; while ( *cp=='\n' || *cp==' ' || *cp=='\t' ) cp--; cp[1] = '\0'; while (isspace((unsigned char)*newScale)) newScale++; for (scale = 0; scale 0 ) { for( descInx = 0; descInx < scaleDesc_da.cnt; descInx++ ) { work = scaleDesc(descInx).scale; if( scaleInfo(work).ratio == scaleInfo(scaleInx).ratio ) { if( !strncmp( scaleInfo(work).scale, scaleInfo(scaleInx).scale, strlen(scaleInfo(work).scale))) found = TRUE; } } } if( !found ) { /* if no, add as new scale */ DYNARR_APPEND( scaleDesc_t, scaleDesc_da, 1 ); s = &(scaleDesc( scaleDesc_da.cnt-1 )); s->scale = scaleInx; sprintf( buf, "%s (1/%.1f)", scaleInfo(scaleInx).scale, scaleInfo(scaleInx).ratio ); s->scaleDesc = MyStrdup( buf ); /* initialize the array with standard gauge */ DYNARR_APPEND( gaugeInfo_t, s->gauges_da, 10 ); g = &(DYNARR_N( gaugeInfo_t, s->gauges_da, (s->gauges_da).cnt - 1 )); g->scale = scaleInx; sprintf( buf, "Standard (%.1fmm)", scaleInfo(scaleInx).gauge*25.4 ); g->gauge = MyStrdup( buf ); } else { /* if yes, is this a new gauge to the scale? */ DYNARR_APPEND( gaugeInfo_t, s->gauges_da, 10 ); g = &(DYNARR_N( gaugeInfo_t, s->gauges_da, (s->gauges_da).cnt - 1 )); g->scale = scaleInx; cp = strchr( s->scaleDesc, ' ' ); if( cp ) len = cp - s->scaleDesc; else len = strlen(s->scaleDesc); sprintf( buf, "%s (%.1fmm)", scaleInfo(scaleInx).scale+len, scaleInfo(scaleInx).gauge*25.4 ); g->gauge = MyStrdup( buf ); } } return( TRUE ); } static BOOL_T AddScale( char * line ) { wIndex_t i; BOOL_T rc; DIST_T R[3], X[3], L[3]; DIST_T ratio, gauge; char scale[40]; scaleInfo_p s; if ( (rc=sscanf( line, "SCALE %[^,]," SCANF_FLOAT_FORMAT "," SCANF_FLOAT_FORMAT "", scale, &ratio, &gauge )) != 3) { SyntaxError( "SCALE", rc, 3 ); return FALSE; } for (i=0;i<3;i++) { line = GetNextLine(); if ( (rc=sscanf( line, "" SCANF_FLOAT_FORMAT "," SCANF_FLOAT_FORMAT "," SCANF_FLOAT_FORMAT "", &R[i], &X[i], &L[i] )) != 3 ) { SyntaxError( "SCALE easement", rc, 3 ); return FALSE; } } DYNARR_APPEND( scaleInfo_t, scaleInfo_da, 10 ); s = &scaleInfo(scaleInfo_da.cnt-1); s->scale = MyStrdup( scale ); s->ratio = ratio; s->gauge = gauge; s->index = -1; for (i=0; i<3; i++) { s->R[i] = R[i]/ratio; s->X[i] = X[i]/ratio; s->L[i] = L[i]/ratio; } s->tieDataValid = FALSE; if ( strcmp( scale, "DEMO" ) == 0 ) demoScaleInx = scaleInfo_da.cnt-1; return TRUE; } EXPORT void ScaleLengthIncrement( SCALEINX_T scale, DIST_T length ) { char * cp; int len; if (scaleInfo(scale).length == 0.0) { if (units == UNITS_METRIC) cp = "999.99m SCALE Flex Track"; else cp = "999' 11\" SCALE Flex Track"; len = strlen( cp )+1; if (len > enumerateMaxDescLen) enumerateMaxDescLen = len; } scaleInfo(scale).length += length; } EXPORT void ScaleLengthEnd( void ) { wIndex_t si; int count; DIST_T length; char tmp[STR_SIZE]; FLOAT_T flexLen; long flexUnit; FLOAT_T flexCost; for (si=0; si 0.0) { count = (int)ceil( length / (flexLen/(flexUnit?2.54:1.00))); } EnumerateList( count, flexCost, tmp ); } scaleInfo(si).length = 0; } } EXPORT void LoadScaleList( wList_p scaleList ) { wIndex_t inx; for (inx=0; inxptr; g = s.gauges_da.ptr; wListClear( gaugeList ); /* remove old list in case */ for (inx=0; inxcnt; inx++) { (g[inx]).index = wListAddValue( gaugeList, (g[inx]).gauge, NULL, (void*)(intptr_t)(g[inx]).scale ); } } static void ScaleChange( long changes ) { if (changes & CHANGE_SCALE) { SetScale( GetLayoutCurScale() ); } } /***************************************************************************** * * * */ EXPORT void Misc2Init( void ) { AddParam( "SCALE ", AddScale ); wPrefGetInteger( "draw", "label-when", &labelWhen, labelWhen ); RegisterChangeNotification( ScaleChange ); wPrefGetInteger( "misc", "include same gauge turnouts", &includeSameGaugeTurnouts, 1 ); }