/* The routines in this file are copyright (c) 1987 by Helene (Lee) Taran. * Permission is granted for use and free distribution as long as the * original author's name is included with the code. */ #include "spline.h" extern DLIST_ELEMENT Control_Points; extern struct PopUp_Menu PointMenu, CurveMenu; extern struct Image control_image; int DrawAFrame = TRUE; int CurveType = OPENB_NATURAL; /* InRange : returns TRUE iff the mouse position is in the selection * range of the given control point position */ int InRange(mouse, control) REAL_POINT *mouse, *control; { return ((mouse->x >= control->x - CONTROL_RADIUS) && (mouse->x <= control->x + CONTROL_RADIUS) && (mouse->y >= control->y - CONTROL_RADIUS) && (mouse->y <= control->y + CONTROL_RADIUS)); } /* Select_ControlPoint : returns the member of Control_Points that is * is selected at . Returns FALSE if no point is selected. */ DLISTPTR Select_ControlPoint(x,y) SHORT x,y; { REAL_POINT tmp; int InRange(); DLISTPTR Find_Element(); tmp.x = (float) x; tmp.y = (float) y; return(Find_Element(&tmp,&Control_Points,InRange)); } /* Print Instruction: prints a string in the upper left hand corner * of the window. Assumes that the current pen color is the the * color you want the string to appear in. */ PrintInstruction(w,instr) struct Window *w; char *instr; { Move(w->RPort,w->LeftEdge + w->BorderLeft + 1, w->TopEdge + w->BorderTop + 1); Text(w->RPort,instr,strlen(instr)); } /* GetPoint : Waits for the user to select a point in window and returns its * x,y coordinates in terms of a REAL_POINT structure. */ DLISTPTR GetPoint(w) struct Window *w; { REAL_POINT *tmp; void *calloc(); DLISTPTR p; struct IntuiMessage mcopy, *msg, *GetMsg(); struct RastPort *rp = w->RPort; BYTE old_mode = rp->DrawMode; if (!((tmp = (REAL_POINT *)calloc(1,sizeof(REAL_POINT))) && (p = (DLISTPTR)calloc(1,sizeof(DLIST_ELEMENT))))) { fprintf(stderr,"splines : trouble in paradise : can't allocate point\n"); panic(0); } SetDrMd(rp,COMPLEMENT); PrintInstruction(w,"Select A Point"); while (1) { Wait(1 << w->UserPort->mp_SigBit); while (msg = GetMsg(w->UserPort)) { mcopy = *msg; ReplyMsg(msg); if ((msg->Class == MOUSEBUTTONS) && (msg->Code == SELECTDOWN) && Inside_Window(msg->MouseX,msg->MouseY,w)) { tmp->x = (float)msg->MouseX; tmp->y = (float)msg->MouseY; PrintInstruction(w,"Select A Point"); SetDrMd(rp,old_mode); PlopDot(w,tmp); p->contents = tmp; return(p); } } } } /* PrintError: prints a error string to the window's upper left hand * corner for approx. 1.6 seconds. The string is drawn in the complement * of the background so that it doesn't destroy what's already drawn in the * window. After the delay, the string is complemented out again so it * disappears. */ PrintError(w,str) struct Window *w; char *str; { struct RastPort *rp = w->RPort; BYTE old_mode = rp->DrawMode; SetDrMd(rp,COMPLEMENT); PrintInstruction(w,str); Delay(80l); PrintInstruction(w,str); SetDrMd(rp,old_mode); } DrawConstructionLine(w,p0,p1) /* draws a dotted line from p0 to p1 */ struct Window *w; REAL_POINT *p0,*p1; { struct RastPort *rp = w->RPort; BYTE old_pen = rp->FgPen; /* save the old pen color */ USHORT old_pat = rp->LinePtrn; /* save the old line pattern */ SetAPen(rp,AFRAME_COLOR); SetDrPt(rp,0xcccc); /* use a dotted line */ Move(rp,(SHORT)p0->x,(SHORT)p0->y); Draw(rp,(SHORT)p1->x,(SHORT)p1->y); SetDrPt(rp,old_pat); SetAPen(rp,old_pen); } /* Edit_Curve : pops up the curve style editing menu in and allows * the user to alter the current curve style */ Edit_CurveStyle(w) struct Window *w; { int option = PopUp(&CurveMenu,w); switch (option) { case TOGGLEAFRAME : DrawAFrame = !DrawAFrame; Redraw(w); break; case REDRAW : Redraw(w); break; case OPENB_TRIPLE: if (LENGTH(&Control_Points) < 4) { PrintError(w,"?Error: Triple Knot option require minimum of 4 points"); return; } /* othewise fall through to action for the next case */ case OPENB_NATURAL : case CLOSEDB : case CLOSED_INTRPL : case OPEN_INTRPL : if (option != CurveType) { CurveType = option; Redraw(w);} break; case QUIT : close_things(); exit(0); break; } } /* Edit_ControlPoint : pops up the control point editing menu in and * allows the user to alter the given control point

. Assumes * that

is the control point that the user just selected. */ Edit_ControlPoint(w,p) struct Window *w; DLISTPTR p; { int option = PopUp(&PointMenu,w); switch (option) { case ADD_AFTER : if (LENGTH(&Control_Points) == MAXG) { PrintError(w,"No! Don't you think you've added enough points?"); return; } else Insert_After(p,GetPoint(w),&Control_Points); break; case ADD_BEFORE : if (LENGTH(&Control_Points) == MAXG) { PrintError(w,"No! Don't you think you've added enough points?"); return; } else Insert_Before(p,GetPoint(w),&Control_Points); break; case MOVE_POINT : { DLISTPTR tmp; EraseDot(w,p->contents); free(p->contents); tmp = GetPoint(w); p->contents = tmp->contents; free(tmp); break; } case REMOVE_POINT : { int len = LENGTH(&Control_Points); if ((len == 4) && (CurveType == OPENB_TRIPLE)) { PrintError(w,"?Error: Triple Knot option require minimum of 4 points"); return; } else if (len == 3) PrintError(w,"?Error: you must have a minimum of 3 control points"); else { Remove_Element(p,&Control_Points); free(p->contents); free(p); } } break; default : return; } Redraw(w); } EraseDot(w,dot) struct Window *w; REAL_POINT *dot; { control_image.PlanePick = 0; PlopDot(w,dot); control_image.PlanePick = 1; } PlopDot(w,point) struct Window *w; REAL_POINT *point; { DrawImage(w->RPort,&control_image,(SHORT)point->x,(SHORT)point->y); } Draw_ControlPoints(w) struct Window *w; { DLISTPTR tmp = &Control_Points; while ((tmp = tmp->next) != &Control_Points) PlopDot(w,POINT(tmp)); } Redraw(w) struct Window *w; { struct RastPort *rp = w->RPort; SetRast(rp,ERASE); SetAPen(rp, CURVECOLOR); Draw_ControlPoints(w); switch (CurveType) { case CLOSEDB : Draw_Closed_Bspline(w,&Control_Points); break; case CLOSED_INTRPL : Draw_Closed_Ispline(w,&Control_Points); break; case OPEN_INTRPL : Draw_Open_Ispline(w,&Control_Points); break; case OPENB_TRIPLE : Draw_TripleKnot_Bspline(w,&Control_Points); break; default: Draw_Natural_Bspline(w,&Control_Points); break; } }