diff options
Diffstat (limited to 'app/bin/trkendpt.c')
-rw-r--r-- | app/bin/trkendpt.c | 648 |
1 files changed, 648 insertions, 0 deletions
diff --git a/app/bin/trkendpt.c b/app/bin/trkendpt.c new file mode 100644 index 0000000..a9ca40b --- /dev/null +++ b/app/bin/trkendpt.c @@ -0,0 +1,648 @@ +/* + * $Header: $ + */ + +/* XTrkCad - Model Railroad CAD + * Copyright (C) 2022 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 "common.h" +#include "common.h" +#include "common-ui.h" +#include "fileio.h" +#include "param.h" +#include "track.h" +#include "trkendpt.h" +#include "trkendptx.h" +#include "draw.h" + + +/************************************************************************ + * Basic Access + */ + +EXPORT CSIZE_T EndPtSize( + EPINX_T epCnt ) +{ + return epCnt * sizeof *(trkEndPt_p)NULL; +} + + +EXPORT coOrd GetEndPtPos( trkEndPt_p epp ) +{ + return epp->pos; +} + + +EXPORT ANGLE_T GetEndPtAngle( trkEndPt_p epp ) +{ + return epp->angle; +} + + +EXPORT track_p GetEndPtTrack( trkEndPt_p epp ) +{ + return epp->track; +} + + +EXPORT void SetEndPt( trkEndPt_p epp, coOrd pos, ANGLE_T angle ) +{ + epp->pos = pos; + epp->angle = angle; +} + + +EXPORT EPINX_T GetEndPtEndPt( trkEndPt_p epp ) +{ + return (EPINX_T)(epp->index); +} + + +EXPORT TRKINX_T GetEndPtIndex( trkEndPt_p epp ) +{ + return (TRKINX_T)(epp->index); +} + + +EXPORT void SetEndPtTrack( trkEndPt_p epp, track_p trk ) +{ + epp->track = trk; + epp->index = -1; +} + + +EXPORT void SetEndPtEndPt( trkEndPt_p epp, EPINX_T ep ) +{ + epp->index = ep; +} + + +EXPORT trkEndPt_p EndPtIndex( trkEndPt_p epp, EPINX_T ep ) +{ + return epp+ep; +} + + +/************************************************************************ + * Temp End Points + */ + +static dynArr_t tempEndPts_da; + +EXPORT void TempEndPtsReset( void ) +{ + DYNARR_RESET( trkEndPt_t, tempEndPts_da ); +} + + +EXPORT void TempEndPtsSet( EPINX_T ep ) +{ + DYNARR_SET( trkEndPt_t, tempEndPts_da, ep ); + memset( &DYNARR_N(trkEndPt_t,tempEndPts_da,0), 0, + ep * sizeof *(trkEndPt_p)NULL ); +} + + +EXPORT EPINX_T TempEndPtsCount( void ) +{ + return tempEndPts_da.cnt; +} + + +EXPORT trkEndPt_p TempEndPt( EPINX_T ep ) +{ + CHECK( ep < tempEndPts_da.cnt ); + return &DYNARR_N( trkEndPt_t, tempEndPts_da, ep ); +} + + +#ifndef MKTURNOUT + +EXPORT trkEndPt_p TempEndPtsAppend( void ) +{ + DYNARR_APPEND( trkEndPt_t, tempEndPts_da, 10 ); + trkEndPt_p epp = &DYNARR_LAST( trkEndPt_t, tempEndPts_da ); + memset( epp, 0, sizeof *epp ); + return epp; +} + + +EXPORT void SwapEndPts( + trkEndPt_p epp, + EPINX_T ep0, + EPINX_T ep1 ) +{ + trkEndPt_t tempEP; + tempEP = epp[ep0]; + epp[ep0] = epp[ep1]; + epp[ep1] = tempEP; +} + + +/************************************************************************ + * Track level access + */ + +EXPORT void SetTrkEndPoint( track_p trk, EPINX_T ep, coOrd pos, ANGLE_T angle ) +{ + CHECK( ep < GetTrkEndPtCnt(trk) ); + // check setTrkEndPoint: endPt is not connected + CHECK( GetEndPtTrack( GetTrkEndPt( trk, ep ) ) == NULL ); + SetEndPt( GetTrkEndPt( trk, ep ), pos, angle ); +} + + +EXPORT void SetTrkEndPointSilent( track_p trk, EPINX_T ep, coOrd pos, + ANGLE_T angle ) +{ + CHECK( ep < GetTrkEndPtCnt(trk) ); + SetEndPt( GetTrkEndPt( trk, ep ), pos, angle ); +} + + +EXPORT coOrd GetTrkEndPos( track_p trk, EPINX_T ep ) +{ + CHECK( ep < GetTrkEndPtCnt(trk) ); + return GetTrkEndPt(trk,ep)->pos; +} + + +EXPORT ANGLE_T GetTrkEndAngle( track_p trk, EPINX_T ep ) +{ + CHECK( ep < GetTrkEndPtCnt(trk) ); + return GetTrkEndPt(trk,ep)->angle; +} + + +EXPORT track_p GetTrkEndTrk( track_p trk, EPINX_T ep ) +{ + CHECK( ep < GetTrkEndPtCnt(trk) ); + return GetTrkEndPt(trk,ep)->track; +} + + +EXPORT long GetTrkEndOption( track_p trk, EPINX_T ep ) +{ + CHECK( ep < GetTrkEndPtCnt(trk) ); + return GetTrkEndPt(trk,ep)->option; +} + + +EXPORT long SetTrkEndOption( track_p trk, EPINX_T ep, long option ) +{ + CHECK( ep < GetTrkEndPtCnt(trk) ); + return GetTrkEndPt(trk,ep)->option = option; +} + + +/************************************************************************ + * Elevations + */ + +EXPORT void SetTrkEndElev( track_p trk, EPINX_T ep, int option, DIST_T height, + char * station ) +{ + track_p trk1; + EPINX_T ep1; + trkEndPt_p epp = GetTrkEndPt( trk, ep ); + epp->elev.option = option; + epp->elev.cacheSet = FALSE; + if (EndPtIsDefinedElev(trk,ep)) { + epp->elev.u.height = height; + } else if (EndPtIsStationElev(trk,ep)) { + if (station == NULL) { + station = ""; + } + epp->elev.u.name = MyStrdup(station); + } + if ( (trk1=GetTrkEndTrk(trk, ep)) != NULL ) { + ep1 = GetEndPtConnectedToMe( trk1, trk ); + if (ep1 >= 0) { + trkEndPt_p epp1 = GetTrkEndPt( trk1, ep1 ); + epp1->elev.option = option; + epp1->elev.u.height = height; + if (EndPtIsDefinedElev(trk1,ep1)) { + epp1->elev.u.height = height; + } else if (EndPtIsStationElev(trk,ep)) { + epp1->elev.u.name = MyStrdup(station); + } + } + } +} + + +EXPORT void GetTrkEndElev( track_p trk, EPINX_T e, int *option, DIST_T *height ) +{ + trkEndPt_p epp = GetTrkEndPt( trk, e ); + *option = epp->elev.option; + *height = epp->elev.u.height; +} + + +EXPORT int GetTrkEndElevUnmaskedMode( track_p trk, EPINX_T e ) +{ + trkEndPt_p epp = GetTrkEndPt( trk, e ); + return epp->elev.option; +} + + +EXPORT int GetTrkEndElevMode( track_p trk, EPINX_T e ) +{ + trkEndPt_p epp = GetTrkEndPt( trk, e ); + return epp->elev.option&ELEV_MASK; +} + + +EXPORT DIST_T GetTrkEndElevHeight( track_p trk, EPINX_T e ) +{ + CHECK( EndPtIsDefinedElev(trk,e) ); + trkEndPt_p epp = GetTrkEndPt( trk, e ); + return epp->elev.u.height; +} + + +EXPORT void ClrEndPtElevCache( + EPINX_T epCnt, + trkEndPt_p epPts ) +{ + for ( EPINX_T ep = 0; ep < epCnt; ep++ ) { + epPts[ep].elev.cacheSet = FALSE; + } +} + + +static BOOL_T bCacheElev = TRUE; + +EXPORT BOOL_T GetTrkEndElevCachedHeight (track_p trk, EPINX_T e, + DIST_T * height, DIST_T * grade) +{ + if ( ! bCacheElev ) { + return FALSE; + } + trkEndPt_p epp = GetTrkEndPt( trk, e ); + if (epp->elev.cacheSet) { + *height = epp->elev.cachedElev; + *grade = epp->elev.cachedGrade; + return TRUE; + } + return FALSE; +} + +EXPORT void SetTrkEndElevCachedHeight ( track_p trk, EPINX_T e, DIST_T height, + DIST_T grade) +{ + trkEndPt_p epp = GetTrkEndPt( trk, e ); + epp->elev.cachedElev = height; + epp->elev.cachedGrade = grade; + epp->elev.cacheSet = TRUE; +} + + +EXPORT char * GetTrkEndElevStation( track_p trk, EPINX_T e ) +{ + CHECK( EndPtIsStationElev(trk,e) ); + trkEndPt_p epp = GetTrkEndPt( trk, e ); + if ( epp->elev.u.name == NULL ) { + return ""; + } else { + return epp->elev.u.name; + } +} + + +EXPORT void DrawEndElev( drawCmd_p d, track_p trk, EPINX_T ep, + wDrawColor color ) +{ + coOrd pp; + wFont_p fp; + elev_t * elev; + track_p trk1; + DIST_T elev0, grade; + ANGLE_T a=0; + int style = BOX_BOX_BACKGROUND; + BOOL_T gradeOk = TRUE; + char *elevStr; + + if ((labelEnable&LABELENABLE_ENDPT_ELEV)==0) { + return; + } + elev = &GetTrkEndPt(trk,ep)->elev; + if ( (elev->option&ELEV_MASK)==ELEV_NONE || + (elev->option&ELEV_VISIBLE)==0 ) { + return; + } + if ( (trk1=GetTrkEndTrk(trk,ep)) && GetTrkIndex(trk1)<GetTrkIndex(trk) ) { + return; + } + + fp = wStandardFont( F_HELV, FALSE, FALSE ); + pp = GetTrkEndPos( trk, ep ); + switch ((elev->option&ELEV_MASK)) { + case ELEV_COMP: + case ELEV_GRADE: + if ( color == wDrawColorWhite ) { + elev0 = grade = elev->u.height; + } else if ( !ComputeElev( trk, ep, FALSE, &elev0, &grade, FALSE ) ) { + elev0 = grade = 0; + gradeOk = FALSE; + } + if ((elev->option&ELEV_MASK)==ELEV_COMP) { + elevStr = FormatDistance(elev0); + elev->u.height = elev0; + } else if (gradeOk) { + sprintf( message, "%0.1f%%", round(fabs(grade*100.0)*10)/10 ); + elevStr = message; + a = GetTrkEndAngle( trk, ep ); + style = BOX_ARROW_BACKGROUND; + if (grade <= -0.001) { + a = NormalizeAngle( a+180.0 ); + } else if ( grade < 0.001 ) { + style = BOX_BOX_BACKGROUND; + } + elev->u.height = grade; + } else { + elevStr = "????%%"; + } + break; + case ELEV_DEF: + elevStr = FormatDistance( elev->u.height); + break; + case ELEV_STATION: + elevStr = elev->u.name; + break; + default: + return; + } + coOrd startLine = pp, endLine = pp; + pp.x += elev->doff.x; + pp.y += elev->doff.y; + if (color==drawColorPreviewSelected) { + Translate(&endLine,pp,FindAngle(pp,startLine),descriptionFontSize/d->dpi); + DrawLine( d, startLine, endLine, 0, color ); + } + DrawBoxedString( style, d, pp, elevStr, fp, (wFontSize_t)descriptionFontSize, + color, a ); + +} + + +/************************************************************************ + * Descriptions + */ + +EXPORT DIST_T EndPtDescriptionDistance( + coOrd pos, + track_p trk, + EPINX_T ep, + coOrd *dpos, + BOOL_T show_hidden, + BOOL_T * hidden) +{ + elev_t *e; + coOrd pos1; + track_p trk1; + *dpos = pos; + if (hidden) { *hidden = FALSE; } + e = &GetTrkEndPt(trk,ep)->elev; + if ((e->option&ELEV_MASK)==ELEV_NONE) { + return DIST_INF; + } + if (((e->option&ELEV_VISIBLE)==0) && !show_hidden) { + return DIST_INF; + } + if ((trk1=GetTrkEndTrk(trk,ep)) && GetTrkIndex(trk1)<GetTrkIndex(trk)) { + return DIST_INF; + } + if ((e->option&ELEV_VISIBLE)==0) { //Hidden - disregard offset + if (hidden) { *hidden = TRUE; } + return FindDistance( GetTrkEndPos(trk,ep), pos ); + } + /*REORIGIN( pos1, e->doff, GetTrkEndPos(trk,ep), GetTrkEndAngle(trk,ep) );*/ + pos1 = GetTrkEndPos(trk,ep); + coOrd tpos = pos1; + pos1.x += e->doff.x; + pos1.y += e->doff.y; + *dpos = pos1; + if (hidden) { *hidden = !(e->option&ELEV_VISIBLE); } + if (FindDistance(tpos,pos)<FindDistance( pos1, pos )) { + return FindDistance(tpos,pos); + } + return FindDistance( pos1, pos ); +} + + +EXPORT STATUS_T EndPtDescriptionMove( + track_p trk, + EPINX_T ep, + wAction_t action, + coOrd pos ) +{ + static coOrd p0; +// static coOrd p1; + elev_t *e; + track_p trk1; + + e = &GetTrkEndPt(trk,ep)->elev; + switch (action) { + case C_DOWN: + p0 = GetTrkEndPos(trk,ep); +// p1 = pos; + e->option |= ELEV_VISIBLE; //Make sure we make visible + DrawEndElev( &mainD, trk, ep, wDrawColorWhite ); + /*no break*/ + case C_MOVE: + case C_UP: +// p1 = pos; + e->doff.x = (pos.x-p0.x); + e->doff.y = (pos.y-p0.y); + if ((trk1=GetTrkEndTrk(trk,ep))) { + EPINX_T ep1 = GetEndPtConnectedToMe(trk1,trk); + trkEndPt_p epp = GetTrkEndPt( trk1, ep1 ); +// e1 = &trk1->endPt[GetEndPtConnectedToMe(trk1,trk)].elev; + epp->elev.doff = e->doff; + } + if ( action == C_UP ) { + wDrawColor color = GetTrkColor( trk, &mainD ); + DrawEndElev( &mainD, trk, ep, color ); + } + return action==C_UP?C_TERMINATE:C_CONTINUE; + + case C_REDRAW: + DrawEndElev( &tempD, trk, ep, drawColorPreviewSelected ); + break; + } + return C_CONTINUE; +} + + +/************************************************************************ + * Read/Write End Points + */ + +EXPORT BOOL_T GetEndPtArg( + char * cp, + char type, + BOOL_T bImprovedEnds ) +{ + long option; + long option2; + trkEndPt_p e = TempEndPtsAppend(); + FLOAT_T ignoreFloat; + + if (type == SEG_CONEP) { + if ( !GetArgs( cp, "dc", &e->index, &cp ) ) { + /*??*/return FALSE; + } + } else { + e->index = -1; + } + if ( !GetArgs( cp, "pfc", + &e->pos, &e->angle, &cp) ) { + /*??*/return FALSE; + } + e->elev.option = 0; + e->elev.u.height = 0.0; + e->elev.doff = zero; + e->option = 0; + if (bImprovedEnds) { //E4 and T4 + if (!GetArgs( cp, "lpc", &option, &e->elev.doff, &cp )) { + /*??*/return FALSE; + } + switch (option&ELEV_MASK) { + case ELEV_STATION: + GetArgs( cp, "qc", &e->elev.u.name, &cp); + break; + default: + GetArgs( cp, "fc", &e->elev.u.height, &cp); //First height + } + DIST_T height2; + if (!GetArgs( cp, "flLlc", &height2, &option2, &e->elev.option, &e->option, + &cp ) ) { + return FALSE; + } + if (option2) { e->elev.option |= ELEV_VISIBLE; } + GetArgs(cp, "fc", &ignoreFloat, &cp); + return TRUE; + } + if ( cp != NULL ) { + if (paramVersion < 7) { + GetArgs( cp, "dfp", &e->elev.option, &e->elev.u.height, &e->elev.doff, &cp ); + /*??*/return TRUE; + } + GetArgs( cp, "lpc", &option, &e->elev.doff, &cp ); + e->option = option >> 8; + e->elev.option = (int)(option&0xFF); + if ( (e->elev.option&ELEV_MASK) != ELEV_NONE ) { + switch (e->elev.option&ELEV_MASK) { + case ELEV_DEF: + GetArgs( cp, "fc", &e->elev.u.height, &cp ); + break; + case ELEV_STATION: + GetArgs( cp, "qc", &e->elev.u.name, &cp ); + /*??*/break; + default: + ; + } + } + } + return TRUE; +} + + +EXPORT BOOL_T bWriteEndPtDirectIndex = FALSE; +EXPORT BOOL_T bWriteEndPtExporting = FALSE; + + +EXPORT BOOL_T WriteEndPt( FILE * f, track_cp trk, EPINX_T ep ) +{ + trkEndPt_p endPt = GetTrkEndPt(trk,ep); + BOOL_T rc = TRUE; + long option; + + CHECK ( endPt ); + if (bWriteEndPtDirectIndex && endPt->index > 0) { + rc &= fprintf( f, "\tT4 %ld ", endPt->index )>0; + } else if (endPt->track == NULL || + ( bWriteEndPtExporting && !GetTrkSelected(endPt->track) ) ) { + rc &= fprintf( f, "\tE4 " )>0; + } else { + rc &= fprintf( f, "\tT4 %d ", GetTrkIndex(endPt->track) )>0; + } + rc &= fprintf( f, "%0.6f %0.6f %0.6f", endPt->pos.x, endPt->pos.y, + endPt->angle )>0; + option = (endPt->option<<8) | (endPt->elev.option&0xFF); + if ( option != 0 ) { + rc &= fprintf( f, " %ld %0.6f %0.6f", option, endPt->elev.doff.x, + endPt->elev.doff.y )>0; + switch ( endPt->elev.option&ELEV_MASK ) { + case ELEV_DEF: + rc &= fprintf( f, " %0.6f ", endPt->elev.u.height )>0; + break; + case ELEV_STATION: + rc &= fprintf( f, " \"%s\" ", PutTitle( endPt->elev.u.name ) )>0; + break; + default: + rc &= fprintf( f, " 0.0 ")>0; + } + } else { + rc &= fprintf( f, " 0 0.0 0.0 0.0 ")>0; + } + if ((endPt->elev.option&ELEV_MASK) == ELEV_DEF) { + rc &= fprintf( f, "%0.6f ",endPt->elev.u.height)>0; + } else { + rc &= fprintf( f, "0.0 ")>0; + } + long elevVisible = (endPt->elev.option&ELEV_VISIBLE)?1:0; + long elevType = endPt->elev.option&ELEV_MASK; + long gapType = endPt->option; + rc &= fprintf( f, "%ld %ld %ld ", elevVisible, elevType, gapType)>0; + rc &= fprintf( f, "%0.6f ", GetTrkElev( trk ) )>0; + rc &= fprintf( f, "\n" )>0; + return rc; +} + + +/************************************************************************ +* Read/Write End Points +*/ + +wBool_t CompareEndPt( + char * cp, + track_p trk1, + track_p trk2, + EPINX_T ep ) +{ + trkEndPt_p epp1 = GetTrkEndPt( trk1, ep ); + trkEndPt_p epp2 = GetTrkEndPt( trk2, ep ); + REGRESS_CHECK_POS( "Pos", epp1, epp2, pos ) + REGRESS_CHECK_ANGLE( "Angle", epp1, epp2, angle ) + // Actual EP connection + int inx1 = -1; + if ( epp1->track ) { + inx1 = GetTrkIndex( epp1->track ); + } + // Expected EP connection. endPt[inx].track is not resolved + int inx2 = epp2->index; + if ( inx1 != inx2 ) { + sprintf( cp, "Index: Actual` %d, Expected %d\n", inx1, inx2 ); + return FALSE; + } + REGRESS_CHECK_INT( "Option", epp1, epp2, option ) + return TRUE; +} +#endif |