|
Volume Number: | 1 | |
Issue Number: | 9 | |
Column Tag: | C WORKSHOP |
How to Draw Arrowheaded Lines
How to Draw Arrowheaded Lines
While writing a new application, I discovered I needed to have lines with arrowheads (like the ones we all love in MacDraw). Not only that, I needed to have the line stop on the surface of an object (usually an oval or rectangle).
The first place to look, of course, is to see how MacDraw did it. After using MacDraw for some time in various applications, I was surprised to see that the arrowheads were not 3-pointed polygons but actually small wedges! This was discovered after placing an arrowhead on a thick line and noticing the curvature of the arrowhead.
Keeping with the Macintosh spirit, I decided to make the call similar to the ones used in QuickDraw (i.e. - Line and LineTo). Instead of using a LineTo call, this routine may be substituted and all of the LineTo's changed to ArrowLineTo's.
The parameter passed to it is the absolute horizontal and vertical coordinates of the end point of the line (as in LineTo). The end point is also where the arrowhead will be drawn.
The basic algorithm is simple -
1). Compute the slope of the line
2). Draw the line
3). Point the wedge in the opposite direction of the line (to create the effect of an arrowhead).
4). Draw the wedge
There is a fantastic Mac routine called PtToAngle that will compute the angle for you! All you need to do is to place a rectangle around the starting point, make the call, and the angle is returned to you (in degrees)!
The following code (written in Mac C) is pretty much self explanatory. You could experiment with the constants arrowWidth and arrowLength (as shown in Fig. 1) to vary the width and length of the arrowhead. Note - this routine could be changed so that these constants are passed as parameters, for applications that need varying sizes of arrowheads.
/************************************************************************ ArrowLineTo.c Copyright 1985, FlottWare ************************************************************************/ #include "MacCDefs.h"// Mac ROM data structure definitions #include "Events.h" #include "Window.h" extern struct P_Str *CtoPstr(); int strlen(str) char *str; {int i=0; while (str[i++]); return i-1;} /*------------------------------------------------------------------------ Global Data ------------------------------------------------------------------------*/ #define False 0 #define True 0xFF Rect windowRect = {40,4,336,508}; // Window Rectangle WindowPtr windowPtr; // Window Pointer EventRecord event; // Current event record /*------------------------------------------------------------------------ main() ------------------------------------------------------------------------*/ main() { if (CatchSignal()) // Is the user quitting this application? ExitToShell(); // Go to Finder when done init(); // Init Mac while (True) // Poll events forever { SystemTask();// Perform System duties if (GetNextEvent(everyEvent, &event)) // Get the next event { switch ( event.what ) // Which event is it? { case autoKey: case keyDown: // Key was pressed case mouseDown: // Mouse Button pressed { Signal("All Done"); // Y - quit application break; } // case autoKey,keyDown,mouseDown: } // switch (event.what) } // if (Getevent) } // while (true) } // main /************************************************************************ Windows ***********************************************************************/ /*---------------------------------------------------------------------- init() - ----------------------------------------------------------------------*/ init() { // Open a window windowPtr = NewWindow(0,&windowRect,CtoPstr("Hit Key or Mouse to Quit "),True, documentProc,-1,True,0); SetPort(windowPtr); #define centerH 250 #define centerV 150 #define offset 50 // Draw some lines with arrowheads MoveTo(centerH,centerV); ArrowLineTo(centerH-offset,centerV); MoveTo(centerH,centerV); ArrowLineTo(centerH-offset,centerV+offset); MoveTo(centerH,centerV); ArrowLineTo(centerH,centerV+offset); MoveTo(centerH,centerV); ArrowLineTo(centerH+offset,centerV+offset); MoveTo(centerH,centerV); ArrowLineTo(centerH+offset,centerV); MoveTo(centerH,centerV); ArrowLineTo(centerH+offset,centerV-offset); MoveTo(centerH,centerV); ArrowLineTo(centerH,centerV-offset); MoveTo(centerH,centerV); ArrowLineTo(centerH-offset,centerV-offset); } // end init() /*---------------------------------------------------------------------- ArrowLineTo(horiz,vert) This routine draws a line from the current pen location to point (h,v) with an arrowhead (wedge) on the end of it. Inputs : horiz - horizontal coord of end point vert - vertical coord of end point Written by: Rick Flott Mac C (Consulair) V 1.0 ----------------------------------------------------------------------*/ ArrowLineTo(horiz,vert) short horiz; short vert; { // Size of starting Rect used in PtToAngle #define rectOffset 30 // Arrowhead (wedge) constants // arrowWidth - width of 1/2 arrowhead (in degrees) // arrowLength - length of arrowhead in pixels #define arrowWidth 25 #define arrowLength 10 // Rects used in angle calculations Rect startRect; // starting Rect used in PtToAngle Rect arrowheadRect; // the Rect that the wedge is drawn in short arrowAngle;// Angle of arrowhead (in degrees) Point startPt,endPt; // Start,End points of line GetPen(&startPt);// Get the current pen location // Set up a rectangle around the starting point // (this is needed for the PtToAngle routine) SetRect (&startRect,startPt.h - rectOffset, startPt.v - rectOffset, startPt.h + rectOffset, startPt.v + rectOffset); SetPt(&endPt,horiz,vert); // Set up the end point // Calculate the angle (in degrees) of the line segment PtToAngle(&startRect,&endPt,&arrowAngle); LineTo(horiz,vert);// Draw the line arrowAngle -= (180 + arrowWidth);// Create a arrowhead with a wedge facing the opposite direction // Set up a Rect for the wedge around the endpoint SetRect (&arrowheadRect,endPt.h - arrowLength, endPt.v - arrowLength, endPt.h + arrowLength, endPt.v + arrowLength); // Draw arrow head (a reversed wedge) PaintArc(&arrowheadRect,arrowAngle,2*arrowWidth); } // end ArrowLineTo()
- SPREAD THE WORD:
- Slashdot
- Digg
- Del.icio.us
- Newsvine