/* * $Header: /home/dmarkle/xtrkcad-fork-cvs/xtrkcad/app/bin/cruler.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "cundo.h" #include "cselect.h" #include "fileio.h" #include "param.h" #include "track.h" #include "misc.h" #define AN_OFF (0) #define AN_FIRST (1) #define AN_SECOND (2) #define AN_ON (3) static struct { STATE_T state; coOrd pos0; coOrd pos1; coOrd pos2; BOOL_T isClose; int modifyingEnd; } An = { AN_OFF, { 0,0 }, { 0,0 } }; void DrawAngle(drawCmd_p d, coOrd p0, coOrd p1, coOrd p2, wDrawColor color) { char msg[512]; trkSeg_t seg; if ((An.state != AN_OFF) && !IsClose(FindDistance(p0,p1))) { seg.type = SEG_STRLIN; seg.lineWidth = 0; seg.color = wDrawColorBlack; seg.u.l.pos[0] = p0; seg.u.l.pos[1] = p1; DrawSegs(d,zero,0.0,&seg,1,trackGauge,color); if (!(IsClose(FindDistance(p0,p2)))) { seg.type = SEG_STRLIN; seg.lineWidth = 0; seg.color = wDrawColorBlack; seg.u.l.pos[0] = p0; seg.u.l.pos[1] = p2; DrawSegs(d,zero,0.0,&seg,1,trackGauge,color); DIST_T r = min(FindDistance(p0,p2),FindDistance(p0,p1))/2; ANGLE_T a = DifferenceBetweenAngles(FindAngle(p0,p1),FindAngle(p0,p2)); ANGLE_T a0; if (a>=0) { a0 = FindAngle(p0,p1); } else { a0 = FindAngle(p0,p2); } ANGLE_T a1 = fabs(DifferenceBetweenAngles(FindAngle(p0,p1),FindAngle(p0,p2))); seg.type = SEG_CRVLIN; seg.u.c.center = p0; seg.u.c.radius = r; seg.u.c.a0 = a0; seg.u.c.a1 = a1; DrawSegs(d,zero,0.0,&seg,1,trackGauge,color); coOrd p; Translate(&p, p0, a1/2+a0, r ); seg.type = SEG_TEXT; seg.u.t.angle = 0.0; sprintf(msg,"RA: %0.3f",a1); seg.u.t.string = msg; seg.u.t.pos = p; seg.u.t.fontSize = 10.0*d->scale; seg.u.t.fontP = NULL; seg.u.t.boxed = FALSE; DrawSegs(d,zero,0.0,&seg,1,trackGauge,color); } } } static STATUS_T CmdAngle( wAction_t action, coOrd pos ) { switch (action) { case C_START: switch (An.state) { case AN_OFF: An.state = AN_ON; break; case AN_ON: An.state = AN_OFF; case AN_FIRST: case AN_SECOND: An.state = AN_OFF; break; } return C_CONTINUE; case C_DOWN: switch (An.state) { case AN_OFF: case AN_ON: An.pos0 = An.pos1 = An.pos2 = pos; An.state = AN_FIRST; InfoMessage( "Drag out base line" ); break; case AN_FIRST: An.pos2 = pos; An.state = AN_SECOND; InfoMessage( "Drag Angle" ); break; } return C_CONTINUE; case C_MOVE: //Lock to 90 degrees with CTRL if (MyGetKeyState()&WKEY_CTRL) { ANGLE_T line_angle; if (An.state == AN_FIRST) { line_angle = 0.0; } else { line_angle = FindAngle(An.pos0,An.pos1); } DIST_T l = FindDistance(An.pos0, pos); if (!IsClose(l)) { ANGLE_T angle2 = NormalizeAngle(FindAngle(An.pos0, pos)-line_angle); int oct = (int)((angle2 + 22.5) / 45.0); l = fabs(l*cos(D2R(angle2-oct*45))); Translate( &pos, An.pos0, oct*45.0+line_angle, l ); } } switch (An.state) { case AN_FIRST: An.pos1 = An.pos2 = pos; break; case AN_SECOND: An.pos2 = pos; break; default:; } if (An.state == AN_FIRST) { InfoMessage( "Base Angle %0.3f",FindAngle(An.pos0,An.pos1)); } if (An.state == AN_SECOND) InfoMessage( "Base Angle %0.3f, Relative Angle %0.3f",FindAngle(An.pos0, An.pos1), fabs(DifferenceBetweenAngles(FindAngle(An.pos0,An.pos1),FindAngle(An.pos0, An.pos2)))); return C_CONTINUE; case C_UP: if (An.state == AN_SECOND) { return C_TERMINATE; } return C_CONTINUE; case C_REDRAW: DrawHighlightBoxes(FALSE,FALSE,NULL); HighlightSelectedTracks(NULL, TRUE, TRUE); if (An.state != AN_OFF) { if (!IsClose(FindDistance(An.pos1,An.pos2))) { DrawAngle( &tempD, An.pos0, An.pos1, An.pos2, wDrawColorBlack ); } } return C_CONTINUE; case C_CANCEL: return C_TERMINATE; } return C_CONTINUE; } STATUS_T ModifyProtractor( wAction_t action, coOrd pos ) { switch (action&0xFF) { case C_DOWN: An.modifyingEnd = -1; An.isClose = FALSE; if ( An.state == AN_OFF ) { return C_ERROR; } if ( IsClose(FindDistance( pos, An.pos0 ))) { An.modifyingEnd = 0; } else if ( IsClose(FindDistance( pos, An.pos1 ))) { An.modifyingEnd = 1; } else if ( IsClose(FindDistance( pos, An.pos2 ))) { An.modifyingEnd = 2; } else { return C_ERROR; } break; case C_MOVE: if ( An.modifyingEnd == 0 ) { An.pos0 = pos; } else if (An.modifyingEnd == 1) { An.pos1 = pos; } else if (An.modifyingEnd == 2) { An.pos2 = pos; } InfoMessage( "Base Angle %0.3f, Relative Angle %0.3f",FindAngle(An.pos0, An.pos1), fabs(DifferenceBetweenAngles(FindAngle(An.pos0,An.pos1),FindAngle(An.pos0, An.pos2)))); return C_CONTINUE; case C_UP: return C_CONTINUE; case C_REDRAW: DrawAngle( &tempD, An.pos0, An.pos1, An.pos2, An.isClose?wDrawColorBlue:wDrawColorBlack ); break; case wActionMove: if ( IsClose(FindDistance( pos, An.pos0 )) || IsClose(FindDistance( pos, An.pos1 )) || IsClose(FindDistance( pos, An.pos2 )) ) { An.isClose = TRUE; } else { An.isClose = FALSE; } break; default: return C_ERROR; } return C_CONTINUE; } /***************************************************************************** * * RULER * */ #define DR_OFF (0) #define DR_ON (1) static struct { STATE_T state; coOrd pos0; coOrd pos1; BOOL_T isClose; int modifyingEnd; } Dr = { DR_OFF, { 0,0 }, { 0,0 } }; void RulerRedraw( BOOL_T demo ) { if (programMode == MODE_TRAIN) { return; } if (Dr.state == DR_ON) { DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, Dr.isClose?wDrawColorBlue:wDrawColorBlack ); } if (demo) { Dr.state = DR_OFF; An.state = AN_OFF; } if (An.state != AN_OFF) { DrawAngle( &tempD, An.pos0, An.pos1, An.pos2, An.isClose?wDrawColorBlue:wDrawColorBlack); } } static STATUS_T CmdRuler( wAction_t action, coOrd pos ) { switch (action) { case C_START: Dr.isClose = FALSE; switch (Dr.state) { case DR_OFF: Dr.state = DR_ON; InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) ); break; case DR_ON: Dr.state = DR_OFF; break; } return C_CONTINUE; case C_DOWN: Dr.pos0 = Dr.pos1 = pos; Dr.state = DR_ON; InfoMessage( "0.0" ); return C_CONTINUE; case C_MOVE: Dr.pos1 = pos; InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) ); return C_CONTINUE; case C_UP: inError = TRUE; return C_TERMINATE; case C_REDRAW: DrawHighlightBoxes(FALSE,FALSE,NULL); HighlightSelectedTracks(NULL, TRUE, TRUE); if (Dr.state == DR_ON) { DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, Dr.isClose?wDrawColorBlue:wDrawColorBlack ); } return C_CONTINUE; case C_CANCEL: return C_TERMINATE; } return C_CONTINUE; } STATUS_T ModifyRuler( wAction_t action, coOrd pos ) { switch (action&0xFF) { case C_DOWN: Dr.modifyingEnd = -1; if ( Dr.state != DR_ON ) { return C_ERROR; } if ( IsClose(FindDistance( pos, Dr.pos0 ))) { Dr.modifyingEnd = 0; } else if ( IsClose(FindDistance( pos, Dr.pos1 ))) { Dr.modifyingEnd = 1; } else { return C_ERROR; } break; case C_MOVE: if ( Dr.modifyingEnd == 0 ) { Dr.pos0 = pos; } else if ( Dr.modifyingEnd == 1) { Dr.pos1 = pos; } else { return C_ERROR; } InfoMessage( "%s", FormatDistance( FindDistance( Dr.pos0, Dr.pos1 ) ) ); return C_CONTINUE; case C_UP: return C_CONTINUE; case C_REDRAW: DrawRuler( &tempD, Dr.pos0, Dr.pos1, 0.0, TRUE, TRUE, Dr.isClose?wDrawColorBlue:wDrawColorBlack ); break; case wActionMove: if ( IsClose(FindDistance( pos, Dr.pos0 )) || IsClose(FindDistance( pos, Dr.pos1 ))) { Dr.isClose = TRUE; An.isClose = FALSE; } else { Dr.isClose = FALSE; ModifyProtractor(wActionMove,pos); } break; default: return C_ERROR; } return C_CONTINUE; } #include "bitmaps/ruler.xpm3" #include "bitmaps/protractor.xpm3" void InitCmdRuler( wMenu_p menu ) { ButtonGroupBegin( _("Measurement"), "cmdMeasureSetCmd", _("Measurement") ); AddMenuButton( menu, CmdRuler, "cmdRuler", _("Ruler"), wIconCreatePixMap(ruler_xpm3[iconSize]), LEVEL0, IC_STICKY|IC_POPUP|IC_NORESTART, ACCL_RULER, NULL ); AddMenuButton( menu, CmdAngle, "cmdAngle", _("Protractor"), wIconCreatePixMap(protractor_xpm3[iconSize]), LEVEL0, IC_STICKY|IC_POPUP|IC_NORESTART, ACCL_ANGLE, NULL ); ButtonGroupEnd(); }