Code archives/Graphics/Fat Functions
This code has been declared by its author to be Public Domain code.
Download source code
| |||||
Add thickness to Lines, Rects, Ovals, Stars, & Circles with these little functions. Rects and Ovals can be rotated through 360 degrees in near realtime (depending on size and thickness). Optimized for speed, and displays without annoying artifacts (holes in thick lines). Functions are commented and includes usage examples. Update: fatSuperEllipse function added. Very useful. | |||||
;This simple 2D demo shows examples of using lines of varying thickness to create graphic primitives. ;There are other methods to achieve the same results but other methods are usually plagued by 'banding' ; (artifacts caused by not filling in the thick line completely). These functions are free of 'banding' artifacts. ;The functions are: ; fatLine ; fatBox ; fatOval ; fatStar ; fatCircle ; fatSuperEllipse ; ;The fatBox and fatOval functions also allow full rotation through 360 degrees. ;Have commented the functions fairly well and each function has a description of the required parameters. ; ;I've tried to optimize all of the functions for speed, but some can be ;tweaked for better results by removing parameter checking and using LUT's. ; ;All of the functions except fatCircle are dependent on fatLine for line thickness, so if you want ;to use any of the other functions,don't forget to copy the fatLine function to ;your application as well. If you don't need the line thickness in the other functions, ;just replace all references to fatLine with Blitz's Line() function. ; ;fatLine written in Blitz+ by Andy Amaya 2003.06.23 ;fatFunctions compiled 2003.10.02 ;Update - fatSuperEllipse() function added 2003.10.06 ; ;Feel free to use these routines as you see fit. Enjoy 8) ; ------> Press any key to cycle through the different examples Const sw% = 800 Const sh% = 600 Const cx% = sw%/2 Const cy% = sh%/2 Graphics sw, sh, 16 SetBuffer BackBuffer() SeedRnd MilliSecs() fntArial=LoadFont("Arial",24,True,False,False) SetFont fntArial Cls Gosub DrawFatLines Gosub TrapKey Gosub DrawFatBoxes Gosub TrapKey Gosub DrawFatCircles Gosub TrapKey Gosub DrawFatStars Gosub DrawGlobe Gosub TrapKey Gosub DrawSuperEllipses Gosub TrapKey Gosub Swirly End .TrapKey WaitKey Return .DrawFatLines Cls For i% = 1 To 360 Step 5 j% = Cos(i%) * cx% + cx% k% = Sin(i%) * cy% + cy% Color Rand(64,255),Rand(64,255),Rand(64,255) ;fatLine(x1%, y1%, x2%, y2%, penSize%) <-- shows syntax of function call fatLine( cx%, cy%, j%, k%, Rand(1,25)) Next Color 255,255,255 Text 0,0,"Randomly thick lines" Flip Return .DrawFatBoxes Cls For i% = 0 To 14 Color Rand(64,255),Rand(64,255),Rand(64,255) tcX% = Cos(i%*24) * 30 + cx% tcY% = Sin(i%*24) * 30 + cy% ;fatBox( x%, y%, wide%, high%, penSize%, rotAngle%) <-- shows syntax of function call fatBox(tcX%, tcY%, 160, 60, 3, i%*24) fatBox(tcX%, tcY%, 170, 50, 3, i%*24) fatBox(tcX%, tcY%, 180, 40, 3, i%*24) fatBox(tcX%, tcY%, 190, 30, 3, i%*24) fatBox(tcX%, tcY%, 200, 20, 3, i%*24) fatBox(tcX%, tcY%, 210, 10, 3, i%*24) Next Color 255,255,255 Text 0,0,"Rotated rectangles" Flip Return .DrawFatCircles Cls r% = 255: g% = 0 : b% = 0 y% = 5 pen% = 1 rad% = 5 While y% <= 620 Color r%, g%, b% x% = 0 While x% <= 850 ;fatCircle(centerX%, centerY%, rad%, penSize%) <-- shows syntax of function call fatCircle( x%, y%, rad%, pen%) x% = x% + rad% * 2 + pen% Wend pen% = pen% + 1 rad% = rad% + 2 y% = y% + rad% * 2 + pen r% = r% - 18 g% = g% + 18 Wend Color 255,255,255 Text 0,0,"Circles of varying thickness" Flip Return .DrawFatStars pen% = 1 While GetKey() = 0 For j = 30 To 70 Step 2 Cls For i% = 1 To 5 outy% = i * j inny% = outy%/2.6 If i% And 1 Then Color 255,96,0 Else Color 255,255,0 ;fatStar(centerX%, centerY%, majorRadius%, minorRadius%, points%, penSize%, mode%) <-- shows syntax of function call fatStar( cx%, cy%, outy%, inny%, 12, pen%, 0) Next Color 255,255,255 Text 0,0,"Variable sized stars" Flip Next For j = 70 To 30 Step -2 Cls For i% = 1 To 5 outy% = i * j inny% = outy%/2.6 If i% And 1 Then Color 255,96,0 Else Color 255,255,0 ;fatStar(centerX%, centerY%, majorRadius%, minorRadius%, points%, penSize%, mode%) <-- shows syntax of function call fatStar( cx%, cy%, outy%, inny%, 12, pen%, 0) Next Color 255,255,255 Text 0,0,"Variable sized stars" Flip Next For j = 30 To 70 Cls For i% = 1 To 5 outy% = i * j inny% = outy%/2.6 If i% And 1 Then Color 255,96,0 Else Color 255,255,0 ;fatStar(centerX%, centerY%, majorRadius%, minorRadius%, points%, penSize%, mode%) <-- shows syntax of function call fatStar( cx%, cy%, outy%, inny%, 5, pen%, 0) Next Color 255,255,255 Text 0,0,"Variable sized stars" Flip Next For j = 70 To 30 Step -1 Cls For i% = 1 To 5 outy% = i * j inny% = outy%/2.6 If i% And 1 Then Color 255,96,0 Else Color 255,255,0 ;fatStar(centerX%, centerY%, majorRadius%, minorRadius%, points%, penSize%, mode%) <-- shows syntax of function call fatStar( cx%, cy%, outy%, inny%, 5, pen%, 0) Next Color 255,255,255 Text 0,0,"Variable sized stars" Flip Next Wend Return .DrawGlobe pen% = 2 globe = 225 globeStep = globe/15 counter = 0 toggle = 0 Cls Flip Cls For rotate = 0 To 360 Step 15 t = 0 While t <= globe penColor% = (penColor% + 1) Mod 3 Select penColor Case 0: Color 0, 0, 255 Case 1: Color 0, 255, 0 Case 2: Color 255, 0, 0 End Select u = globe-t ;fatOval(centerX%, centerY%, wide%, high%, penSize%, rotAngle%,interval%) <-- shows syntax of function call fatOval( cx, cy, u, globe, pen%, rotate, 40) counter = counter + 2 t = t + globeStep Wend Flip Next Color 255,255,255 Text 0,0,"Sphere made from rotated ovals" Flip Return .Swirly pen% = 2 toggle = 0 ClsColor 4,4,80 Cls Repeat ;jiggle% = Rand(0,5) ;Jiggles center of whirlpool while spinning For j% = 360 To 15 Step -15 Cls iwx% = Rand(cx% - jiggle%, cx% + jiggle%) iwy% = Rand(cy% - jiggle%, cy% + jiggle%) For i% = 15 To 270 Step 15 toggle% = 1 - toggle% If toggle Color 0,0,255 Else Color 16,16,192 ;fatOval(centerX%, centerY%, wide%, high%, penSize%, rotAngle%,interval%) <-- shows syntax of function call fatOval( iwx%, iwy%, i% Shl 1, i%, pen%, i%+j%, 24) If GetKey() <> 0 Then flag% = 1: Exit Next Color 255 , 255 , 255 Text 0,0,"Whirlpool (rotating ovals)" Flip If flag% Then Exit Next If flag% Then Exit Forever Return .DrawSuperEllipses ClsColor 160,192,255 Cls Color 96,96,96 For i% = 16 To 799 Step 16 Line(i%, 48, i%, 576) Next For i% = 48 To 576 Step 16 Line(0, i%, 799, i%) Next r% = 0: g% = 0: b% = 255 fpen# = 2 k% = 0 For j% = 32 To 795 Step 60 Color r%, g%, b% ; (show fatSuperEllipse() function syntax) ; fatSuperEllipse(centerX%, centerY%, wide%, high%, exponent#, levelOfDetail#, penSize%, rotAngle%) fatSuperEllipse j%, 77, 24, 18, .4, 20.0, fpen#, k% fatSuperEllipse j%, 134, 24, 18, .75, 20.0, fpen#, k% fatSuperEllipse j%, 191, 24, 18, 1, 90.0, fpen#, k% fatSuperEllipse j%, 248, 24, 24, 2, 72, fpen#, k% fatSuperEllipse j%, 305, 24, 24, 2, 51.428571, fpen#, k% fatSuperEllipse j%, 362, 24, 18, 2, 20.0, fpen#, k% fatSuperEllipse j%, 420, 24, 18, 3, 20.0, fpen#, k% fatSuperEllipse j%, 477, 24, 18, 5, 20.0, fpen#, k% fatSuperEllipse j%, 534, 24, 18, 10, 15.0, fpen#, k% k% = k% + 30 r% = r% + 21.25 b% = b% - 21.25 fpen# = fpen# + .3 Next Color 0,0,128 For i% = 0 To 12 angle$ = Str$(i% * 30) + "°" wid% = StringWidth(angle$) Text (i * 61 - wid% + 42), 576,angle$ Next msg$ = "All of these shapes created using just one function: fatSuperEllipse!" wid% = StringWidth(msg$) Text (800-wid%)/2,10,msg$ Flip Return ;********************************** fatLine ****************************************** ;** Parameters are: ** ;** x1%, y1%, x2%, y2%, penSize% ** ;** ** ;** x1%, y1% are the coords of the line origin ** ;** x2%, y2% are the coords of the line end point ** ;** penSize% is the thickness of line to be drawn ** ;** ** ;** BRESLINE.PAS - A general line drawing procedure. ** ;** By Mark Feldman ** ;** ** ;** Source: http://www.gamedev.net/reference/articles/article767.asp ** ;** ** ;** Adapted for Blitz+ fatLine function by Andy Amaya ** ;** ** ;***************************************************************************************** Function fatLine(x1%, y1%, x2%, y2%, penSize%) If penSize% < 1 Then Return False If penSize% = 1 Then Line(x1%, y1%, x2%, y2%): Return ; penSize% is thickness to draw line offset% = penSize% / 2 ;offset needed to place Oval correctly ; Calculate deltax and deltay for initialization deltax% = Abs(x2% - x1%) deltay% = Abs(y2% - y1%) ; Initialize all vars based on which is the independent variable If deltax% >= deltay% Then ; x is the independent variable numovals% = deltax% + 1 d% = (2 * deltay%) - deltax% dinc1% = deltay% Shl 1 dinc2% = (deltay% - deltax%) Shl 1 xinc1% = 1 xinc2% = 1 yinc1% = 0 yinc2% = 1 Else ; y is the independent variable numovals% = deltay% + 1 d% = (2 * deltax%) - deltay% dinc1% = deltax% Shl 1 dinc2% = (deltax% - deltay%) Shl 1 xinc1% = 0 xinc2% = 1 yinc1% = 1 yinc2% = 1 End If ; Make sure x and y move in the right directions If x1% > x2% Then xinc1% = - xinc1% xinc2% = - xinc2% End If If y1% > y2% Then yinc1% = - yinc1% yinc2% = - yinc2% End If ; Start drawing at x%, y% x% = x1% - offset% y% = y1% - offset% ; Draw the filled ovals For i% = 1 To numovals% Oval x%, y%, penSize%, penSize%, 1 If d% < 0 Then d% = d% + dinc1% x% = x% + xinc1% y% = y% + yinc1% Else d% = d% + dinc2% x% = x% + xinc2% y% = y% + yinc2% End If Next End Function ;********************************** fatBox ****************************************** ;** Parameters are: ** ;** x%, y%, wide%, high%, penSize%, rotAngle% ** ;** ** ;** x%, y% are the coords of the upper left corner of the box to be plotted ** ;** this function rotates box around the upper left corner (not center of box) ** ;** wide% is the width of the box ** ;** high% is the height of the box ** ;** penSize% is the thickness of lines used to plot box ** ;** rotAngle% is the rotation angle of the box to be plotted (0 to 360 typically) ** ;** ** ;***************************************************************************************** Function fatBox(x%, y%, wide%, high%, penSize%, rotAngle%) If rotAngle > 360 Then rotAngle = rotAngle Mod 360 ;No rotation involved, so just draw a box If rotAngle% = 0 Or rotAngle% = 360 Then fatLine(x% , y% , x% + wide%, y% , penSize%) fatLine(x% + wide%, y% , x% + wide%, y% + high%, penSize%) fatLine(x% , y% + high%, x% + wide%, y% + high%, penSize%) fatLine(x% , y% , x%, y% + high%, penSize%) Else ;Make rotation calculations and draw rotated box vtx% = rotAngle% + 90 cs% = Cos(vtx%) * high% sn% = Sin(vtx%) * high% x1% = Cos(rotAngle%)* wide% + x% y1% = Sin(rotAngle%)* wide% + y% fatLine(x%, y%, x1%, y1%, penSize%) x2% = cs% + x1% y2% = sn% + y1% fatLine(x1%, y1%, x2%, y2%, penSize%) x3% = cs% + x% y3% = sn% + y% fatLine(x%, y%, x3%, y3%, penSize%) fatLine(x2%, y2%, x3%, y3%, penSize%) End If End Function ;********************************** fatOval ****************************************** ;** Parameters are: ** ;** centerX%, centerY%, wide%, high%, penSize%, rotAngle%, sides% ** ;** ** ;** centerX%, centerY% coords locate center of oval to be plotted ** ;** wide% is the x-radius of the oval ** ;** high% is the y-radius of the oval ** ;** penSize% is the thickness of lines used to plot oval ** ;** rotAngle% is the rotation angle of the oval to plot (0 to 359) ** ;** sides% is the number of connected points on plotted oval ** ;** ** ;***************************************************************************************** Function fatOval(centerX%, centerY%, wide%, high%, penSize%, rotAngle%, sides%) ;360 sides generates the smoothest oval, 3 sides generates a triangle ;interval# is the number of degrees between plotted points interval# = Float(360 / sides%) If interval# <= 0.0 Or interval# > 180.0 Then Return False ;Keep rotAngle between 0 and 359 rotAngle% = rotAngle% Mod 360 If penSize% < 1 Then Return False ;If rotation angle is 0 don't do extra calculations If rotAngle% = 0 Then x1% = wide% + centerX% y1% = centerY% ;This While..Wend is same as For i# = interval# To 360.0 Step interval#) i# = interval# While i# <= 360.0 x2% = Cos(i#) * wide% + centerX% y2% = Sin(i#) * high% + centerY% fatLine(x1%, y1%, x2%, y2%, penSize%) x1% = x2% y1% = y2% i# = i# + interval# ;(increment loop index, else you end up with a Repeat..Forever loop) Wend Else ;Make rotation calculations and draw oval cs# = Cos(rotAngle%) sn# = Sin(rotAngle%) x1% = cs# * wide% + centerX% y1% = sn# * wide% + centerY% ;This While..Wend is same as For i# = interval# To 360.0 Step interval#) i# = interval# While i# <= 360.0 rotX# = Cos(i#) * wide% rotY# = Sin(i#) * high% x2% = cs# * rotX# - sn# * rotY# + centerX% y2% = sn# * rotX# + cs# * rotY# + centerY% fatLine(x1%, y1%, x2%, y2%, penSize%) x1% = x2% y1% = y2% i# = i# + interval# ;(increment loop index, else you end up with a Repeat..Forever loop) Wend End If End Function ;********************************** fatStar ****************************************** ;** Parameters are: ** ;** centerX%, centerY%, majorRadius%, minorRadius%, points%, penSize%, mode% ** ;** ** ;** centerX%, centerY% coords locate center of star to be plotted ** ;** majorRadius% is the size of 'convex' star points ** ;** minorRadius% is the size of 'concave' star points ** ;** points% is the number of ;convex; star points: 3 - 180 are valid number of points ** ;** penSize% sets the thickness for lines that draw the star ** ;** ** ;***************************************************************************************** Function fatStar(centerX%, centerY%, majorRadius%, minorRadius%, points%, penSize%, mode%) ;tell function to draw a star with 3 to 180 'convex' points, otherwise can't do - Return False If points% < 3 Or points% > 180 Then Return False ;inc is number of star points times 2 ;For example: a five point star has 5 ;convex; points + 5 ;concave; points inc# = 360.0/(points * 2) ;initialize variables ;toggle keeps track of 'concave' And 'convex' radii toggle% = 0 ;calculate First x,y coords to start due north of center point oldX% = centerX ;same as Cos(270)*majorRadius + centerX oldY% = -majorRadius + centerY ;same as Sin(270)*majorRadius + centerY ;remember First x,y coords To close polyStar firstX% = oldX%: firstY% = oldY% ;loop that draws the star ;next 3 lines are equivalent to: For i# = inc# To 360 - (inc#-1) Step inc i# = 0 While i# <= 360 - (inc#-1) i# = i# + inc# ;start first star point due north of center point angle% = i# + 270 ;scale back degrees to between 0 And 360 angle = angle Mod 360 ;make toggle either 0 Or 1 toggle% = 1 - toggle% ;If toggle is 1 Then calculate a 'concave' point x,y pair If toggle Then ;valid minorRadius values for stars are integers: 0 < minorRadius < majorRadius newX% = Cos(angle) * minorRadius + centerX newY% = Sin(angle) * minorRadius + centerY ;draw a line from last 'convex' point to new 'concave' point fatLine(oldX, oldY, newX, newY, penSize) ;If mode = 1 Then draw lines from center of star to a 'concave' point If mode% Then fatLine(newX, newY, centerX, centerY, penSize) End If Else ;valid majorRadius values for stars are integers: 0 < minorRadius <= majorRadius newX = Cos(angle) * majorRadius+ centerX newY = Sin(angle) * majorRadius+ centerY ;draw a line from last 'concave' point to new 'convex' point fatLine(oldX, oldY, newX, newY, penSize) End If ;remember last x,y pair to use as start for the next line segment oldX = newX oldY = newY Wend ;close the polyStar by drawing line from last 'concave' point to 1st 'convex' point fatLine(oldX, oldY, firstX, firstY, penSize) End Function ;********************************** fatCircle ****************************************** ;** Parameters are: ** ;** centerX%, centerY%, rad%, penSize% ** ;** ** ;** centerX%, centerY% coords locate center of circle to be plotted ** ;** rad% is the radius of the circle ** ;** penSize% is the line thickness used to draw circle ** ;** ** ;** Note: Bresenham's circle algorithm is smoother but is about 10 times slower ** ;** ** ;***************************************************************************************** Function fatCircle(centerX%, centerY%, rad%, penSize%) If penSize < 1 Or rad% < 1 Then Return False If penSize% = 1 Then Oval centerX%-rad%, centerY%-rad%, rad% Shl 1, rad% Shl 1, 0: Return offset% = penSize% Shr 1 For i% = 0 To 360 a% = Cos(i%) * rad% + centerX% b% = Sin(i%) * rad% + centerY% Oval a% - offset%, b% - offset%, penSize%, penSize%, 1 Next End Function ;****************************** fatSuperEllipse ************************************* ;** Parameters are: ** ;** centerX%, centerY%, wide%, high%, exponent#, levelOfDetail, penSize%, rotAngle% ** ;** ** ;** centerX%, centerY% coords locate center of SuperEllipse to be plotted ** ;** wide% is the x-radius of the SuperEllipse ** ;** high% is the y-radius of the SuperEllipse ** ;** exponent# determines the overall shape of the SuperEllipse (0.1 to 99 typical) ** ;** levelOfDetail# - determines number of points plotted & connected with lines ** ;** penSize% is the thickness of lines used to plot SuperEllipse ( 1 to 200 typical) ** ;** rotAngle% is the rotation angle of the SuperEllipse plotted ( 0 to 360 typical) ** ;** ** ;** Sources: ** ;** http://www.cs.colorado.edu/lizb/graphics.html ** ;** http://astronomy.swin.edu.au/pbourke/surfaces/superellipse/ ** ;** http://www.wikipedia.org/wiki/Super_ellipse ** ;** ** ;** Ported to Blitz+ by Andy Amaya 2003.10.06 ** ;***************************************************************************************** Function fatSuperEllipse (centerX%, centerY%, wide%, high%, exponent#, levelOfDetail#, penSize%, rotAngle%) rotAngle% = rotAngle% Mod 360 ;Make sure we don't get any divide by zero errors If exponent# = 2.0 Or Exponent = 0.0 Then power# = 0.0 Else power# = 2.0/exponent#-1 End If ;If rotation angle is zero then don't do the extra calculations If rotAngle% = 0 Then theta# = 0.0 ;determine the first x,y coords x1% = wide% * 1.0^power# + centerX% y1% = centerY% ;initialize theta (current angle) and loop variable theta# = levelOfDetail# limit# = 360.0 + levelOfDetail# While theta# <= limit# cosTheta# = Cos(theta#) sinTheta# = Sin(theta#) ;calculate x,y coords using Super Ellipse formula x2% = wide% * cosTheta# * Abs(cosTheta#)^power# + centerX% y2% = high% * sinTheta# * Abs(sinTheta#)^power# + centerY% ;connect the 2 sets of coords calculated with a line fatLine (x1%, y1%, x2%, y2%, penSize%) ;last coords are now first coords of line x1% = x2% y1% = y2% ;increment loop variable by amount indicated by "levelOfDetail" theta# = theta# + levelOfDetail# Wend Else ;need to rotate SuperEllipse, so do the extra math theta# = 0.0 cosTheta# = 1.0 sinTheta# = 0.0 ;pre-calc Cos() and Sin() of rotation angle cs# = Cos(rotAngle%) sn# = Sin(rotAngle%) ;calculate the first rotated x,y coords rotX# = wide% * 1.0^power# rotY# = 0.0 x1% = cs# * rotX# - sn# * rotY# + centerX% y1% = sn# * rotX# + cs# * rotY# + centerY% ;initialize theta (current angle) and loop variable theta# = levelOfDetail# limit# = 360.0 + levelOfDetail# While theta# <= limit# cosTheta# = Cos(theta#) sinTheta# = Sin(theta#) ;calculate the next pair of rotated x,y coords rotX# = cosTheta# * wide% * Abs(cosTheta#)^power# rotY# = sinTheta# * high% * Abs(sinTheta#)^power# x2% = cs# * rotX# - sn# * rotY# + centerX% y2% = sn# * rotX# + cs# * rotY# + centerY% ;connect the 2 sets of coords calculated with a line fatLine(x1%, y1%, x2%, y2%, penSize) ;last coords are now first coords of line x1% = x2% y1% = y2% ;increment loop variable by amount indicated by "levelOfDetail" theta# = theta# + levelOfDetail# Wend End If End Function |
Comments
None.
Code Archives Forum