diff options
Diffstat (limited to 'app/bin/drawgeom.c')
-rw-r--r-- | app/bin/drawgeom.c | 2347 |
1 files changed, 1996 insertions, 351 deletions
diff --git a/app/bin/drawgeom.c b/app/bin/drawgeom.c index 2342599..d23031f 100644 --- a/app/bin/drawgeom.c +++ b/app/bin/drawgeom.c @@ -37,46 +37,42 @@ static long drawGeomCurveMode; #define contextSegs(N) DYNARR_N( trkSeg_t, context->Segs_da, N ) - - static dynArr_t points_da; -#define points(N) DYNARR_N( coOrd, points_da, N ) +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 ) +static void EndPoly( drawContext_t * context, int cnt, wBool_t open) { trkSeg_p segPtr; track_p trk; - long oldOptions; - coOrd * pts; + pts_t * pts; int inx; if (context->State==0 || cnt == 0) return; - oldOptions = context->D->funcs->options; - context->D->funcs->options |= wDrawOptTemp; - DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - context->D->funcs->options = oldOptions; - - if (IsClose(FindDistance(tempSegs(0).u.l.pos[0], tempSegs(cnt-1).u.l.pos[1] ))) - cnt--; - if ( cnt < 2 ) { + if ( cnt < 3 ) { tempSegs_da.cnt = 0; ErrorMessage( MSG_POLY_SHAPES_3_SIDES ); return; } - pts = (coOrd*)MyMalloc( (cnt+1) * sizeof (coOrd) ); - for ( inx=0; inx<cnt; inx++ ) - pts[inx] = tempSegs(inx).u.l.pos[0]; - pts[cnt] = tempSegs(cnt-1).u.l.pos[1]; + pts = (pts_t*)MyMalloc( (cnt) * sizeof (pts_t) ); + for ( inx=0; inx<cnt; inx++ ) { + pts[inx].pt = tempSegs(inx).u.l.pos[0]; + pts[inx].pt_type = wPolyLineStraight; + } DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); segPtr = &tempSegs(0); - segPtr->type = ( context->Op == OP_POLY ? SEG_POLY: SEG_FILPOLY ); - segPtr->u.p.cnt = cnt+1; + segPtr->type = ( (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 = FREEFORM; + segPtr->u.p.polyType = open?POLYLINE:FREEFORM; UndoStart( _("Create Lines"), "newDraw" ); trk = MakeDrawFromSeg( zero, 0.0, segPtr ); DrawNewTrack( trk ); @@ -100,6 +96,80 @@ static void DrawGeomOk( void ) tempSegs_da.cnt = 0; } +static void CreateEndAnchor(coOrd p, wBool_t lock) { + DIST_T d = tempD.scale*0.15; + + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = lock?SEG_FILCRCL:SEG_CRVLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.c.center = p; + anchors(i).u.c.radius = d/2; + anchors(i).u.c.a0 = 0.0; + anchors(i).u.c.a1 = 360.0; + anchors(i).width = 0; +} + +static void CreateLineAnchor(coOrd p, coOrd p0) { + DIST_T d = tempD.scale*0.15; + coOrd p1; + ANGLE_T a = FindAngle(p0,p); + Translate(&p1,p,a,d*5); + DYNARR_APPEND(trkSeg_t,anchors_da,1); + int i = anchors_da.cnt-1; + anchors(i).type = SEG_STRLIN; + anchors(i).color = wDrawColorBlue; + anchors(i).u.l.pos[0] = p; + anchors(i).u.l.pos[1] = p0; + anchors(i).width = 0; +} + +static void CreateSquareAnchor(coOrd p) { + DIST_T d = tempD.scale*0.15; + int i = anchors_da.cnt; + DYNARR_SET(trkSeg_t,anchors_da,i+4); + for (int j =0; j<4;j++) { + anchors(i+j).type = SEG_STRLIN; + anchors(i+j).color = wDrawColorBlue; + anchors(i+j).width = 0; + } + anchors(i).u.l.pos[0].x = anchors(i+2).u.l.pos[1].x = + anchors(i+3).u.l.pos[0].x = anchors(i+3).u.l.pos[1].x = p.x-d/2; + + anchors(i).u.l.pos[0].y = anchors(i).u.l.pos[1].y = + anchors(i+1).u.l.pos[0].y = anchors(i+3).u.l.pos[1].y = p.y-d/2; + + anchors(i).u.l.pos[1].x = + anchors(i+1).u.l.pos[0].x = anchors(i+1).u.l.pos[1].x = + anchors(i+2).u.l.pos[0].x = p.x+d/2; + + anchors(i+1).u.l.pos[1].y = + anchors(i+2).u.l.pos[0].y = anchors(i+2).u.l.pos[1].y = + anchors(i+3).u.l.pos[0].y = p.y+d/2; +} + +BOOL_T FindTempNear(drawContext_t *context, coOrd *p) { + if (context->State == 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. @@ -108,63 +178,195 @@ static void DrawGeomOk( void ) * \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 ) + drawContext_t *context) { static int lastValid = FALSE; + static wBool_t lock; static coOrd pos0, pos0x, pos1, lastPos; trkSeg_p segPtr; - coOrd *pts; + 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; - long oldOptions; - width = context->Width/context->D->dpi; + 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: - return C_CONTINUE; - - case wActionLDown: - context->Started = TRUE; - if (context->State == 0) { //First Down only - switch (context->Op) { //Snap pos to nearest line end point if this is end and just shift is depressed for lines and some curves - case OP_LINE: + 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: - if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_SHIFT ) { + 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))) { - if (GetClosestEndPt(t,&p)) { - pos = p; + 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 { - if ( (MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) // Control snaps to nearest track (not necessarily the end) - OnTrack( &pos, FALSE, FALSE ); pos0 = pos; pos1 = pos; } @@ -173,9 +375,6 @@ STATUS_T DrawGeomMouse( case OP_LINE: case OP_DIMLINE: case OP_BENCH: - if ( lastValid && ( MyGetKeyState() & WKEY_CTRL ) ) { - pos = pos0 = lastPos; - } DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); switch (context->Op) { case OP_LINE: tempSegs(0).type = SEG_STRLIN; break; @@ -191,12 +390,9 @@ STATUS_T DrawGeomMouse( tempSegs(0).u.l.option = 0; } tempSegs_da.cnt = 0; - context->message( _("Drag to place next end point") ); + context->message( _("Drag to next point, +Shift to lock to object, +Ctrl to lock to 90deg") ); break; case OP_TBLEDGE: - if ( lastValid && ( MyGetKeyState() & WKEY_CTRL ) ) { - pos = pos0 = lastPos; - } OnTableEdgeEndPt( NULL, &pos ); DYNARR_SET( trkSeg_t, tempSegs_da, 1 ); tempSegs(0).type = SEG_TBLEDGE; @@ -214,9 +410,8 @@ STATUS_T DrawGeomMouse( case OP_CURVE3: drawGeomCurveMode = crvCmdFromCenter; break; case OP_CURVE4: drawGeomCurveMode = crvCmdFromChord; break; } - CreateCurve( C_DOWN, pos, FALSE, context->Color, width, drawGeomCurveMode, context->message ); - } else { - tempSegs_da.cnt = segCnt; + 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: @@ -240,6 +435,7 @@ STATUS_T DrawGeomMouse( break; case OP_FILLBOX: width = 0; + /* no break */ case OP_BOX: DYNARR_SET( trkSeg_t, tempSegs_da, 4 ); for ( inx=0; inx<4; inx++ ) { @@ -248,75 +444,172 @@ STATUS_T DrawGeomMouse( tempSegs(inx).width = width; tempSegs(inx).u.l.pos[0] = tempSegs(inx).u.l.pos[1] = pos; } - tempSegs_da.cnt = 0; context->message( _("Drag set box size") ); break; case OP_POLY: case OP_FILLPOLY: + case OP_POLYLINE: tempSegs_da.cnt = segCnt; - DYNARR_APPEND( trkSeg_t, tempSegs_da, 10 ); + 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); - if ( tempSegs_da.cnt == 1 ) { - segPtr->u.l.pos[0] = pos; - } else { - segPtr->u.l.pos[0] = segPtr[-1].u.l.pos[1]; + //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; - oldOptions = context->D->funcs->options; - context->D->funcs->options |= wDrawOptTemp; - DrawSegs( context->D, zero, 0.0, &tempSegs(tempSegs_da.cnt-1), 1, trackGauge, wDrawColorBlack ); - context->D->funcs->options = oldOptions; + segCnt = tempSegs_da.cnt; + context->message(_("+Shift - lock to close object, +Ctrl - lock to 90 deg")); break; } return C_CONTINUE; case wActionLDrag: - oldOptions = context->D->funcs->options; - context->D->funcs->options |= wDrawOptTemp; - if (context->Op == OP_POLY || context->Op == OP_FILLPOLY) - DrawSegs( context->D, zero, 0.0, &tempSegs(tempSegs_da.cnt-1), 1, trackGauge, wDrawColorBlack ); - else - DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - if ( (MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) - OnTrack( &pos, FALSE, FALSE ); + 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) { - CreateCurve( C_MOVE, pos, FALSE, context->Color, width, drawGeomCurveMode, context->message ); 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 )) ); @@ -337,14 +630,21 @@ STATUS_T DrawGeomMouse( ErrorMessage( MSG_CURVE_TOO_LARGE ); tempSegs_da.cnt = 0; context->ArcData.type = curveTypeNone; - context->D->funcs->options = oldOptions; 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: @@ -352,6 +652,7 @@ STATUS_T DrawGeomMouse( 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 ); @@ -369,58 +670,48 @@ STATUS_T DrawGeomMouse( FormatDistance(fabs(pos1.x - pos0.x)), FormatDistance(fabs(pos1.y - pos0.y)) ); break; } - if (context->Op == OP_POLY || context->Op == OP_FILLPOLY) - DrawSegs( context->D, zero, 0.0, &tempSegs(tempSegs_da.cnt-1), 1, trackGauge, wDrawColorBlack ); - else - DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - context->D->funcs->options = oldOptions; - if (context->Op == OP_DIMLINE) MainRedraw(); //Wipe Out Text return C_CONTINUE; case wActionLUp: - oldOptions = context->D->funcs->options; - context->D->funcs->options |= wDrawOptTemp; - if (context->Op != OP_POLY && context->Op != OP_FILLPOLY) - DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); lastValid = FALSE; createTrack = FALSE; - if ((context->State == 0 && (context->Op == OP_LINE )) || //first point release for line, - (context->State == 1 && context->Op == OP_CURVE1)) { //second point for curve from end - switch (context->Op) { //Snap pos to nearest line end point if this is on a line and just shift is depressed for lines and some curves - case OP_CURVE1: - case OP_LINE: - if ((MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_SHIFT ) { - coOrd p = pos1; - track_p t; - if ((t=OnTrack(&p,FALSE,FALSE))) { - if (GetClosestEndPt(t,&p)) { - pos1 = p; - if (context->Op == OP_LINE) { - tempSegs(0).u.l.pos[1] = p; - } else { - PlotCurve( drawGeomCurveMode, pos0, pos0x, pos1, &context->ArcData, FALSE ); - 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; - } else if (context->ArcData.type == curveTypeNone) { - tempSegs_da.cnt = 0; - } 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; - } - } - } + 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; } - }; - break; - default: - ; + } + + } } } switch ( context->Op ) { @@ -430,22 +721,22 @@ STATUS_T DrawGeomMouse( 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, context->message ); - DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - segCnt = tempSegs_da.cnt; + CreateCurve( C_UP, pos, FALSE, context->Color, width, drawGeomCurveMode, &anchors_da, context->message ); context->message( _("Drag on Red arrows to adjust curve") ); - context->D->funcs->options = oldOptions; return C_CONTINUE; } else { - tempSegs_da.cnt = 0; + DYNARR_SET(trkSeg_t,tempSegs_da,1); if (context->ArcData.type == curveTypeCurve) { - tempSegs_da.cnt = 1; segPtr = &tempSegs(0); segPtr->type = SEG_CRVLIN; segPtr->color = context->Color; @@ -454,20 +745,22 @@ STATUS_T DrawGeomMouse( 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) { - tempSegs_da.cnt = 1; 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; - } else { - tempSegs_da.cnt = 0; + context->radius = 0; + context->length = FindDistance(pos0,pos1); + context->angle = FindAngle(pos0,pos1); } - context->State = 0; lastValid = TRUE; lastPos = pos1; + context->State = 2; /*drawContext = context; DrawGeomOp( (void*)context->Op );*/ } @@ -480,14 +773,17 @@ STATUS_T DrawGeomMouse( case OP_FILLCIRCLE3: if ( context->Op>=OP_FILLCIRCLE1 && context->Op<=OP_FILLCIRCLE3 ) tempSegs(0).type = SEG_FILCRCL; - /*drawContext = context; - DrawGeomOp( (void*)context->Op );*/ + tempSegs_da.cnt = 1; + context->State = 2; + context->radius = tempSegs(0).u.c.radius; break; case OP_BOX: case OP_FILLBOX: - pts = (coOrd*)MyMalloc( 4 * sizeof (coOrd) ); - for ( inx=0; inx<4; inx++ ) - pts[inx] = tempSegs(inx).u.l.pos[0]; + 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; @@ -497,188 +793,1259 @@ STATUS_T DrawGeomMouse( 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; - context->D->funcs->options = oldOptions; return C_CONTINUE; } context->Started = FALSE; - context->Changed = TRUE; + context->Changed = TRUE; //Update screen shown /*CheckOk();*/ - context->D->funcs->options = oldOptions; + 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) == ' ' ) { - EndPoly(context, segCnt); - context->State = 0; + 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: - - oldOptions = context->D->funcs->options; - context->D->funcs->options |= wDrawOptTemp; - DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - context->D->funcs->options = oldOptions; + 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: - oldOptions = context->D->funcs->options; - context->D->funcs->options |= wDrawOptTemp; - DrawSegs( context->D, zero, 0.0, &tempSegs(0), tempSegs_da.cnt, trackGauge, wDrawColorBlack ); - context->D->funcs->options = oldOptions; + 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<points_da.cnt; inx++ ) { + DYNARR_APPEND(trkSeg_t,anchors_da,3); + + anchors(inx).type = point_selected(inx)?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/2; + anchors(inx).u.c.center = points(inx).pt; + } + if (index>=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;inx<context->segPtr->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<points_da.cnt; i++) { + if (IsClose(FindDistance(pos,points(i).pt))) { + CreateMovingAnchor(points(i).pt,TRUE); + return C_CONTINUE; + } + } + int pInx=0; + coOrd pm0,pm1; + DIST_T dm = 10000.0; + for ( int inx=0; inx<points_da.cnt; inx++ ) { + pm0 = pos; + DIST_T ddm = LineDistance( &pm0, points( inx==0?points_da.cnt-1:inx-1).pt, points(inx).pt ); + if ( dm > 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<points_da.cnt;i++) { + point_selected(i) = FALSE; + } + selected_count = 0; + } else { + for (int i=0;i<points_da.cnt;i++) { + if (IsClose(FindDistance(pos,points(i).pt)) && point_selected(i)==TRUE) { + point_selected(i) = FALSE; + selected_count--; + } + } + } + } + //Select Point (polyInx) + for ( int inx=0; inx<points_da.cnt; inx++ ) { + p0 = pos; + dd = LineDistance( &p0, points( inx==0?points_da.cnt-1:inx-1).pt, points(inx).pt ); + if ( d > dd ) { + d = dd; + polyInx = inx; + } + } + if (!IsClose(d)) { //Not on/near object - de-select all points + for (int i=0;i<points_da.cnt;i++) { + point_selected(i) = FALSE; + } + polyInx = -1; + selected_count = 0; + CreatePolyAnchors( -1); + context->prev_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;i<select_da.cnt;i++) { + if (i == polyInx) point_selected(i) = TRUE; + else point_selected(i) = FALSE; + } + selected_count=1; + DYNARR_APPEND(pts_t,points_da,1); + tempSegs(0).u.p.pts = &points(0); + for (inx=points_da.cnt-1; inx>polyInx; 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; i<points_da.cnt;i++) { + if (IsClose(FindDistance(pos,points(i).pt))) { + + point_selected(i) = FALSE; + + } + if (point_selected(i) == TRUE) { + polyInx = i; + } + } + } + pos = points(polyInx).pt; //Move to point + if (point_selected(polyInx)) { //Already selected + } else { + point_selected(polyInx) = TRUE; + ++selected_count; + } + //Work out before and after point + int first_inx = -1; + if (selected_count >0 && selected_count < points_da.cnt-2) { + for (int i=0; i<points_da.cnt;i++) { + if (point_selected(i)) { + first_inx = i; + break; + } + } + } + int last_inx = -1, next_inx = -1; + ANGLE_T an1, an0; + if (first_inx >=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<points_da.cnt;i++) { + if (point_selected(i)) { + first_inx = i; + break; + } + } + } + last_inx = -1; + next_inx = -1; + coOrd intersect; + wBool_t show_intersect = FALSE; + if (first_inx >=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<points_da.cnt;i++) { + if (point_selected(i)) { + points(i).pt.x = points(i).pt.x + diff.x; + points(i).pt.y = points(i).pt.y + diff.y; + } + } + if (first_inx>=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<points_da.cnt;i++) { + if (point_selected(i)) { + first_inx = i; + break; + } + } + last_inx = first_inx==0?(points_da.cnt-1):(first_inx-1); + if (first_inx>=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<points_da.cnt;i++) { + point_selected(i) = FALSE; + if (i>=prev_inx && i<points_da.cnt-1) + points(i) = points(i+1); + } + points_da.cnt--; + select_da.cnt--; + selected_count=0; + tempSegs(0).u.p.cnt = points_da.cnt; + context->max_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; i<points_da.cnt; i++) { + pos = points(i).pt; + pos.x -= context->orig.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( - coOrd orig, - ANGLE_T angle, - wIndex_t segCnt, - trkSeg_p segPtr, wAction_t action, coOrd pos, - wBool_t selected) + drawModContext_t * context) { ANGLE_T a; - coOrd p0, p1, pc; + coOrd p0, p1, pc, pm; static coOrd start_pos; static wIndex_t segInx; static EPINX_T segEp; static ANGLE_T segA1; - static int polyInx, inx_other, inx_line, inx_origin; + 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; - int mergePoints; tempSegs_da.cnt = 1; - switch ( action ) { - case C_DOWN: + 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; - corner_mode = FALSE; - DistanceSegs( orig, angle, segCnt, segPtr, &pos, &segInx ); + polyMode = FALSE; + DistanceSegs( context->orig, context->angle, context->segCnt, context->segPtr, &pos, &segInx ); if (segInx == -1) return C_ERROR; - tempSegs(0).width = segPtr[segInx].width; - tempSegs(0).color = segPtr[segInx].color; - switch ( segPtr[segInx].type ) { + 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;inx<context->segPtr->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: - REORIGIN( p0, segPtr[segInx].u.l.pos[0], angle, orig ); - REORIGIN( p1, segPtr[segInx].u.l.pos[1], angle, orig ); - tempSegs(0).type = segPtr[segInx].type; + 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 = segPtr[segInx].u.l.option; + 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: - REORIGIN( pc, segPtr[segInx].u.c.center, angle, orig ) - tempSegs(0).type = segPtr[segInx].type; - tempSegs(0).u.c.center = pc; - tempSegs(0).u.c.radius = fabs(segPtr[segInx].u.c.radius); - if (segPtr[segInx].u.c.a1 >= 360.0) { + 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 { - tempSegs(0).u.c.a0 = NormalizeAngle( segPtr[segInx].u.c.a0+angle ); - tempSegs(0).u.c.a1 = segPtr[segInx].u.c.a1; - segA1 = NormalizeAngle( segPtr[segInx].u.c.a0 + segPtr[segInx].u.c.a1 + angle ); - PointOnCircle( &p0, pc, fabs(segPtr[segInx].u.c.radius), segPtr[segInx].u.c.a0+angle ); - PointOnCircle( &p1, pc, fabs(segPtr[segInx].u.c.radius), segPtr[segInx].u.c.a0+segPtr[segInx].u.c.a1+angle ); + 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: - tempSegs(0).type = segPtr[segInx].type; - tempSegs(0).u.p.cnt = segPtr[segInx].u.p.cnt; - tempSegs(0).u.p.angle = 0.0; - tempSegs(0).u.p.orig = zero; - tempSegs(0).u.p.polyType = segPtr[segInx].u.p.polyType; - DYNARR_SET( coOrd, points_da, segPtr[segInx].u.p.cnt+1 ); - tempSegs(0).u.p.pts = &points(0); d = 10000; polyInx = 0; - for ( inx=0; inx<segPtr[segInx].u.p.cnt; inx++ ) { - REORIGIN( points(inx), segPtr[segInx].u.p.pts[inx], angle, orig ); - } - for ( inx=0; inx<segPtr[segInx].u.p.cnt; inx++ ) { + 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?segPtr[segInx].u.p.cnt-1:inx-1), points( inx ) ); + dd = LineDistance( &p0, points( inx==0?3:inx-1).pt, points( inx ).pt ); if ( d > dd ) { d = dd; - polyInx = inx; + inx_line = inx; } } - if (segPtr[segInx].u.p.polyType == RECTANGLE) { - d1 = FindDistance( points(polyInx), pos ); - d2 = FindDistance( points(polyInx==0?segPtr[segInx].u.p.cnt-1:polyInx-1), pos ); + if (!corner_mode) { + d1 = FindDistance( points(inx_line).pt, pos ); + d2 = FindDistance( points(inx_line==0?3:inx_line-1).pt, pos ); if (d2<d1) { - inx_line = polyInx; - polyInx = polyInx==0?segPtr[segInx].u.p.cnt-1:polyInx-1; + polyInx = inx_line==0?3:inx_line-1; } else { - inx_line = polyInx==0?segPtr[segInx].u.p.cnt-1:polyInx-1; + polyInx = inx_line; } - //polyInx is closest point - inx1 = (polyInx==0?3:polyInx-1); //Prev point - inx2 = (polyInx==3?0:polyInx+1); //Next Point - inx_origin = (inx2==3?0:inx2+1); //Opposite point - if ( IsClose(d2) || IsClose(d1) ) { - corner_mode = TRUE; - pos = points(polyInx); - start_pos = pos; - DrawArrowHeads( &tempSegs(1), pos, FindAngle(points(polyInx),points(inx_origin)), TRUE, wDrawColorRed ); - tempSegs_da.cnt = 6; - InfoMessage( _("Drag to Move Corner Point")); - } else { - corner_mode = FALSE; - start_pos = pos; - pos.x = (points(polyInx).x + points(inx_line).x)/2; - pos.y = (points(polyInx).y + points(inx_line).y)/2; - DrawArrowHeads( &tempSegs(1), pos, FindAngle(points(polyInx),pos)+90, TRUE, wDrawColorRed ); - tempSegs_da.cnt = 6; - InfoMessage( _("Drag to Move Edge ")); - } - return C_CONTINUE; + } + inx1 = (polyInx==0?3:polyInx-1); //Prev point + inx2 = (polyInx==3?0:polyInx+1); //Next Point + inx_origin = (inx2==3?0:inx2+1); //Opposite point + if ( corner_mode ) { + start_pos = pos; + pos = points(inx).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")); } else { - inx = (polyInx==0?segPtr[segInx].u.p.cnt-1:polyInx-1); - d = FindDistance( points(inx), pos ); - dd = FindDistance( points(inx), points(polyInx) ); - if ( d < 0.25*dd ) { - polyInx = inx; - } else if ( d > 0.75*dd ) { - ; - } else { - tempSegs(0).u.p.cnt++; - for (inx=points_da.cnt-1; inx>polyInx; inx-- ) { - points(inx) = points(inx-1); - } -/*fprintf( stderr, "Inserting vertix before %d\n", polyInx );*/ - } - points(polyInx) = pos; + start_pos = pos; + 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(polyInx).pt,pos)+90, TRUE, wDrawColorRed ); + InfoMessage( _("Drag to Move Edge ")); } - p1=p0; - break; + context->state = MOD_SELECTED_PT; + return C_CONTINUE; case SEG_TEXT: segInx = -1; return C_ERROR; @@ -690,7 +2057,7 @@ STATUS_T DrawGeomModify( segEp = 0; else { segEp = 1; - switch ( segPtr[segInx].type ) { + switch ( context->type ) { case SEG_TBLEDGE: case SEG_STRLIN: case SEG_DIMLIN: @@ -701,176 +2068,454 @@ STATUS_T DrawGeomModify( ; } } + UndrawNewTrack( context->trk ); return C_CONTINUE; case C_MOVE: - if (segInx == -1) - return C_ERROR; - if ( ( MyGetKeyState() & WKEY_SHIFT ) && - (tempSegs(0).type == SEG_STRLIN || tempSegs(0).type == SEG_DIMLIN || tempSegs(0).type == SEG_BENCH || tempSegs(0).type == SEG_TBLEDGE) ) { - d = FindDistance( pos, tempSegs(0).u.l.pos[1-segEp] ); - Translate( &pos, tempSegs(0).u.l.pos[1-segEp], segA1, d ); - } else if ( (MyGetKeyState() & (WKEY_SHIFT|WKEY_CTRL|WKEY_ALT)) == WKEY_CTRL ) { - OnTrack( &pos, FALSE, FALSE ); + 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: - tempSegs(0).u.l.pos[segEp] = pos; - InfoMessage( _("Length = %0.3f Angle = %0.3f"), FindDistance( tempSegs(0).u.l.pos[segEp], tempSegs(0).u.l.pos[1-segEp] ), FindAngle( tempSegs(0).u.l.pos[1-segEp], tempSegs(0).u.l.pos[segEp] ) ); + 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( tempSegs(0).u.c.center, pos ); + 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 { - a = FindAngle( tempSegs(0).u.c.center, pos ); - if (segEp==0) { - tempSegs(0).u.c.a1 = NormalizeAngle(segA1-a); - tempSegs(0).u.c.a0 = a; + 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 { - tempSegs(0).u.c.a1 = NormalizeAngle(a-tempSegs(0).u.c.a0); + 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: - switch (tempSegs(0).u.p.polyType) { - case RECTANGLE: - if (!corner_mode) { - /* Constrain movement to be perpendicular */ - d = FindDistance(start_pos, pos); - line_angle = NormalizeAngle(FindAngle(points(inx_line),points(polyInx))-90); - 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), points(polyInx), a, d); - d = FindDistance(points(orig_pnt),points(polyInx)); - a = FindAngle(points(orig_pnt),points(polyInx)); - prior_angle = FindAngle(points(orig_pnt),points(prior_pnt)); - Translate( &points(prior_pnt), points(orig_pnt), prior_angle, d*cos(D2R(prior_angle-a))); - next_angle = FindAngle(points(orig_pnt),points(next_pnt)); - Translate( &points(next_pnt), points(orig_pnt), next_angle, d*cos(D2R(next_angle-a))); - if (!corner_mode) { - pos.x = (points(polyInx).x + points(inx_line).x)/2; - pos.y = (points(polyInx).y + points(inx_line).y)/2; - DrawArrowHeads( &tempSegs(1), pos, FindAngle(points(polyInx),points(inx_line))+90, TRUE, wDrawColorRed ); - tempSegs_da.cnt = 6; - InfoMessage( _("Drag to Move Edge")); - } else { - pos = points(polyInx); - DrawArrowHeads( &tempSegs(1), pos, FindAngle(points(polyInx),points(inx_origin)), TRUE, wDrawColorRed ); - tempSegs_da.cnt = 6; - InfoMessage( _("Drag to Move Corner Point")); - } - break; - default: - points(polyInx) = pos; + 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: - pos = tempSegs(0).u.l.pos[segEp]; - pos.x -= orig.x; - pos.y -= orig.y; - Rotate( &pos, zero, -angle ); - segPtr[segInx].u.l.pos[segEp] = pos; + 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).u.c.a1 >= 360.0 ) { - segPtr[segInx].u.c.radius = fabs(tempSegs(0).u.c.radius); + 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 { - a = FindAngle( tempSegs(0).u.c.center, pos ); - a = NormalizeAngle( a-angle ); - segPtr[segInx].u.c.a1 = tempSegs(0).u.c.a1; - if (segEp == 0) { - segPtr[segInx].u.c.a0 = a; - } + 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: - switch(tempSegs(0).u.p.polyType) { - case RECTANGLE: - for (int i=0;i<4;i++) { - pos = points(i); - pos.x -= orig.x; - pos.y -= orig.y; - Rotate( &pos, zero, -angle ); - segPtr[segInx].u.p.pts[i] = pos; - } - break; - default: - mergePoints = FALSE; - if ( IsClose( FindDistance( pos, points( polyInx==0?tempSegs(0).u.p.cnt-1:polyInx-1 ) ) ) || - IsClose( FindDistance( pos, points( (polyInx==tempSegs(0).u.p.cnt-1)?0:polyInx+1 ) ) ) ) { - mergePoints = TRUE; - if (segPtr[segInx].u.p.cnt <= 3) { - ErrorMessage( MSG_POLY_SHAPES_3_SIDES ); + 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); - coOrd * oldPts = segPtr[segInx].u.p.pts; - newPts = (coOrd*)MyMalloc( tempSegs(0).u.p.cnt * sizeof (coOrd) ); - int size = segPtr[segInx].u.p.cnt; - memcpy( newPts, segPtr[segInx].u.p.pts, (size) * sizeof (coOrd) ); - segPtr[segInx].u.p.pts = newPts; - MyFree(oldPts); + if (polyMode) return DrawGeomPolyModify(action,pos,context); + if (action>>8 == 'o') { + MenuMode(1); + } - if ( tempSegs(0).u.p.cnt > segPtr[segInx].u.p.cnt ) { - ASSERT( tempSegs(0).u.p.cnt == segPtr[segInx].u.p.cnt+1 ); - for (inx=tempSegs(0).u.p.cnt-1; inx>polyInx; inx--) - segPtr[segInx].u.p.pts[inx] = segPtr[segInx].u.p.pts[inx-1]; - segPtr[segInx].u.p.cnt++; + 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; } - - pos = points(polyInx); - if ( mergePoints ) { - for (inx=polyInx+1; inx<segPtr[segInx].u.p.cnt; inx++) - segPtr[segInx].u.p.pts[inx-1] = segPtr[segInx].u.p.pts[inx]; - segPtr[segInx].u.p.cnt--; -/*fprintf( stderr, "Merging with vertix %d\n", polyInx );*/ - break; + 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; } - pos.x -= orig.x; - pos.y -= orig.y; - Rotate( &pos, zero, -angle ); - segPtr[segInx].u.p.pts[polyInx] = pos; - } - break; - default: - ; + 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_ERROR; + return C_CONTINUE; } |