/* 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 #include #include "ccurve.h" #include "cbezier.h" #include "compound.h" #include "cundo.h" #include "drawgeom.h" #include "fileio.h" #include "i18n.h" #include "messages.h" #include "param.h" #include "track.h" #include "utility.h" static long drawGeomCurveMode; #define contextSegs(N) DYNARR_N( trkSeg_t, context->Segs_da, N ) static dynArr_t points_da; static dynArr_t anchors_da; static dynArr_t select_da; #define points(N) DYNARR_N( pts_t, points_da, N ) #define point_selected(N) DYNARR_N( wBool_t, select_da, N) #define anchors(N) DYNARR_N( trkSeg_t, anchors_da, N) static void EndPoly( drawContext_t * context, int cnt, wBool_t open) { trkSeg_p segPtr; track_p trk; pts_t * pts; int inx; if (context->State==0 || cnt == 0) return; if ( cnt < 3 ) { tempSegs_da.cnt = 0; ErrorMessage( MSG_POLY_SHAPES_3_SIDES ); return; } pts = (pts_t*)MyMalloc( (cnt) * sizeof (pts_t) ); for ( inx=0; inxtype = ( (context->Op == OP_POLY || context->Op == OP_POLYLINE )? SEG_POLY:SEG_FILPOLY ); segPtr->u.p.cnt = cnt; segPtr->u.p.pts = pts; segPtr->u.p.angle = 0.0; segPtr->u.p.orig = zero; segPtr->u.p.polyType = open?POLYLINE:FREEFORM; UndoStart( _("Create Lines"), "newDraw" ); trk = MakeDrawFromSeg( zero, 0.0, segPtr ); DrawNewTrack( trk ); tempSegs_da.cnt = 0; } static void DrawGeomOk( void ) { track_p trk; int inx; if (tempSegs_da.cnt <= 0) return; UndoStart( _("Create Lines"), "newDraw" ); for ( inx=0; inxState == 2) { if (context->Op >= OP_CURVE1 && context->Op <= OP_CURVE4) { if (context->ArcData.type == curveTypeCurve) { ANGLE_T a = FindAngle(context->ArcData.curvePos,*p); if (IsClose(FindDistance(context->ArcData.curvePos,*p)-context->ArcData.curveRadius) && (a>=context->ArcData.a0) && (a<=context->ArcData.a0+context->ArcData.a1)) { Translate(p,context->ArcData.curvePos,a,context->ArcData.curveRadius); return TRUE; } } else { if (IsClose(LineDistance(p,tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]))) return TRUE; } } else if ( context->Op >=OP_LINE && context->Op <= OP_BENCH) { if (IsClose(LineDistance(p,tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]))) return TRUE; } } return FALSE; } /** * Create and draw a graphics primitive (lines, arc, circle). The complete handling of mouse * movements and clicks during the editing process is done here. * * \param action IN mouse action * \param pos IN position of mouse pointer * \param context IN/OUT parameters for drawing op * \return next command state * * Note - Poly supports both clicking points and/or dragging sides. Close is space or enter. * Note - This routine will be recalled to C_UPDATE the last action if the State is 2 and the user updates the dialog * */ STATUS_T DrawGeomMouse( wAction_t action, coOrd pos, drawContext_t *context) { static int lastValid = FALSE; static wBool_t lock; static coOrd pos0, pos0x, pos1, lastPos; trkSeg_p segPtr; pts_t *pts; int inx; DIST_T width; static int segCnt; DIST_T d; ANGLE_T a1,a2; static ANGLE_T line_angle; BOOL_T createTrack; width = context->line_Width/context->D->dpi; switch (action&0xFF) { case C_UPDATE: if (context->State == 0 ) return C_TERMINATE; if (context->Op != OP_POLY && context->Op != OP_FILLPOLY && context->Op != OP_POLYLINE && context->State == 1) return C_TERMINATE; switch (context->Op) { case OP_CIRCLE1: case OP_CIRCLE2: case OP_CIRCLE3: case OP_FILLCIRCLE1: case OP_FILLCIRCLE2: case OP_FILLCIRCLE3: tempSegs(0).u.c.radius = context->radius; break; case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4: if (context->ArcData.type == curveTypeCurve) { if (tempSegs(0).u.c.radius != context->radius) { coOrd end; Translate(&end,context->ArcData.curvePos,context->ArcData.a0,context->ArcData.curveRadius); tempSegs(0).u.c.radius = context->radius; Translate(&tempSegs(0).u.c.center,end,context->ArcData.a0+180,context->radius); context->ArcData.curvePos = tempSegs(0).u.c.center; context->ArcData.curveRadius = tempSegs(0).u.c.radius; } tempSegs(0).u.c.a1 = context->angle; context->ArcData.a1 = tempSegs(0).u.c.a1; Translate(&context->ArcData.pos1,context->ArcData.curvePos,context->ArcData.a0,context->ArcData.curveRadius); Translate(&context->ArcData.pos2,context->ArcData.curvePos,context->ArcData.a0+context->ArcData.a1,context->ArcData.curveRadius); } else Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,context->length); break; case OP_LINE: case OP_BENCH: case OP_TBLEDGE: a1 = FindAngle(pos0,pos1); Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,context->length); lastPos = pos1 = tempSegs(0).u.l.pos[1]; tempSegs_da.cnt = 1; context->angle = NormalizeAngle(context->angle); break; case OP_BOX: case OP_FILLBOX: pts = tempSegs(0).u.p.pts; a1 = FindAngle(pts[0].pt,pts[1].pt); Translate(&pts[1].pt,pts[0].pt,a1,context->length); a2 = FindAngle(pts[0].pt,pts[3].pt); Translate(&pts[2].pt,pts[1].pt,a2,context->width); Translate(&pts[3].pt,pts[0].pt,a2,context->width); tempSegs_da.cnt = 1; break; case OP_POLY: case OP_FILLPOLY: case OP_POLYLINE: tempSegs_da.cnt = segCnt; if (segCnt>1) { ANGLE_T an = FindAngle(tempSegs(segCnt-2).u.l.pos[0],tempSegs(segCnt-2).u.l.pos[1]); an = an+context->angle; Translate(&tempSegs(segCnt-1).u.l.pos[1],tempSegs(segCnt-1).u.l.pos[0],an,context->length); } else { Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->angle,context->length); } pos1 = lastPos = tempSegs(segCnt-1).u.l.pos[1]; context->angle = fabs(context->angle); if (context->angle >180) context->angle = context->angle - 180.0; break; default: break; } MainRedraw(); anchors_da.cnt = 0; return C_CONTINUE; case C_START: context->State = 0; context->Changed = FALSE; segCnt = 0; CleanSegs(&tempSegs_da); DYNARR_RESET( trkSeg_t, tempSegs_da ); DYNARR_RESET( trkSeg_t, anchors_da ); lock = FALSE; if (!magneticSnap) InfoMessage(_("+Shift to lock to nearby objects")); else InfoMessage(_("+Shift to not lock to nearby objects")); return C_CONTINUE; case wActionMove: if (context->State == 0 || context->State ==2 ) { DYNARR_RESET( trkSeg_t, anchors_da ); switch (context->Op) { //Snap pos to nearest line if this is end and just shift is depressed for lines and some curves case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4: case OP_LINE: case OP_DIMLINE: case OP_BENCH: case OP_POLY: case OP_FILLPOLY: case OP_POLYLINE: if (((MyGetKeyState() & WKEY_ALT) == 0) == magneticSnap ) { coOrd p = pos; track_p t; if ((t=OnTrack(&p,FALSE,FALSE))!=NULL) { if (context->Op == OP_DIMLINE ) { CreateEndAnchor(p,FALSE); } else if (!IsTrack(t)) CreateEndAnchor(p,FALSE); } else { p = pos; if (FindTempNear(context,&p)) { CreateEndAnchor(p,FALSE); } } } break; default: ; } } return C_CONTINUE; case wActionLDown: DYNARR_RESET( trkSeg_t, anchors_da ); if (context->State == 2) { tempSegs_da.cnt = segCnt; if ((context->Op == OP_POLY || context->Op == OP_FILLPOLY || context->Op == OP_POLYLINE)) { EndPoly(context, segCnt, context->Op==OP_POLYLINE); } else { DrawGeomOk(); } segCnt = 0; anchors_da.cnt = 0; context->State = 0; } context->Started = TRUE; line_angle = 90.0; if ((context->Op == OP_CURVE1 && context->State != 2) || (context->Op == OP_CURVE2 && context->State == 0) || (context->Op == OP_CURVE3 && context->State != 0) || (context->Op == OP_CURVE4 && context->State != 2) || (context->Op == OP_LINE) || (context->Op == OP_DIMLINE) || (context->Op == OP_BENCH) ) { BOOL_T found = FALSE; if (((MyGetKeyState() & WKEY_ALT) ==0) == magneticSnap ) { coOrd p = pos; track_p t; if ((t=OnTrack(&p,FALSE,FALSE))!=NULL) { if (!IsTrack(t)) { EPINX_T ep1,ep2; line_angle = GetAngleAtPoint(t,pos,&ep1,&ep2); pos = p; found = TRUE; } } } if (!found) SnapPos( &pos ); } if ((context->Op == OP_CURVE1 || context->Op == OP_CURVE2 || context->Op == OP_CURVE3 || context->Op == OP_CURVE4) && context->State == 1) { ; } else { pos0 = pos; pos1 = pos; } switch (context->Op) { case OP_LINE: case OP_DIMLINE: case OP_BENCH: DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); switch (context->Op) { case OP_LINE: tempSegs(0).type = SEG_STRLIN; break; case OP_DIMLINE: tempSegs(0).type = SEG_DIMLIN; break; case OP_BENCH: tempSegs(0).type = SEG_BENCH; break; } tempSegs(0).color = context->Color; tempSegs(0).width = width; tempSegs(0).u.l.pos[0] = tempSegs(0).u.l.pos[1] = pos; if ( context->Op == OP_BENCH || context->Op == OP_DIMLINE ) { tempSegs(0).u.l.option = context->benchOption; } else { tempSegs(0).u.l.option = 0; } tempSegs_da.cnt = 0; context->message( _("Drag to next point, +Shift to lock to object, +Ctrl to lock to 90deg") ); break; case OP_TBLEDGE: OnTableEdgeEndPt( NULL, &pos ); DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); tempSegs(0).type = SEG_TBLEDGE; tempSegs(0).color = context->Color; tempSegs(0).width = (mainD.scale<=16)?(3/context->D->dpi*context->D->scale):0; tempSegs(0).u.l.pos[0] = tempSegs(0).u.l.pos[1] = pos; tempSegs_da.cnt = 0; context->message( _("Drag to place next end point") ); break; case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4: if (context->State == 0) { switch ( context->Op ) { case OP_CURVE1: drawGeomCurveMode = crvCmdFromEP1; break; case OP_CURVE2: drawGeomCurveMode = crvCmdFromTangent; break; case OP_CURVE3: drawGeomCurveMode = crvCmdFromCenter; break; case OP_CURVE4: drawGeomCurveMode = crvCmdFromChord; break; } CreateCurve( C_START, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message ); CreateCurve( C_DOWN, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message ); } break; case OP_CIRCLE1: case OP_CIRCLE2: case OP_CIRCLE3: case OP_FILLCIRCLE1: case OP_FILLCIRCLE2: case OP_FILLCIRCLE3: DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); tempSegs(0).type = SEG_CRVLIN; tempSegs(0).color = context->Color; if ( context->Op >= OP_CIRCLE1 && context->Op <= OP_CIRCLE3 ) tempSegs(0).width = width; else tempSegs(0).width = 0; tempSegs(0).u.c.a0 = 0; tempSegs(0).u.c.a1 = 360; tempSegs(0).u.c.radius = 0; tempSegs(0).u.c.center = pos; context->message( _("Drag to set radius") ); break; case OP_FILLBOX: width = 0; /* no break */ case OP_BOX: DYNARR_SET( trkSeg_t, tempSegs_da, 4 ); for ( inx=0; inx<4; inx++ ) { tempSegs(inx).type = SEG_STRLIN; tempSegs(inx).color = context->Color; tempSegs(inx).width = width; tempSegs(inx).u.l.pos[0] = tempSegs(inx).u.l.pos[1] = pos; } context->message( _("Drag set box size") ); break; case OP_POLY: case OP_FILLPOLY: case OP_POLYLINE: tempSegs_da.cnt = segCnt; wBool_t first_spot = FALSE; if (segCnt == 1 && tempSegs(0).type == SEG_CRVLIN) { coOrd start; start = tempSegs(0).u.c.center; tempSegs(0).type = SEG_STRLIN; tempSegs(0).u.l.pos[0] = start; first_spot=TRUE; } else { DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 ); } segPtr = &tempSegs(tempSegs_da.cnt-1); segPtr->type = SEG_STRLIN; segPtr->color = context->Color; segPtr->width = (context->Op==OP_POLY?width:0); //End if over start if ( segCnt>2 && IsClose(FindDistance(tempSegs(0).u.l.pos[0], pos ))) { segPtr->u.l.pos[0] = tempSegs(segCnt-1).u.l.pos[1]; segPtr->u.l.pos[1] = tempSegs(0).u.l.pos[0]; EndPoly(context, tempSegs_da.cnt, context->Op==OP_POLYLINE); DYNARR_RESET(pts_t, points_da); DYNARR_RESET(trkSeg_t,tempSegs_da); context->State = 0; segCnt = 0; return C_TERMINATE; } if (!first_spot) { if ( tempSegs_da.cnt == 1) { segPtr->u.l.pos[0] = pos; } else { segPtr->u.l.pos[0] = segPtr[-1].u.l.pos[1]; } } segPtr->u.l.pos[1] = pos; context->State = 1; segCnt = tempSegs_da.cnt; context->message(_("+Shift - lock to close object, +Ctrl - lock to 90 deg")); break; } return C_CONTINUE; case wActionLDrag: DYNARR_RESET(trkSeg_t, anchors_da ); if ((context->Op == OP_CURVE1 && context->State == 1) || (context->Op == OP_CURVE2 && context->State == 0) || (context->Op == OP_CURVE4 && context->State != 2) || (context->Op == OP_LINE) || (context->Op == OP_BENCH) ) { if (( (MyGetKeyState() & WKEY_ALT)==0) == magneticSnap) { if (OnTrack( &pos, FALSE, FALSE )!=NULL) CreateEndAnchor(pos,TRUE); } } else if (context->Op == OP_DIMLINE) { if (OnTrack( &pos, FALSE, FALSE )!=NULL) CreateEndAnchor(pos,TRUE); } pos1 = pos; switch (context->Op) { case OP_TBLEDGE: OnTableEdgeEndPt( NULL, &pos1 ); /* no break */ case OP_LINE: case OP_DIMLINE: case OP_BENCH: if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) { //Snap to Right-Angle from previous or from 0 DIST_T l = FindDistance(pos0, pos); ANGLE_T angle2 = NormalizeAngle(FindAngle(pos0, pos)-line_angle); int quad = (int)((angle2 + 45.0) / 90.0); if (tempSegs_da.cnt != 1 && (quad == 2)) { pos1 = pos0; } else if (quad == 1 || quad == 3) { if (tempSegs_da.cnt != 1) l = fabs(l*cos(D2R(((quad==1)?line_angle+90.0:line_angle-90.0)-FindAngle(pos,pos0)))); Translate( &pos1, pos0, NormalizeAngle(quad==1?line_angle+90.0:line_angle-90.0), l ); } else { if (tempSegs_da.cnt != 1) l = fabs(l*cos(D2R(((quad==0||quad==4)?line_angle:line_angle+180.0)-FindAngle(pos,pos0)))); Translate( &pos1, pos0, NormalizeAngle((quad==0||quad==4)?line_angle:line_angle+180.0), l ); } CreateLineAnchor(pos1,pos0); } tempSegs(0).u.l.pos[1] = pos1; context->message( _("Length = %s, Angle = %0.2f"), FormatDistance(FindDistance( pos0, pos1 )), PutAngle(FindAngle( pos0, pos1 )) ); tempSegs_da.cnt = 1; if (anchors_da.cnt == 0) CreateEndAnchor(pos, FALSE); break; case OP_POLY: case OP_FILLPOLY: case OP_POLYLINE: if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) { coOrd last_point = zero; ANGLE_T last_angle, initial_angle; if (tempSegs_da.cnt == 1) { last_angle = 90.0; last_point = tempSegs(0).u.l.pos[0]; initial_angle = 90.0; } else { last_point = tempSegs(tempSegs_da.cnt-2).u.l.pos[1]; last_angle = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[0],tempSegs(tempSegs_da.cnt-2).u.l.pos[1]); initial_angle = FindAngle(tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]); } //Snap to Right-Angle from previous or from 0 DIST_T l = FindDistance(tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos); ANGLE_T angle2 = NormalizeAngle(FindAngle(tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos)-last_angle); int quad = (int)((angle2+45.0)/90.0); if (tempSegs_da.cnt != 1 && (quad == 2)) { pos = tempSegs(tempSegs_da.cnt-1).u.l.pos[0]; } else if (quad == 1 || quad == 3) { if (tempSegs_da.cnt != 1) l = fabs(l*cos(D2R(((quad==1)?last_angle+90.0:last_angle-90.0)-FindAngle(pos,last_point)))); Translate( &pos, tempSegs(tempSegs_da.cnt-1).u.l.pos[0], NormalizeAngle(quad==1?last_angle+90.0:last_angle-90.0), l ); } else { if (tempSegs_da.cnt != 1) l = fabs(l*cos(D2R(((quad==0||quad==4)?last_angle:last_angle+180.0)-FindAngle(pos,last_point)))); Translate( &pos, tempSegs(tempSegs_da.cnt-1).u.l.pos[0], NormalizeAngle((quad==0||quad==4)?last_angle:last_angle+180.0), l ); } CreateEndAnchor(pos,TRUE); if (FindDistance(pos,last_point)>0.0) CreateLineAnchor(pos,last_point); } //If there is any point on this line that will give a 90 degree return to the first point, show it if (tempSegs_da.cnt > 1) { coOrd intersect; ANGLE_T an_this = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[1],pos); if (FindIntersection(&intersect,tempSegs(0).u.l.pos[0],an_this+90.0,tempSegs(tempSegs_da.cnt-2).u.l.pos[1],an_this)) { ANGLE_T an_inter = FindAngle(tempSegs(tempSegs_da.cnt-2).u.l.pos[1],intersect); if (fabs(DifferenceBetweenAngles(an_inter,an_this))<90.0) { CreateSquareAnchor(intersect); d = FindDistance(intersect,pos); if (IsClose(d)) { pos = intersect; } } } } tempSegs(tempSegs_da.cnt-1).type = SEG_STRLIN; tempSegs(tempSegs_da.cnt-1).u.l.pos[1] = pos; context->message( _("Length = %s, Angle = %0.2f"), FormatDistance(FindDistance( tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos )), PutAngle(FindAngle( tempSegs(tempSegs_da.cnt-1).u.l.pos[0], pos )) ); segCnt = tempSegs_da.cnt; break; case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4: if (context->State == 0) { pos0x = pos; CreateCurve( C_MOVE, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message ); } else { PlotCurve( drawGeomCurveMode, pos0, pos0x, pos1, &context->ArcData, FALSE ); tempSegs(0).color = context->Color; tempSegs(0).width = width; DYNARR_SET(trkSeg_t,tempSegs_da,1); if (context->ArcData.type == curveTypeStraight) { tempSegs(0).type = SEG_STRLIN; tempSegs(0).u.l.pos[0] = pos0; tempSegs(0).u.l.pos[1] = context->ArcData.pos1; tempSegs_da.cnt = 1; CreateEndAnchor(pos0, FALSE); CreateEndAnchor(context->ArcData.pos1, FALSE); context->message( _("Straight Line: Length=%s Angle=%0.3f"), FormatDistance(FindDistance( pos0, context->ArcData.pos1 )), PutAngle(FindAngle( pos0, context->ArcData.pos1 )) ); } else if (context->ArcData.type == curveTypeNone) { tempSegs_da.cnt = 0; context->message( _("Back") ); } else if (context->ArcData.type == curveTypeCurve) { tempSegs(0).type = SEG_CRVLIN; tempSegs(0).u.c.center = context->ArcData.curvePos; tempSegs(0).u.c.radius = context->ArcData.curveRadius; tempSegs(0).u.c.a0 = context->ArcData.a0; tempSegs(0).u.c.a1 = context->ArcData.a1; tempSegs_da.cnt = 1; d = D2R(context->ArcData.a1); if (d < 0.0) d = 2*M_PI+d; if ( d*context->ArcData.curveRadius > mapD.size.x+mapD.size.y ) { ErrorMessage( MSG_CURVE_TOO_LARGE ); tempSegs_da.cnt = 0; context->ArcData.type = curveTypeNone; return C_CONTINUE; } context->message( _("Curved Line: Radius=%s Angle=%0.3f Length=%s"), FormatDistance(context->ArcData.curveRadius), context->ArcData.a1, FormatDistance(context->ArcData.curveRadius*d) ); if (context->Op == OP_CURVE1 || context->Op == OP_CURVE4 ) DrawArrowHeadsArray(&anchors_da,pos,FindAngle(context->ArcData.curvePos,pos),TRUE,wDrawColorRed); else if (context->Op == OP_CURVE2 || context->Op == OP_CURVE3 ) { CreateEndAnchor(context->ArcData.pos2,FALSE); DrawArrowHeadsArray(&anchors_da,context->ArcData.pos2,FindAngle(context->ArcData.curvePos,context->ArcData.pos2)+90,TRUE,wDrawColorRed); } CreateEndAnchor(context->ArcData.curvePos,TRUE); } } if (anchors_da.cnt == 0) CreateEndAnchor(pos, FALSE); break; case OP_CIRCLE1: case OP_FILLCIRCLE1: break; case OP_CIRCLE2: case OP_FILLCIRCLE2: tempSegs(0).u.c.center = pos1; /* no break */ case OP_CIRCLE3: case OP_FILLCIRCLE3: tempSegs(0).u.c.radius = FindDistance( pos0, pos1 ); context->message( _("Radius = %s"), FormatDistance(FindDistance( pos0, pos1 )) ); break; case OP_BOX: case OP_FILLBOX: tempSegs_da.cnt = 4; tempSegs(0).u.l.pos[1].x = tempSegs(1).u.l.pos[0].x = tempSegs(1).u.l.pos[1].x = tempSegs(2).u.l.pos[0].x = pos.x; tempSegs(1).u.l.pos[1].y = tempSegs(2).u.l.pos[0].y = tempSegs(2).u.l.pos[1].y = tempSegs(3).u.l.pos[0].y = pos.y; context->message( _("Width = %s, Height = %s"), FormatDistance(fabs(pos1.x - pos0.x)), FormatDistance(fabs(pos1.y - pos0.y)) ); break; } return C_CONTINUE; case wActionLUp: lastValid = FALSE; createTrack = FALSE; if ((context->Op == OP_CURVE1 && context->State == 1) || (context->Op == OP_CURVE2 && context->State == 0) || (context->Op == OP_CURVE3 && context->State != 0) || (context->Op == OP_CURVE4 && context->State != 2) || (context->Op == OP_LINE) || (context->Op == OP_DIMLINE) || (context->Op == OP_BENCH) ) { if (((MyGetKeyState() & WKEY_ALT)==0) == magneticSnap ) { coOrd p = pos1; track_p t; if ((t=OnTrack(&p,FALSE,FALSE))) { pos1 = p; if (context->Op == OP_LINE || context->Op == OP_DIMLINE || context->Op == OP_BENCH) { tempSegs(0).u.l.pos[1] = p; } else { PlotCurve( drawGeomCurveMode, pos0, pos0x, pos1, &context->ArcData, FALSE ); if (context->ArcData.type == curveTypeStraight) { DYNARR_RESET(trkSeg_t,tempSegs_da); DYNARR_APPEND(trkSeg_t,tempSegs_da,1); tempSegs(0).type = SEG_STRLIN; tempSegs(0).u.l.pos[0] = pos0; tempSegs(0).u.l.pos[1] = context->ArcData.pos1; tempSegs_da.cnt = 1; } else if (context->ArcData.type == curveTypeNone) { DYNARR_RESET(trkSeg_t,tempSegs_da); } else if (context->ArcData.type == curveTypeCurve) { DYNARR_RESET(trkSeg_t,tempSegs_da); DYNARR_APPEND(trkSeg_t,tempSegs_da,1); tempSegs(0).type = SEG_CRVLIN; tempSegs(0).u.c.center = context->ArcData.curvePos; tempSegs(0).u.c.radius = context->ArcData.curveRadius; tempSegs(0).u.c.a0 = context->ArcData.a0; tempSegs(0).u.c.a1 = context->ArcData.a1; tempSegs_da.cnt = 1; } } } } } switch ( context->Op ) { case OP_LINE: case OP_DIMLINE: case OP_BENCH: case OP_TBLEDGE: lastValid = TRUE; lastPos = pos1; context->length = FindDistance(pos1,pos0); context->angle = FindAngle(pos0,pos1); context->State = 2; segCnt = tempSegs_da.cnt; break; case OP_CURVE1: case OP_CURVE2: case OP_CURVE3: case OP_CURVE4: if (context->State == 0) { context->State = 1; context->ArcAngle = FindAngle( pos0, pos1 ); pos0x = pos1; CreateCurve( C_UP, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message ); context->message( _("Drag on Red arrows to adjust curve") ); return C_CONTINUE; } else { DYNARR_SET(trkSeg_t,tempSegs_da,1); if (context->ArcData.type == curveTypeCurve) { segPtr = &tempSegs(0); segPtr->type = SEG_CRVLIN; segPtr->color = context->Color; segPtr->width = width; segPtr->u.c.center = context->ArcData.curvePos; segPtr->u.c.radius = context->ArcData.curveRadius; segPtr->u.c.a0 = context->ArcData.a0; segPtr->u.c.a1 = context->ArcData.a1; context->radius = context->ArcData.curveRadius; context->angle = context->ArcData.a1; } else if (context->ArcData.type == curveTypeStraight) { segPtr = &tempSegs(0); segPtr->type = SEG_STRLIN; segPtr->color = context->Color; segPtr->width = width; segPtr->u.l.pos[0] = pos0; segPtr->u.l.pos[1] = pos1; context->radius = 0; context->length = FindDistance(pos0,pos1); context->angle = FindAngle(pos0,pos1); } lastValid = TRUE; lastPos = pos1; context->State = 2; /*drawContext = context; DrawGeomOp( (void*)context->Op );*/ } break; case OP_CIRCLE1: case OP_CIRCLE2: case OP_CIRCLE3: case OP_FILLCIRCLE1: case OP_FILLCIRCLE2: case OP_FILLCIRCLE3: if ( context->Op>=OP_FILLCIRCLE1 && context->Op<=OP_FILLCIRCLE3 ) tempSegs(0).type = SEG_FILCRCL; tempSegs_da.cnt = 1; context->State = 2; context->radius = tempSegs(0).u.c.radius; break; case OP_BOX: case OP_FILLBOX: pts = (pts_t*)MyMalloc( 4 * sizeof (pts_t) ); for ( inx=0; inx<4; inx++ ) { pts[inx].pt = tempSegs(inx).u.l.pos[0]; pts[inx].pt_type = wPolyLineStraight; } tempSegs(0).type = (context->Op == OP_FILLBOX)?SEG_FILPOLY:SEG_POLY; tempSegs(0).u.p.cnt = 4; tempSegs(0).u.p.pts = pts; tempSegs(0).u.p.angle = 0.0; tempSegs(0).u.p.orig = zero; tempSegs(0).u.p.polyType = RECTANGLE; tempSegs_da.cnt = 1; /*drawContext = context; DrawGeomOp( (void*)context->Op );*/ context->length = FindDistance(pts[0].pt,pts[1].pt); context->width = FindDistance(pts[3].pt,pts[0].pt); context->State = 2; segCnt = tempSegs_da.cnt; break; case OP_POLY: case OP_FILLPOLY: case OP_POLYLINE: tempSegs_da.cnt = segCnt; anchors_da.cnt=0; //End if close to start if ( segCnt>2 && IsClose(FindDistance(tempSegs(0).u.l.pos[0], pos))) { EndPoly(context, tempSegs_da.cnt, context->Op==OP_POLYLINE); DYNARR_RESET(pts_t, points_da); CleanSegs(&tempSegs_da); context->State = 0; segCnt = 0; return C_TERMINATE; } //If too short, remove last segment if (IsClose(FindDistance(tempSegs(segCnt-1).u.l.pos[0],pos))) { if (tempSegs_da.cnt>1) { --tempSegs_da.cnt; segCnt = tempSegs_da.cnt; wBeep(); } else { //First spot only tempSegs(0).color = wDrawColorRed; tempSegs(0).type = SEG_CRVLIN; tempSegs(0).u.c.a1 = 360; tempSegs(0).u.c.radius = tempD.scale*0.15/2; tempSegs(0).u.c.center = pos; segCnt = tempSegs_da.cnt; } return C_CONTINUE; } int text_inx = tempSegs_da.cnt-1; //tempSegs(tempSegs_da.cnt-1).u.l.pos[1] = pos; context->length = FindDistance(tempSegs(text_inx).u.l.pos[0],tempSegs(text_inx).u.l.pos[1]); if (text_inx>1) { ANGLE_T an = FindAngle(tempSegs(text_inx-1).u.l.pos[0],tempSegs(text_inx-1).u.l.pos[1]); context->angle = NormalizeAngle(FindAngle(tempSegs(text_inx).u.l.pos[0],tempSegs(text_inx).u.l.pos[1])-an); } else context->angle = FindAngle(tempSegs(1).u.l.pos[0],tempSegs(1).u.l.pos[1]); context->State = 1; context->index = text_inx; segCnt = tempSegs_da.cnt; return C_CONTINUE; } context->Started = FALSE; context->Changed = TRUE; //Update screen shown /*CheckOk();*/ if (context->State == 2 && IsCurCommandSticky()) { segCnt = tempSegs_da.cnt; return C_CONTINUE; } DrawGeomOk(); context->State = 0; context->Changed = FALSE; context->message(""); return C_TERMINATE; case wActionText: DYNARR_RESET(trkSeg_t, anchors_da ); if ( ((action>>8)&0xFF) == 0x0D || ((action>>8)&0xFF) == ' ' ) { if ((context->Op == OP_POLY) || (context->Op == OP_FILLPOLY) || (context->Op == OP_POLYLINE)) { tempSegs_da.cnt = segCnt; //If last segment wasn't just a point, add another starting on its end if (!IsClose(FindDistance(tempSegs(segCnt-1).u.l.pos[0],tempSegs(segCnt-1).u.l.pos[1]))) { DYNARR_APPEND(trkSeg_t,tempSegs_da,1); segPtr = &tempSegs(tempSegs_da.cnt-1); segPtr->type = SEG_STRLIN; segPtr->u.l.pos[0] = segPtr[-1].u.l.pos[1]; segPtr->u.l.pos[1] = tempSegs(0).u.l.pos[0]; } EndPoly(context, tempSegs_da.cnt, context->Op == OP_POLYLINE); DYNARR_RESET(pts_t, points_da); DYNARR_RESET(trkSeg_t,tempSegs_da); } else { if (context->State == 2) tempSegs_da.cnt = segCnt; DrawGeomOk(); } } context->State = 0; segCnt = 0; return C_TERMINATE; case C_CANCEL: if (context->Changed) { //If the update values were shown if (context->State == 2) { tempSegs_da.cnt = segCnt; DrawGeomOk(); } } DYNARR_RESET(trkSeg_t, anchors_da ); tempSegs_da.cnt = 0; context->message( "" ); context->Changed = FALSE; context->State = 0; segCnt = 0; lastValid = FALSE; return C_TERMINATE; case C_REDRAW: DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); if (anchors_da.cnt > 0) { DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, 0.0, wDrawColorBlack ); } return C_CONTINUE; case C_CMDMENU: return C_CONTINUE; default: return C_CONTINUE; } } static int polyInx; static int lineInx; static int curveInx; typedef enum {POLY_NONE, POLY_SELECTED, POLYPOINT_SELECTED} PolyState_e; static PolyState_e polyState = POLY_NONE; static coOrd rotate_origin; static ANGLE_T rotate_angle; static dynArr_t origin_da; void static CreateCircleAnchor(wBool_t selected,coOrd center, DIST_T rad, ANGLE_T angle) { DYNARR_RESET(trkSeg_t,anchors_da); double d = tempD.scale*0.15; DYNARR_APPEND(trkSeg_t,anchors_da,2); anchors(0).type = (selected)?SEG_FILCRCL:SEG_CRVLIN; anchors(0).u.c.a1 = 360.0; anchors(0).color = wDrawColorBlue; anchors(0).u.c.radius = d/2; PointOnCircle(&anchors(0).u.c.center,center,rad,angle); } void static CreateLineAnchors(int index, coOrd p0, coOrd p1) { DYNARR_RESET(trkSeg_t,anchors_da); double d = tempD.scale*0.15; DYNARR_APPEND(trkSeg_t,anchors_da,2); anchors(0).type = (index ==0)?SEG_FILCRCL:SEG_CRVLIN; anchors(0).u.c.a1 = 360.0; anchors(0).color = wDrawColorBlue; anchors(0).u.c.radius = d/2; anchors(0).u.c.center = p0; DYNARR_APPEND(trkSeg_t,anchors_da,1); anchors(1).type = (index ==1)?SEG_FILCRCL:SEG_CRVLIN; anchors(1).u.c.a1 = 360.0; anchors(1).color = wDrawColorBlue; anchors(1).u.c.radius = d/2; anchors(1).u.c.center = p1; } void static CreateBoxAnchors(int index, pts_t pt[4]) { DYNARR_RESET(trkSeg_t,anchors_da); double d = tempD.scale*0.15; ANGLE_T a = FindAngle(pt[0].pt,pt[1].pt); ANGLE_T diag = FindAngle(pt[0].pt,pt[2].pt); for (int i=0;i<4;i++) { DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pt[i].pt,(diag>a?45.0:-45.0)+a+(90.0*(i)),TRUE,i==index?wDrawColorRed:wDrawColorBlue); } coOrd pp; for (int i=0;i<4;i++) { pp.x = (i==3?((((pt[0].pt.x - pt[i].pt.x)/2))+pt[i].pt.x):((pt[i+1].pt.x - pt[i].pt.x)/2)+pt[i].pt.x); pp.y = (i==3?((((pt[0].pt.y - pt[i].pt.y)/2))+pt[i].pt.y):((pt[i+1].pt.y - pt[i].pt.y)/2)+pt[i].pt.y); DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pp,90.0*(i-1)+a,TRUE,i==index+5?wDrawColorRed:wDrawColorBlue); } } void static CreateOriginAnchor(coOrd origin, wBool_t trans_selected) { double d = tempD.scale*0.15; DYNARR_APPEND(trkSeg_t,anchors_da,2); int i = anchors_da.cnt-1; coOrd p0,p1; Translate(&p0,origin,0,d*4); Translate(&p1,origin,0,-d*4); anchors(i).type = SEG_STRLIN; anchors(i).u.l.pos[0] = p0; anchors(i).u.l.pos[1] = p1; anchors(i).color = wDrawColorBlue; anchors(i).width = 0; DYNARR_APPEND(trkSeg_t,anchors_da,1); Translate(&p0,origin,90,d*4); Translate(&p1,origin,90,-d*4); i = anchors_da.cnt-1; anchors(i).type = SEG_STRLIN; anchors(i).u.l.pos[0] = p0; anchors(i).u.l.pos[1] = p1; anchors(i).color = wDrawColorBlue; anchors(i).width = 0; } void static CreateCurveAnchors(int index, coOrd pm, coOrd pc, coOrd p0, coOrd p1) { DYNARR_RESET(trkSeg_t,anchors_da); double d = tempD.scale*0.15; DYNARR_APPEND(trkSeg_t,anchors_da,9); anchors(0).type = (index ==0)?SEG_FILCRCL:SEG_CRVLIN; anchors(0).u.c.a1 = 360.0; anchors(0).color = wDrawColorBlue; anchors(0).u.c.radius = d/2; anchors(0).u.c.center = p0; anchors(0).width = 0; DYNARR_APPEND(trkSeg_t,anchors_da,8); anchors(1).type = (index ==1)?SEG_FILCRCL:SEG_CRVLIN; anchors(1).u.c.a1 = 360.0; anchors(1).color = wDrawColorBlue; anchors(1).u.c.radius = d/2; anchors(1).u.c.center = p1; anchors(1).width = 0; DYNARR_SET(trkSeg_t,anchors_da,anchors_da.cnt+5); DrawArrowHeads(&DYNARR_N(trkSeg_t,anchors_da,anchors_da.cnt-5),pm,FindAngle(pm,pc),TRUE,index==2?wDrawColorAqua:wDrawColorBlue); } void static CreatePolyAnchors(int index) { DYNARR_RESET(trkSeg_t,anchors_da); double d = tempD.scale*0.15; for ( int inx=0; inx=0) { DYNARR_APPEND(trkSeg_t,anchors_da,1); int inx = anchors_da.cnt-1; anchors(inx).type = SEG_STRLIN; anchors(inx).u.l.pos[0] = points(index==0?points_da.cnt-1:index-1).pt; anchors(inx).u.l.pos[1] = points(index).pt; anchors(inx).color = wDrawColorBlue; anchors(inx).width = 0; DYNARR_APPEND(trkSeg_t,anchors_da,1); inx = anchors_da.cnt-1; int index0 = index==0?points_da.cnt-1:index-1; ANGLE_T an0 = FindAngle(points(index0).pt, points(index).pt); ANGLE_T an1 = FindAngle(points(index0==0?points_da.cnt-1:index0-1).pt, points(index0).pt); anchors(inx).type = SEG_CRVLIN; if (DifferenceBetweenAngles(an0,an1)<=0) { anchors(inx).u.c.a1 = DifferenceBetweenAngles(an0,an1)-180; anchors(inx).u.c.a0 = an0; } else { anchors(inx).u.c.a1 = 180-DifferenceBetweenAngles(an0,an1); anchors(inx).u.c.a0 = NormalizeAngle(180+an1); } anchors(inx).color = wDrawColorBlue; anchors(inx).u.c.radius = d; anchors(inx).u.c.center = points(index0).pt; } } void CreateMovingAnchor(coOrd pos,BOOL_T fill) { double d = tempD.scale*0.15; DYNARR_APPEND(trkSeg_t,anchors_da,1); int inx = anchors_da.cnt-1; anchors(inx).type = fill?SEG_FILCRCL:SEG_CRVLIN; anchors(inx).u.c.a0 = 0.0; anchors(inx).u.c.a1 = 360.0; anchors(inx).width = 0; anchors(inx).color = wDrawColorBlue; anchors(inx).u.c.radius = d/4; anchors(inx).u.c.center = pos; } /* * Modify Polygons. Polygons have a variable number of nodes. * * Each point has an anchor and selecting the node allows it to be moved * Selecting a point between nodes adds a node ready for dragging * The last selected node can be deleted * */ STATUS_T DrawGeomPolyModify( wAction_t action, coOrd pos, drawModContext_t *context) { double d; static int selected_count; static int segInx; static int prev_inx; static wDrawColor save_color; static wBool_t drawnAngle; static double currentAngle; static double baseAngle; static BOOL_T lock; switch ( action&0xFF ) { case C_START: lock = FALSE; DistanceSegs( context->orig, context->angle, context->segCnt, context->segPtr, &pos, &segInx ); if (segInx == -1) return C_ERROR; if (context->type != SEG_POLY && context->type != SEG_FILPOLY) return C_ERROR; prev_inx = -1; polyState = POLY_SELECTED; polyInx = -1; //Copy points DYNARR_RESET( pts_t, points_da); DYNARR_RESET( wBool_t, select_da); for (int inx=0;inxsegPtr->u.p.cnt;inx++) { DYNARR_APPEND(pts_t, points_da,3); DYNARR_APPEND(wBool_t,select_da,3); REORIGIN( points(inx).pt, context->segPtr[segInx].u.p.pts[inx].pt, context->angle, context->orig ); points(inx).pt_type = context->segPtr[segInx].u.p.pts[inx].pt_type; point_selected(inx) = FALSE; } context->prev_inx = -1; context->max_inx = points_da.cnt-1; selected_count=0; rotate_origin = context->orig; rotate_angle = context->angle; context->p0 = points(0).pt; context->p1 = points(1).pt; //Show points tempSegs_da.cnt = 1; tempSegs(0).width = context->segPtr->width; save_color = context->segPtr->color; tempSegs(0).color = wDrawColorRed; tempSegs(0).type = context->type; tempSegs(0).u.p.cnt = context->segPtr[segInx].u.p.cnt; tempSegs(0).u.p.angle = 0.0; tempSegs(0).u.p.orig = zero; tempSegs(0).u.p.polyType = context->segPtr[segInx].u.p.polyType; tempSegs(0).u.p.pts = &points(0); CreatePolyAnchors( -1); InfoMessage(_("Select points or use context menu")); ClrAllTrkBitsRedraw( TB_UNDRAWN, TRUE ); UndrawNewTrack( context->trk ); return C_CONTINUE; case wActionMove: DYNARR_RESET(trkSeg_t,anchors_da); CreatePolyAnchors(context->prev_inx); for (int i = 0; i ddm ) { dm = ddm; pm1 = pm0; pInx = inx; } } if (!IsClose(dm)) return C_CONTINUE; int inxm = pInx==0?points_da.cnt-1:pInx-1; dm = FindDistance( points(inxm).pt, pm1 ); DIST_T ddm = FindDistance( points(inxm).pt, points(pInx).pt ); if ( (dm > 0.25*ddm) && (dm < 0.75*ddm)) { CreateMovingAnchor(pm1,FALSE); } else { if (dm < FindDistance( points(pInx).pt, pm1 )) CreateMovingAnchor(points(inxm).pt,TRUE); else CreateMovingAnchor(points(pInx).pt,TRUE); } return C_CONTINUE; break; case C_DOWN: d = 10000.0; polyInx = -1; coOrd p0; double dd; int inx; if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) != WKEY_SHIFT) { if (selected_count <2 ) { //Wipe out selection(s) if we don't have multiple already (i,e. move with >1 selected) for (int i=0;i dd ) { d = dd; polyInx = inx; } } if (!IsClose(d)) { //Not on/near object - de-select all points for (int i=0;iprev_inx = -1; return C_CONTINUE; //Not close to any line } polyState = POLYPOINT_SELECTED; inx = polyInx==0?points_da.cnt-1:polyInx-1; //Find if the point is to be added d = FindDistance( points(inx).pt, pos ); dd = FindDistance( points(inx).pt, points(polyInx).pt ); if ( d < 0.25*dd ) { polyInx = inx; } else if ( d > 0.75*dd ) { ; } else { if (selected_count == 0) { //Only add a new point if no points are already selected! DYNARR_APPEND(wBool_t,select_da,1); for (int i=0;ipolyInx; inx-- ) { points(inx) = points(inx-1); } points(polyInx).pt_type = wPolyLineStraight; tempSegs(0).u.p.cnt = points_da.cnt; context->max_inx = points_da.cnt-1; } } //If already selected (multiple points), not using shift (to add) select, and on object move to first point if (selected_count>0 && ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) != WKEY_SHIFT)) { for (int i=0; i0 && selected_count < points_da.cnt-2) { for (int i=0; i=0) { if (first_inx == 0) { last_inx = points_da.cnt-1; } else { last_inx = first_inx-1; } if (first_inx == points_da.cnt-1) { next_inx = 0; } else { next_inx = first_inx+1; } context->length = FindDistance(points(last_inx).pt,points(first_inx).pt); an1 = FindAngle(points(last_inx).pt,points(first_inx).pt); an0 = FindAngle(points(last_inx==0?(points_da.cnt-1):(last_inx-1)).pt,points(last_inx).pt); if (DifferenceBetweenAngles(an0,an1)<=0) { context->rel_angle = 180+DifferenceBetweenAngles(an0,an1); } else { context->rel_angle = 180-DifferenceBetweenAngles(an0,an1); } } else { } context->prev_inx = first_inx; context->p0 = points(0).pt; context->p1 = points(1).pt; //Show three anchors only CreatePolyAnchors(first_inx); return C_CONTINUE; case C_LDOUBLE: return C_CONTINUE; case C_MOVE: tempSegs_da.cnt = 1; if (polyState != POLYPOINT_SELECTED) { return C_CONTINUE; } //Moving with Point Selected if (polyInx<0) return C_ERROR; first_inx = -1; if (selected_count >0 && selected_count < points_da.cnt-2) { for (int i=0; i=0) { if (first_inx == 0) { last_inx = points_da.cnt-1; } else { last_inx = first_inx-1; } if (first_inx == points_da.cnt-1) { next_inx = 0; } else { next_inx = first_inx+1; } //Lock to 90 degrees first/last point if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_SHIFT ) { ANGLE_T last_angle,next_angle; coOrd last_point,next_point; if (first_inx == 0) { last_point = points(points_da.cnt-1).pt; last_angle = FindAngle(points(points_da.cnt-2).pt,last_point); } else if (first_inx == 1) { last_point = points(0).pt; last_angle = FindAngle(points(points_da.cnt-1).pt,last_point); } else { last_point = points(first_inx-1).pt; last_angle = FindAngle(points(first_inx-2).pt,last_point); } if (first_inx == points_da.cnt-1) { next_point = points(0).pt; next_angle = FindAngle(next_point,points(1).pt); } else if (first_inx == points_da.cnt-2){ next_point = points(points_da.cnt-1).pt; next_angle = FindAngle(next_point,points(0).pt); } else { next_point = points(first_inx+1).pt; next_angle = FindAngle(next_point,points(first_inx+2).pt); } coOrd diff; diff.x = pos.x - points(polyInx).pt.x; diff.y = pos.y - points(polyInx).pt.y; coOrd pos_lock = points(first_inx).pt; pos_lock.x += diff.x; pos_lock.y += diff.y; //Snap to Right-Angle from previous or from 0 DIST_T l = FindDistance(last_point, pos_lock); ANGLE_T angle2 = NormalizeAngle(FindAngle(last_point, pos_lock)-last_angle); int quad = (int)((angle2+45.0)/90.0); if (tempSegs_da.cnt != 1 && (quad == 2)) { pos_lock = last_point; } else if (quad == 1 || quad == 3) { l = fabs(l*cos(D2R(((quad==1)?last_angle+90.0:last_angle-90.0)-FindAngle(pos_lock,last_point)))); Translate( &pos_lock, last_point, NormalizeAngle((quad==1)?last_angle+90.0:last_angle-90.0), l ); } else { l = fabs(l*cos(D2R(((quad==0||quad==4)?last_angle:last_angle+180.0)-FindAngle(pos_lock,last_point)))); Translate( &pos_lock, last_point, NormalizeAngle((quad==0||quad==4)?last_angle:last_angle+180.0), l ); } diff.x = pos_lock.x - points(first_inx).pt.x; diff.y = pos_lock.y - points(first_inx).pt.y; pos.x = points(polyInx).pt.x+diff.x; pos.y = points(polyInx).pt.y+diff.y; if (selected_count<2) { if (FindIntersection(&intersect,last_point,last_angle+90.0,next_point,last_angle+180.0)) { show_intersect = TRUE; } } d = FindDistance(intersect,pos_lock); if (IsClose(d)) { pos = intersect; } InfoMessage( _("Length = %s, Last angle = %0.2f"), FormatDistance(FindDistance(pos_lock,last_point)), PutAngle(FindAngle(pos_lock,last_point))); } } context->prev_inx = first_inx; coOrd diff; diff.x = pos.x - points(polyInx).pt.x; diff.y = pos.y - points(polyInx).pt.y; //points(polyInx) = pos; for (int i=0;i=0) { context->length = FindDistance(points(first_inx).pt,points(last_inx).pt); an1 = FindAngle(points(last_inx).pt,points(first_inx).pt); an0 = FindAngle(points(first_inx==0?(points_da.cnt-1):(first_inx-1)).pt,points(first_inx).pt); context->rel_angle = NormalizeAngle(180-(an1-an0)); } CreatePolyAnchors(first_inx); if (show_intersect) CreateSquareAnchor(intersect); context->p0 = points(0).pt; context->p1 = points(1).pt; return C_CONTINUE; case C_UP: context->prev_inx = -1; if (segInx == -1 || polyState != POLYPOINT_SELECTED) return C_CONTINUE; //Didn't get a point selected/added polyState = POLY_SELECTED; //Return to base state anchors_da.cnt = 0; CreatePolyAnchors(polyInx); //Show last selection prev_inx = polyInx; for (int i=0;i=0) { context->length = FindDistance(points(first_inx).pt,points(last_inx).pt); an1 = FindAngle(points(last_inx).pt,points(first_inx).pt); an0 = FindAngle(points(last_inx==0?(points_da.cnt-1):(last_inx-1)).pt,points(last_inx).pt); if (DifferenceBetweenAngles(an0,an1)<=0) { context->rel_angle = 180+DifferenceBetweenAngles(an0,an1); } else { context->rel_angle = 180-DifferenceBetweenAngles(an0,an1); } } context->prev_inx = first_inx; context->p0 = points(0).pt; context->p1 = points(1).pt; polyInx = -1; return C_CONTINUE; case C_UPDATE: if (context->prev_inx>=0) { int last_index = context->prev_inx==0?(points_da.cnt-1):(context->prev_inx-1); an0 = FindAngle(points(last_index==0?(points_da.cnt-1):(last_index-1)).pt,points(last_index).pt); an1 = FindAngle(points(last_index).pt,points(context->prev_inx).pt); if (DifferenceBetweenAngles(an0,an1)<=0) { an1 = NormalizeAngle(an0-(180-context->rel_angle)); } else { an1 = NormalizeAngle((180-context->rel_angle)+an0); } Translate(&points(prev_inx).pt,points(last_index).pt,an1,context->length); } context->rel_angle = fabs(context->rel_angle); if (context->rel_angle >180) context->rel_angle = context->rel_angle - 180.0; CreatePolyAnchors(prev_inx); context->p0 = points(0).pt; context->p1 = points(1).pt; break; case C_TEXT: if (action>>8 == 'o') { //"o" -> origin mode MenuMode(1); InfoMessage("Move Origin Mode: Place Origin, p for Points, Enter or Esc"); return C_CONTINUE; } if (((prev_inx>=0 && tempSegs(0).u.p.polyType != POLYLINE) || (prev_inx>=1 && prev_inx<=points_da.cnt-2)) && ((action>>8 == 's') || (action>>8 == 'v') || (action>>8 == 'r'))) { switch(action>>8) { case 's': points(context->prev_inx).pt_type = wPolyLineSmooth; break; case 'v': points(context->prev_inx).pt_type = wPolyLineStraight; break; case 'r': points(context->prev_inx).pt_type = wPolyLineRound; break; default: return C_CONTINUE; } } if ((action>>8 == 'g') && (tempSegs(0).type == SEG_POLY) && (tempSegs(0).u.p.polyType == POLYLINE) ) { tempSegs(0).u.p.polyType = FREEFORM; context->subtype=FREEFORM; context->open = FALSE; CreatePolyAnchors( -1); return C_CONTINUE; } if ((action>>8 == 'l') && (tempSegs(0).type == SEG_POLY) && (tempSegs(0).u.p.polyType == FREEFORM)) { tempSegs(0).u.p.polyType = POLYLINE; context->subtype=POLYLINE; context->open = TRUE; CreatePolyAnchors( -1); return C_CONTINUE; } if ((action>>8 == 'f') && (tempSegs(0).type == SEG_POLY) && (tempSegs(0).u.p.polyType != POLYLINE )) { tempSegs(0).type = SEG_FILPOLY; context->type = SEG_FILPOLY; context->filled = TRUE; CreatePolyAnchors( -1); return C_CONTINUE; } if ((action>>8 == 'u') && (tempSegs(0).type == SEG_FILPOLY) ) { tempSegs(0).type = SEG_POLY; context->type = SEG_POLY; context->filled = FALSE; CreatePolyAnchors( -1); return C_CONTINUE; } //Delete or backspace deletes last selected index if (action>>8 == 127 || action>>8 == 8) { if (polyState == POLY_SELECTED && prev_inx >=0) { if (selected_count >1) { ErrorMessage( MSG_POLY_MULTIPLE_SELECTED ); return C_CONTINUE; } if (points_da.cnt <= 3) { ErrorMessage( MSG_POLY_SHAPES_3_SIDES ); return C_CONTINUE; } for (int i=0;i=prev_inx && imax_inx = points_da.cnt-1; } prev_inx = -1; context->prev_inx = -1; polyInx = -1; polyState = POLY_SELECTED; CreatePolyAnchors( -1); InfoMessage(_("Point Deleted")); return C_CONTINUE; } if (action>>8 != 32 && action>>8 != 13) return C_CONTINUE; /* no break */ case C_FINISH: //copy changes back into track if (polyState != POLY_SELECTED) return C_TERMINATE; pts_t * oldPts = context->segPtr[segInx].u.p.pts; void * newPts = (pts_t*)MyMalloc( points_da.cnt * sizeof (pts_t) ); context->segPtr[segInx].u.p.pts = newPts; context->segPtr->u.p.cnt = points_da.cnt; context->orig = rotate_origin; context->angle = rotate_angle; for (int i=0; iorig.x; pos.y -= context->orig.y; Rotate( &pos, zero, -context->angle ); context->segPtr[segInx].u.p.pts[i].pt = pos; context->segPtr[segInx].u.p.pts[i].pt_type = points(i).pt_type; } MyFree(oldPts); oldPts = NULL; polyState = POLY_NONE; DYNARR_RESET(trkSeg_t,anchors_da); DYNARR_RESET(trkSeg_t,tempSegs_da); DrawNewTrack( context->trk ); return C_TERMINATE; case C_REDRAW: if (polyState == POLY_NONE) return C_CONTINUE; DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt,trackGauge, wDrawColorBlack); DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); break; default: ; } return C_CONTINUE; } void BuildCircleContext(drawModContext_t * context,int segInx) { context->radius = fabs(context->segPtr[segInx].u.c.radius); REORIGIN( context->pc, context->segPtr[segInx].u.c.center, context->angle, context->orig ); PointOnCircle( &context->p0, context->segPtr[segInx].u.c.center, fabs(context->segPtr[segInx].u.c.radius), context->segPtr[segInx].u.c.a0 ); REORIGIN( context->p0, context->p0, context->angle, context->orig ); PointOnCircle( &context->p1, context->segPtr[segInx].u.c.center, fabs(context->segPtr[segInx].u.c.radius), context->segPtr[segInx].u.c.a0 + context->segPtr[segInx].u.c.a1); REORIGIN( context->p1, context->p1, context->angle, context->orig ); if (context->segPtr[segInx].u.c.a1<360) { context->arc_angle = context->segPtr[segInx].u.c.a1; PointOnCircle( &context->pm, context->segPtr[segInx].u.c.center, fabs(context->segPtr[segInx].u.c.radius), context->segPtr[segInx].u.c.a0 + (context->segPtr[segInx].u.c.a1/2)); REORIGIN( context->pm, context->pm, context->angle, context->orig ); coOrd cm; cm = context->pm; ANGLE_T a = FindAngle(context->p1,context->p0); Rotate(&cm,context->p1,-a ); context->disp = cm.x-context->p1.x; } else { context->pm = context->p0; context->disp = 0; context->arc_angle = 360.0; } } void CreateSelectedAnchor(coOrd pos) { double d = tempD.scale*0.15; DYNARR_APPEND(trkSeg_t,anchors_da,1); int inx = anchors_da.cnt-1; anchors(inx).type = SEG_FILCRCL; anchors(inx).u.c.a0 = 0.0; anchors(inx).u.c.a1 = 360.0; anchors(inx).color = wDrawColorBlue; anchors(inx).u.c.radius = d/2; anchors(inx).u.c.center = pos; } /* * Rotate Object Dialogs. * * Each Draw object has a rotation origin which all the points are offset from. * Formerly this has been set to the origin, but it doesn't have to be. By setting * to a point on the shape this allows assembly by aligning parts to a common point on a base object. * The angle is always set to zero when the Modify finishes but can be altered via Describe. * * First locate the origin, and then place a rotation arm which is (optionally) rotated about the origin. * Also supports whole object translate using translate anchor. **/ STATUS_T DrawGeomOriginMove( wAction_t action, coOrd pos, drawModContext_t * context) { switch ( action&0xFF ) { case C_START: context->state = MOD_ORIGIN; context->rotate_state = TRUE; context->rot_moved = TRUE; DYNARR_RESET(trkSeg_t,anchors_da); CreateOriginAnchor(context->rot_center,FALSE); if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) { CreateSelectedAnchor(points(context->prev_inx).pt); } InfoMessage("Move Origin Mode: Place Origin, 0-4, c or l, Enter or Esc"); return C_CONTINUE; break; case wActionMove: CreateOriginAnchor(context->rot_center, TRUE); if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) { CreateSelectedAnchor(points(context->prev_inx).pt); } return C_CONTINUE; break; case C_DOWN: if (context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG) { context->state = MOD_ORIGIN; DYNARR_RESET(trkSeg_t,anchors_da); if (IsClose(FindDistance(pos,context->rot_center))) { pos = context->rot_center; } else { context->rot_center = pos; } CreateOriginAnchor(context->rot_center, TRUE); if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) { CreateSelectedAnchor(points(context->prev_inx).pt); } } return C_CONTINUE; break; case C_MOVE: if (context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG){ context->rot_center = pos; DYNARR_RESET(trkSeg_t,anchors_da); CreateOriginAnchor(context->rot_center, TRUE); if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) { CreateSelectedAnchor(points(context->prev_inx).pt); } } return C_CONTINUE; break; case C_UP: DYNARR_RESET(trkSeg_t,anchors_da); if (context->state == MOD_ORIGIN) { context->state = MOD_AFTER_ORIG; } CreateOriginAnchor(context->rot_center,FALSE); if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) { CreateSelectedAnchor(points(context->prev_inx).pt); } return C_CONTINUE; break; case C_UPDATE: DYNARR_RESET(trkSeg_t,anchors_da); if (context->state == MOD_AFTER_ORIG) { if (context->rot_center.x != context->rel_center.x && context->rot_center.y != context->rel_center.y ) { context->rel_center = context->rot_center; CreateOriginAnchor(context->rot_center, FALSE); if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) { CreateSelectedAnchor(points(context->prev_inx).pt); } } } return C_CONTINUE; break; case C_TEXT: if ((context->state == MOD_ORIGIN || context->state == MOD_AFTER_ORIG) && ((action>>8 >= '0' && action>>8 <= '1') || action>>8 == 'l' || action>>8 == 'm' || action>>8 == 'p')) { // 0,1,2,3,4 -> reset rot center if (action>>8 == '0') { context->rot_center = zero; } else if (action>>8 == '1') { context->rot_center = context->p0; } else if (action>>8 == '2') { context->rot_center = context->p1; } else if (tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) { if (action>>8 == '3' || action>>8 == '4') { context->rot_center = action>>8 == '3'?points(2).pt:points(3).pt; } else if (action>>8 == 'l') { //"l" - last selected if (context->prev_inx !=-1) { context->rot_center = points(context->prev_inx).pt; } } else if (action>>8 == 'm') { context->rot_center = FindCentroid(points_da.cnt,&points(0)); } } if (action>>8 == 'p') { //"p" - points mode MenuMode(0); return C_CONTINUE; } context->rel_center = context->rot_center; context->rot_angle = 0; DYNARR_RESET(trkSeg_t,anchors_da); context->state = MOD_AFTER_ORIG; CreateOriginAnchor(context->rot_center, FALSE); if ((tempSegs(0).type == SEG_POLY || tempSegs(0).type == SEG_FILPOLY) && (context->prev_inx>=0)) { CreateSelectedAnchor(points(context->prev_inx).pt); } return C_CONTINUE; } break; case C_FINISH: context->rotate_state = FALSE; context->state = MOD_STARTED; return C_CONTINUE; break; default: break; } return C_CONTINUE; } /* * Base Modify function for Draw objects. */ STATUS_T DrawGeomModify( wAction_t action, coOrd pos, drawModContext_t * context) { ANGLE_T a; coOrd p0, p1, pc, pm; static coOrd start_pos; static wIndex_t segInx; static EPINX_T segEp; static ANGLE_T segA1; static int inx_other, inx_line, inx_origin; static BOOL_T corner_mode; static BOOL_T polyMode; static ANGLE_T original_angle; int inx, inx1, inx2; DIST_T d, d1, d2, dd; coOrd * newPts = NULL; tempSegs_da.cnt = 1; switch ( action&0xFF ) { case C_START: if (!context->rotate_state && !context->rot_moved) { context->rot_center.x = context->orig.x; context->rot_center.y = context->orig.y; } context->state = MOD_STARTED; context->rotate_state = FALSE; context->last_inx=-1; lineInx = -1; curveInx = -1; segInx = -1; polyMode = FALSE; DistanceSegs( context->orig, context->angle, context->segCnt, context->segPtr, &pos, &segInx ); if (segInx == -1) return C_ERROR; context->type = context->segPtr[segInx].type; switch(context->type) { case SEG_TBLEDGE: case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: REORIGIN( p0, context->segPtr[segInx].u.l.pos[0], context->angle, context->orig ); REORIGIN( p1, context->segPtr[segInx].u.l.pos[1], context->angle, context->orig ); tempSegs(0).type = SEG_STRLIN; tempSegs(0).color = wDrawColorRed; tempSegs(0).u.l.pos[0] = p0; tempSegs(0).u.l.pos[1] = p1; tempSegs(0).width = 0; tempSegs_da.cnt = 1; context->p0 = p0; context->p1 = p1; CreateLineAnchors(-1,p0,p1); break; case SEG_CRVLIN: case SEG_FILCRCL: BuildCircleContext(context,segInx); tempSegs(0).type = SEG_CRVLIN; tempSegs(0).color = wDrawColorRed; tempSegs(0).u.c.center = context->pc; tempSegs(0).u.c.radius = context->radius; tempSegs(0).u.c.a0 = context->segPtr[segInx].u.c.a0; tempSegs(0).u.c.a1 = context->segPtr[segInx].u.c.a1; tempSegs(0).width = 0; tempSegs_da.cnt = 1; if (tempSegs(0).u.c.a1<360.0) { CreateCurveAnchors(-1,context->pm,context->pc,context->p0,context->p1); } else CreateCircleAnchor(FALSE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,FindAngle(tempSegs(0).u.c.center,pos)); context->last_inx = 2; break; case SEG_POLY: case SEG_FILPOLY: if (context->segPtr[segInx].u.p.polyType !=RECTANGLE) { polyMode = TRUE; return DrawGeomPolyModify(action,pos,context); } else { tempSegs(0).type = SEG_POLY; tempSegs(0).color = wDrawColorRed; DYNARR_RESET( pts_t, points_da); for (int inx=0;inxsegPtr->u.p.cnt;inx++) { DYNARR_APPEND(pts_t, points_da,3); REORIGIN( points(inx).pt, context->segPtr[segInx].u.p.pts[inx].pt, context->angle, context->orig ); } tempSegs(0).u.p.pts = &points(0); tempSegs(0).u.p.cnt = points_da.cnt; tempSegs(0).width = 0; tempSegs_da.cnt = 1; context->p0 = points(0).pt; CreateBoxAnchors(-1,&context->segPtr[segInx].u.p.pts[0]); context->p0 = points(0).pt; context->p1 = points(1).pt; } break; case SEG_TEXT: InfoMessage("Text can only be modified with Describe"); wBeep(); return C_ERROR; default: ; } InfoMessage("Points Mode - Select and drag Anchor Point"); return C_CONTINUE; break; case wActionMove: if (context->rotate_state) return DrawGeomOriginMove(action,pos,context); if (polyMode) return DrawGeomPolyModify(action,pos,context); DYNARR_RESET(trkSeg_t,anchors_da); switch( context->type) { case SEG_TBLEDGE: case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: DYNARR_RESET(trkSeg_t,anchors_da); CreateLineAnchors(lineInx,context->p0,context->p1); dd = FindDistance( context->p0, pos ); if ( IsClose(dd)) { CreateMovingAnchor(context->p0,TRUE); } else { dd = FindDistance( context->p1, pos ); if ( IsClose(dd)) { CreateMovingAnchor(context->p1,TRUE); } } break; case SEG_CRVLIN: case SEG_FILCRCL: DYNARR_RESET(trkSeg_t,anchors_da); if (tempSegs(0).u.c.a1 < 360.0) CreateCurveAnchors(curveInx,context->pm,context->pc,context->p0,context->p1); dd = FindDistance( context->p0, pos ); if ( IsClose(dd)) { CreateMovingAnchor(context->p0,TRUE); } else { dd = FindDistance( context->p1, pos ); if ( IsClose(dd)) { CreateMovingAnchor(context->p1,TRUE); } else { dd = FindDistance( context->pm, pos ); if ( IsClose(dd)) { CreateMovingAnchor(context->pm,TRUE); } } } break; case SEG_POLY: case SEG_FILPOLY:; CreateBoxAnchors(-1,&points(0)); break; default:; } return C_CONTINUE; break; case C_DOWN: if (context->rotate_state) return DrawGeomOriginMove(action,pos,context); if (polyMode) return DrawGeomPolyModify(action,pos,context); corner_mode = FALSE; segInx = 0; context->state = MOD_STARTED; tempSegs(0).width = context->segPtr[segInx].width; tempSegs(0).color = context->segPtr[segInx].color; switch ( context->type ) { case SEG_TBLEDGE: if ( MyGetKeyState() & WKEY_CTRL ) OnTableEdgeEndPt( NULL, &pos ); case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: p0 = context->p0; p1 = context->p1; lineInx = -1; dd = FindDistance( p0, pos ); if ( IsClose(dd)) { lineInx = 0; } else { dd = FindDistance( p1, pos ); if ( IsClose(dd)) { lineInx = 1; } } if (lineInx < 0 ) { InfoMessage( _("Not close to end of line")); } else { InfoMessage("End selected, drag to reposition"); context->state = MOD_SELECTED_PT; } tempSegs(0).color = wDrawColorBlack; tempSegs(0).width = 0; tempSegs(0).type = context->type; tempSegs(0).u.l.pos[0] = p0; tempSegs(0).u.l.pos[1] = p1; tempSegs(0).u.l.option = context->segPtr[segInx].u.l.option; segA1 = FindAngle( p1, p0 ); tempSegs_da.cnt = 1; CreateLineAnchors(lineInx,p0,p1); break; case SEG_CRVLIN: case SEG_FILCRCL: curveInx = -1; tempSegs(0).color = wDrawColorBlack; tempSegs(0).width = 0; tempSegs(0).type = context->type; tempSegs(0).u.c.center = context->pc; tempSegs(0).u.c.radius = context->radius; if (context->segPtr[segInx].u.c.a1 >= 360.0) { tempSegs(0).u.c.a0 = 0.0; tempSegs(0).u.c.a1 = 360.0; InfoMessage("Drag to Change Radius"); CreateCircleAnchor(TRUE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,FindAngle(tempSegs(0).u.c.center,pos)); } else { p0 = context->p0; p1 = context->p1; pm = context->pm; pc = context->pc; tempSegs(0).u.c.a0 = FindAngle(context->pc,context->p0); tempSegs(0).u.c.a1 = DifferenceBetweenAngles(FindAngle(context->pc,context->p0),FindAngle(context->pc,context->p1)); tempSegs(0).u.c.center = context->pc; tempSegs(0).u.c.radius = context->radius; curveInx = -1; dd = FindDistance( p0, pos ); if ( IsClose(dd)) { curveInx = 0; } else { dd = FindDistance( p1, pos ); if ( IsClose(dd)) { curveInx = 1; } else { dd = FindDistance( pm, pos ); if ( IsClose(dd)) { curveInx = 2; } } } if (curveInx < 0) { InfoMessage( _("Not close to ends or middle of mine, reselect")); return C_CONTINUE; } else { if (curveInx <2 ) InfoMessage("Drag to move end, +Ctrl to lock to other objects"); else InfoMessage("Drag to change radius"); } tempSegs_da.cnt = 1; if (tempSegs(0).u.c.a1 < 360.0) CreateCurveAnchors(curveInx,pm,pc,p0,p1); } context->state = MOD_SELECTED_PT; break; case SEG_POLY: case SEG_FILPOLY: d = 10000; polyInx = 0; for ( inx=0; inx<4; inx++ ) { if (IsClose(FindDistance(pos,points(inx).pt))) { corner_mode = TRUE; polyInx = inx; break; } p0 = pos; dd = LineDistance( &p0, points( inx==0?3:inx-1).pt, points( inx ).pt ); if ( d > dd ) { d = dd; inx_line = inx; } } if (!corner_mode) { d1 = FindDistance( points(inx_line).pt, pos ); d2 = FindDistance( points(inx_line==0?3:inx_line-1).pt, pos ); if (d2state = MOD_SELECTED_PT; return C_CONTINUE; case SEG_TEXT: segInx = -1; return C_ERROR; default: ASSERT( FALSE ); /* CHECKME */ } if ( FindDistance( p0, pos ) < FindDistance( p1, pos ) ) segEp = 0; else { segEp = 1; switch ( context->type ) { case SEG_TBLEDGE: case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: segA1 = NormalizeAngle( segA1 + 180.0 ); break; default: ; } } UndrawNewTrack( context->trk ); return C_CONTINUE; case C_MOVE: if (context->rotate_state) return DrawGeomOriginMove(action,pos,context); if (polyMode) return DrawGeomPolyModify(action,pos,context); if (context->state != MOD_SELECTED_PT) return C_CONTINUE; switch (tempSegs(0).type) { case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: case SEG_TBLEDGE: if ( (MyGetKeyState() & WKEY_SHIFT) != 0) { d = FindDistance( pos, tempSegs(0).u.l.pos[1-lineInx] ); Translate( &pos, tempSegs(0).u.l.pos[1-lineInx], segA1, d ); } else if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_SHIFT ) { OnTrack( &pos, FALSE, FALSE ); CreateEndAnchor(pos,TRUE); } break; default: break; } int prior_pnt, next_pnt, orig_pnt; ANGLE_T prior_angle, next_angle, line_angle; tempSegs_da.cnt = 1; switch (tempSegs(0).type) { case SEG_TBLEDGE: if ( MyGetKeyState() & WKEY_CTRL ) OnTableEdgeEndPt( NULL, &pos ); /* no break */ case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: if (lineInx<0 || lineInx>1) return C_CONTINUE; tempSegs(0).u.l.pos[lineInx] = pos; InfoMessage( _("Length = %0.3f Angle = %0.3f"), FindDistance( tempSegs(0).u.l.pos[lineInx], tempSegs(0).u.l.pos[1-lineInx] ), FindAngle( tempSegs(0).u.l.pos[1-lineInx], tempSegs(0).u.l.pos[lineInx] ) ); tempSegs_da.cnt = 1; context->p0 = tempSegs(0).u.l.pos[0]; context->p1 = tempSegs(0).u.l.pos[1]; p0 = context->p0; p1 = context->p1; CreateLineAnchors(lineInx, p0, p1); break; case SEG_CRVLIN: case SEG_FILCRCL: if (tempSegs(0).u.c.a1 >= 360.0) { tempSegs(0).u.c.radius = FindDistance( context->pc, pos ); CreateCircleAnchor(TRUE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,FindAngle(tempSegs(0).u.c.center,pos)); } else { if (context->state != MOD_SELECTED_PT) return C_CONTINUE; if (curveInx < 0 || curveInx > 2) return C_CONTINUE; p0 = context->p0; p1 = context->p1; pc = context->pc; pm = context->pm; if ( (MyGetKeyState() & WKEY_SHIFT) != 0) { //Preserve Radius, Change swept angle a = FindAngle( pc, pos ); if (curveInx==0) { tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(pc,p1)-a); tempSegs(0).u.c.a0 = a; } else if (curveInx ==1) { tempSegs(0).u.c.a1 = NormalizeAngle(a-tempSegs(0).u.c.a0); } PointOnCircle(&p0,pc,context->radius,tempSegs(0).u.c.a0); PointOnCircle(&p1,pc,context->radius,tempSegs(0).u.c.a0+tempSegs(0).u.c.a1); context->p0 = p0; context->p1 = p1; PointOnCircle(&pm,pc,context->radius,tempSegs(0).u.c.a0+(tempSegs(0).u.c.a1/2)); context->pm = pm; } else { if (curveInx == 0 || curveInx == 1) { p0 = context->p0; p1 = context->p1; /* Preserve Curve "Deflection" */ d = context->disp; // Original Deflection if (curveInx == 0) { context->p0 = p0 = pos; } else { context->p1 = p1 = pos; } coOrd posx; //Middle of chord posx.x = (p1.x-p0.x)/2.0+p0.x; posx.y = (p1.y-p0.y)/2.0+p0.y; //Middle of chord ANGLE_T a0 = FindAngle( p1, p0 ); DIST_T d0 = FindDistance( p0, p1 )/2.0; DIST_T r = 1000.0; if ( fabs(d) >= 0.01 ) { d2 = sqrt( d0*d0 + d*d )/2.0; r = d2*d2*2.0/d; if ( fabs(r) > 1000.0 ) r = ((r > 0)? 1 : -1) *1000.0; } else { r = ((r > 0) ? 1 : -1 ) *1000.0; } a0 -= 90.0; if (r<0) { coOrd pt = p0; p0 = p1; p1 = pt; a0 += 180.0; } context->radius = tempSegs(0).u.c.radius = fabs(r); Translate( &pc, posx, a0, fabs(r)-fabs(d) ); context->pc = tempSegs(0).u.c.center = pc; tempSegs(0).u.c.a0 = FindAngle(pc,p0); context->arc_angle = tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(pc,p1)-FindAngle(pc,p0)); PointOnCircle(&pm,pc,context->radius,tempSegs(0).u.c.a0+(tempSegs(0).u.c.a1/2.0)); context->pm = pm; } else { //Change radius using chord p0 = context->p0; p1 = context->p1; pm = context->pm; ANGLE_T a0 = FindAngle( p1, p0 ); DIST_T d0 = FindDistance( p0, p1 )/2.0; coOrd pos2 = pos; Rotate( &pos2, p1, -a0 ); pos2.x -= p1.x; DIST_T r = 1000.0; if ( fabs(pos2.x) >= 0.01 ) { d2 = sqrt( d0*d0 + pos2.x*pos2.x )/2.0; r = d2*d2*2.0/pos2.x; if ( fabs(r) > 1000.0 ) r = ((r > 0) ? 1 : -1 ) *1000.0; } else { r = ((r > 0) ? 1 : -1 ) *1000.0; } coOrd posx; //Middle of chord posx.x = (p1.x-p0.x)/2.0 + p0.x; posx.y = (p1.y-p0.y)/2.0 + p0.y; a0 -= 90.0; if (r<0) { coOrd pt = p0; p0 = p1; p1 = pt; a0 += 180.0; } Translate( &pc, posx, a0, fabs(r) - fabs(pos2.x) ); context->pc = tempSegs(0).u.c.center = pc; context->radius = tempSegs(0).u.c.radius = fabs(r); a0 = FindAngle( pc, p0 ); ANGLE_T a1 = FindAngle( pc, p1 ); tempSegs(0).u.c.a0 = a0; tempSegs(0).u.c.a1 = NormalizeAngle(a1-a0); PointOnCircle(&pm,pc,context->radius,a0+(NormalizeAngle(a1-a0)/2)); context->p0 = p0; context->p1 = p1; context->pm = pm; context->disp = pos2.x; } } if (tempSegs(0).u.c.a1 < 360.0) CreateCurveAnchors(curveInx,pm,pc,p0,p1); } break; case SEG_POLY: case SEG_FILPOLY: if (!corner_mode) { /* Constrain movement to be perpendicular */ d = FindDistance(start_pos, pos); line_angle = NormalizeAngle(FindAngle(points(inx_line).pt,points(inx_line==3?0:inx_line+1).pt)); a = FindAngle(pos,start_pos); Translate( &pos, start_pos, line_angle, - d*cos(D2R(line_angle-a))); } d = FindDistance(start_pos,pos); a = FindAngle(start_pos, pos); start_pos = pos; prior_pnt = (polyInx == 0)?3:polyInx-1; next_pnt = (polyInx == 3)?0:polyInx+1; orig_pnt = (prior_pnt == 0)?3:prior_pnt-1; Translate( &points(polyInx).pt, points(polyInx).pt, a, d); d = FindDistance(points(orig_pnt).pt,points(polyInx).pt); a = FindAngle(points(orig_pnt).pt,points(polyInx).pt); prior_angle = FindAngle(points(orig_pnt).pt,points(prior_pnt).pt); Translate( &points(prior_pnt).pt, points(orig_pnt).pt, prior_angle, d*cos(D2R(prior_angle-a))); next_angle = FindAngle(points(orig_pnt).pt,points(next_pnt).pt); Translate( &points(next_pnt).pt, points(orig_pnt).pt, next_angle, d*cos(D2R(next_angle-a))); if (!corner_mode) { pos.x = (points(inx_line).pt.x + points(inx_line==0?3:inx_line-1).pt.x)/2; pos.y = (points(inx_line).pt.y + points(inx_line==0?3:inx_line-1).pt.y)/2; DYNARR_SET(trkSeg_t,anchors_da,5); DrawArrowHeads( &anchors(0), pos, FindAngle(points(inx_line).pt,points(inx_line==0?3:inx_line-1).pt)+90, TRUE, wDrawColorRed ); InfoMessage( _("Drag to Move Edge")); } else { pos = points(polyInx).pt; DYNARR_SET(trkSeg_t,anchors_da,5); DrawArrowHeads( &anchors(0), pos, FindAngle(points(polyInx).pt,points(inx_origin).pt), TRUE, wDrawColorRed ); InfoMessage( _("Drag to Move Corner Point")); } context->p0 = points(0).pt; context->p1 = points(1).pt; break; default: ; } return C_CONTINUE; case C_UP: if (context->rotate_state) return DrawGeomOriginMove(action, pos, context); if (polyMode) { int rc; rc = DrawGeomPolyModify(action,pos,context); if (context->prev_inx != -1) context->state = MOD_AFTER_PT; return rc; } if (segInx == -1) return C_CONTINUE; switch (tempSegs(0).type) { case SEG_TBLEDGE: case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: p0 = context->p0; p1 = context->p1; context->abs_angle = FindAngle(p0,p1); context->length = FindDistance(p0,p1); CreateLineAnchors(lineInx,p0,p1); context->last_inx = lineInx; break; case SEG_CRVLIN: case SEG_FILCRCL: if ( (tempSegs(0).type == SEG_FILCRCL) || (tempSegs(0).u.c.a1 == 360.0 || tempSegs(0).u.c.a1 == 0.0) ) { context->radius = fabs(tempSegs(0).u.c.radius); context->arc_angle = 360.0; CreateCircleAnchor(FALSE,tempSegs(0).u.c.center,tempSegs(0).u.c.radius,FindAngle(tempSegs(0).u.c.center,pos)); } else { p0 = context->p0; p1 = context->p1; pc = context->pc; pm = context->pm; context->radius = fabs(tempSegs(0).u.c.radius); context->arc_angle = tempSegs(0).u.c.a1; CreateCurveAnchors(curveInx,pm,pc,p0,p1); a = FindAngle(p1,p0); Rotate(&pm,p1,-a); context->disp = pm.x-p1.x; } context->last_inx = curveInx; break; case SEG_POLY: case SEG_FILPOLY: CreateBoxAnchors(-1,tempSegs(0).u.p.pts); context->width = FindDistance(tempSegs(0).u.p.pts[0].pt,tempSegs(0).u.p.pts[1].pt); context->height = FindDistance(tempSegs(0).u.p.pts[1].pt,tempSegs(0).u.p.pts[2].pt); context->last_inx = polyInx; if (corner_mode) context->last_inx +=5; break; default: ; } context->state = MOD_AFTER_PT; curveInx = -1; lineInx = -1; polyInx = -1; InfoMessage("Enter/Space to Accept, ESC to Reject"); return C_CONTINUE; case C_UPDATE: if (context->rotate_state) return DrawGeomOriginMove(action, pos, context); if (polyMode) return DrawGeomPolyModify(action,pos,context); if (context->state == MOD_AFTER_PT) { switch (tempSegs(0).type) { case SEG_TBLEDGE: case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: context->abs_angle = NormalizeAngle(context->abs_angle); Translate(&tempSegs(0).u.l.pos[1],tempSegs(0).u.l.pos[0],context->abs_angle,context->length); CreateLineAnchors(context->last_inx,tempSegs(0).u.l.pos[0],tempSegs(0).u.l.pos[1]); context->p0 = tempSegs(0).u.l.pos[0]; context->p1 = tempSegs(0).u.l.pos[1]; break; case SEG_CRVLIN: case SEG_FILCRCL: if (tempSegs(0).u.c.a1 == 360.0 || tempSegs(0).u.c.a1 == 0.0) { tempSegs(0).u.c.a1 = 360.0; tempSegs(0).u.c.radius = context->radius; Translate(&p0,tempSegs(0).u.c.center,tempSegs(0).u.c.a0,tempSegs(0).u.c.radius); context->p0 = p0; context->p1 = p0; context->pm = p0; context->pc = tempSegs(0).u.c.center; break; } if (context->radius < 0) { //swap ends context->radius = fabs(context->radius); p1 = context->p0; p0 = context->p1; a = FindAngle(context->pc,context->pm); Translate(&pm,context->pm,a+180,2*context->disp); Translate(&pc,pm,a,context->radius); context->pm = pm; context->pc = pc; context->p0 = p0; context->p1 = p1; } else { pm = context->pm; pc = context->pc; p0 = context->p0; p1 = context->p1; } if (context->last_inx == 0) { p1 = context->p1; pc = context->pc; a = FindAngle(p1,pc); Translate(&pc,p1,a,context->radius); context->pc = pc; PointOnCircle( &p0, context->pc, context->radius, NormalizeAngle(a+180-context->arc_angle) ); context->p0 = p0; PointOnCircle( &pm, context->pc, context->radius, NormalizeAngle(a+180-(context->arc_angle/2))); context->pm = pm; } else if (context->last_inx == 1) { p0 = context->p0; pc = context->pc; a = FindAngle(p0,pc); Translate(&pc,p0,a,context->radius); context->pc = pc; PointOnCircle( &p1, context->pc, context->radius, NormalizeAngle(a+180+context->arc_angle) ); context->p1 = p1; PointOnCircle( &pm, context->pc, context->radius, NormalizeAngle(a+180+(context->arc_angle/2))); context->pm = pm; } else { // Middle if neither a = FindAngle(context->pm,context->pc); Translate(&pc,context->pm,a,context->radius); context->pc = pc; PointOnCircle( &p1, context->pc, context->radius, NormalizeAngle(FindAngle(context->pc,context->pm)+(context->arc_angle/2)) ); PointOnCircle( &p0, context->pc, context->radius, NormalizeAngle(FindAngle(context->pc,context->pm)-(context->arc_angle/2)) ); context->p1 = p1; context->p0 = p0; } a = FindAngle(p1,p0); Rotate(&pm,p1,-a); context->disp = pm.x-p1.x; tempSegs(0).u.c.center = context->pc; tempSegs(0).u.c.a0 = FindAngle(context->pc,context->p0); tempSegs(0).u.c.a1 = NormalizeAngle(FindAngle(context->pc,context->p1)-tempSegs(0).u.c.a0); if (tempSegs(0).u.c.a1 == 0.0) tempSegs(0).u.c.a1 = 360.0; tempSegs(0).u.c.radius = context->radius; CreateCurveAnchors(context->last_inx,context->pm,context->pc,context->p0,context->p1); break; case SEG_POLY: case SEG_FILPOLY: a = NormalizeAngle(FindAngle(points(0).pt,points(3).pt)); Translate( &points(3).pt, points(0).pt, a, context->height); Translate( &points(2).pt, points(1).pt, a, context->height); a = NormalizeAngle(FindAngle(points(0).pt,points(1).pt));; Translate( &points(1).pt, points(0).pt, a, context->width); Translate( &points(2).pt, points(3).pt, a, context->width); CreateBoxAnchors(context->last_inx,&points(0)); break; default: break; } } break; case C_TEXT: if (context->rotate_state) DrawGeomOriginMove(action, pos, context); if (polyMode) return DrawGeomPolyModify(action,pos,context); if (action>>8 == 'o') { MenuMode(1); } if (action>>8 != 32 && action>>8 != 13) return C_CONTINUE; /* no break */ case C_FINISH: if (polyMode) { DrawGeomPolyModify(action,pos,context); context->segPtr[segInx].type = context->type; context->segPtr[segInx].u.p.polyType = context->subtype; return C_TERMINATE; } //copy changes back into track context->orig.x = context->rot_center.x; context->orig.y = context->rot_center.y; context->rot_moved = FALSE; context->angle = 0.0; switch (tempSegs(0).type) { case SEG_TBLEDGE: case SEG_STRLIN: case SEG_DIMLIN: case SEG_BENCH: for (int i=0;i<2;i++) { pos = i==0?context->p0:context->p1; pos.x -= context->rot_center.x; pos.y -= context->rot_center.y; context->segPtr[segInx].u.l.pos[i] = pos; } break; case SEG_CRVLIN: case SEG_FILCRCL: pc = context->pc; pc.x -= context->rot_center.x; pc.y -= context->rot_center.y; context->segPtr[segInx].u.c.center = pc; p0 = context->p0; p0.x -= context->rot_center.x; p0.y -= context->rot_center.y; p1 = context->p1; p1.x -= context->rot_center.x; p1.y -= context->rot_center.y; context->segPtr[segInx].u.c.a0 = FindAngle(pc,p0); context->segPtr[segInx].u.c.a1 = NormalizeAngle(FindAngle(pc,p1)-FindAngle(pc,p0)); if (context->segPtr[segInx].u.c.a1 == 0) context->segPtr[segInx].u.c.a1 = 360.0; context->segPtr[segInx].u.c.radius = context->radius; break; case SEG_POLY: case SEG_FILPOLY: for (int i=0;i<4;i++) { pos = points(i).pt; pos.x -= context->rot_center.x; pos.y -= context->rot_center.y; context->segPtr[segInx].u.p.pts[i].pt = pos; } break; default: break; } context->state = MOD_NONE; context->rotate_state = FALSE; context->last_inx = -1; DYNARR_RESET(trkSeg_t,anchors_da); DYNARR_RESET(trkSeg_t,tempSegs_da); DrawNewTrack( context->trk ); return C_TERMINATE; case C_REDRAW: if (polyMode) return DrawGeomPolyModify(action,pos,context); if (context->state == MOD_NONE) return C_CONTINUE; DrawSegs( &tempD, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack); DrawSegs( &tempD, zero, 0.0, &anchors(0), anchors_da.cnt, trackGauge, wDrawColorBlack ); break; case C_CANCEL: case C_CONFIRM: case C_TERMINATE: context->state = MOD_NONE; context->rotate_state = FALSE; context->rot_moved = FALSE; DYNARR_RESET(trkSeg_t,anchors_da); DYNARR_RESET(trkSeg_t,tempSegs_da); break; default: ; } return C_CONTINUE; }