'=========================================================================== ' Subject: ARROW MANIA! Date: 12-17-98 (17:52) ' Author: David Szafranski Code: LB ' Origin: digital_paris@csi.com Packet: LIBERTY.ABC '=========================================================================== 'ArrowMania! 'Program to draw random points, then draw line arrows between the closest 'neighboring points. Includes code for trackbar/slider for selecting variables. 'Also contains a fast Shell Sort routine. 'David Szafranski August 1998 digital_paris@csi.com nomainwin [arrow] checkFlag = 1 ' Set up tracker1 variables (points) which can be modified by user SlideMin=10 'Minimum Slider Value SlideMax=100 'Maximum Slider Value 'max no of points to be drawn tickMarks = 10 'distance between tick marks ' Initialize other tracker1 variables XMin=5 'Current Cursor X-Min Position XMax=218 'Current Cursor X-Max Position YMin=15 'Current Cursor Y-Min Position (Constant) YMax=30 'Current Cursor Y-Max Position (Constant) pointerWidth = 13 'width of pointer (constant) range = XMax-XMin-pointerWidth xstop = XMax-pointerWidth ' Set up tracker2 variables (closest) which can be modified by user SlideMin2=1 'Minimum Slider Value SlideMax2=9 'Maximum Slider Value tickMarks2 = 25 'distance between tick marks ' Initialize other tracker2 variables XMin2=5 'Current Cursor X-Min Position XMax2=218 'Current Cursor X-Max Position YMin2=15 'Current Cursor Y-Min Position (Constant) YMax2=30 'Current Cursor Y-Max Position (Constant) pointerWidth2 = 13 'width of pointer (constant) range2 = XMax2-XMin2-pointerWidth2 xstop2 = XMax2-pointerWidth2 WindowWidth = 430 WindowHeight = 600 UpperLeftX = int((DisplayWidth - WindowWidth) / 2) UpperLeftY = int((DisplayHeight - WindowHeight) / 2) button #arrow.setTracker2, "Apply!", [setTracker2], UL, 295, 527, 60, 20 button #arrow.setTracker1, "Apply!", [setTracker1], UL, 295, 472, 60, 20 button #arrow.draw, "Draw!", [drawArrow], UL, 10, 10, 74, 20 button #arrow.save, "Save!", [saveBmp], UL, 85, 10, 74, 20 button #arrow.exit, "Exit!", [quitArrow], UL, 159, 10, 74, 20 checkbox #arrow.chk, "", [arrowFlag], [arrowFlag], 240, 15, 15, 15 graphicbox #arrow.tracker2, 10, 507, 227, 45 graphicbox #arrow.tracker1, 10, 452, 227, 45 textbox #arrow.trackValue2, 245, 527, 40, 20 textbox #arrow.trackValue1, 245, 472, 40, 20 graphicbox #arrow.drawing, 10, 40, 402, 402 graphicbox #arrow.back, 0, 0, 422, 570 open "ArrowMania!" for dialog_modal as #arrow print #arrow, "trapclose [quitArrow]" open "gdi.dll" for dll as #gdi open "user.dll" for dll as #user h = hwnd(#arrow.drawing) 'get handle of window calldll #user ,"GetDC",_ h as word,_ hdc as word print #arrow, "down; fill lightgray" print #arrow.back, "down; fill lightgray" print #arrow.back, "backcolor lightgray" print #arrow.back, "place 258 25" print #arrow.back, "color black" print #arrow.back, "\Add Arrows!" 'label for checkbox print #arrow.back, "place 243 465" print #arrow.back, "\Total Number of Points" 'label for tracker1 print #arrow.back, "place 243 520" print #arrow.back, "\Number of Closest Points" 'label for tracker2 print #arrow.drawing, "down; fill lightgray; flush; flush" print #arrow, "flush" print #arrow.back, "flush" aFlag = 0 'arrow flag to turn arrows on or off using checkbox 0=off gbox = 400 pi = 3.1415926535896 arrowAngle = 10 arrowHeadLength = 15 gosub [initTracker1] 'initialize tracker1 gosub [initTracker2] 'initialize tracker2 [arrowLoop] input aVar$ goto [arrowLoop] [arrowFlag] print #arrow.chk, "value?" input #arrow.chk, result$ if result$ = "set" then aFlag = 1 else aFlag =0 goto [arrowLoop] [drawArrow] print #arrow.drawing, "segment" input #arrow.drawing, segNo print #arrow.drawing, "delsegment "; segNo-1 'delete last drawing print #arrow.drawing, "redraw" print #arrow.drawing, "fill lightgray" print #arrow.drawing, "size 1" flag = 1 RandomN.Seed = 0 ' points = 20 ' number of points to draw print #arrow.trackValue1, "!contents?" 'get value for points input #arrow.trackValue1, Var$ points = int(val(Var$)) MouseX = (points - SlideMin)/(SlideMax-SlideMin)*range+XMin if MouseX > XMax then MouseX=xstop : print #arrow.trackValue1, SlideMax if MouseX < XMin then MouseX=XMin : print #arrow.trackValue1, SlideMin xM = MouseX gosub [pointerLines] redim px(points) 'location of x points redim py(points) 'location of y points redim dist(points,points) 'point number and distance between it and all the other points redim array(points) 'temp array to sort distances redim position(points) 'temp pointer array to keep track of relative order of closest points cursor hourglass ' closest = 5 'number of closest points to select and draw lines to print #arrow.trackValue2, "!contents?" 'get value for number of closest points to draw line to input #arrow.trackValue2, Var$ closest = int(val(Var$)) MouseX = (closest - SlideMin2)/(SlideMax2-SlideMin2)*range2+XMin2 if MouseX > XMax2 then MouseX=xstop2 : print #arrow.trackValue2, SlideMax2 if MouseX < XMin2 then MouseX=XMin2 : print #arrow.trackValue2, SlideMin2 xM2 = MouseX gosub [pointerLines2] for i = 0 to points-1 gosub [RandomN] 'select random points and put into arrays px() and py() y1 = int(RandomN.RN * gbox) + 1 gosub [RandomN] x1 = int(RandomN.RN * gbox) + 1 px(i) = x1 py(i) = y1 print #arrow.drawing, "place "; x1; " "; y1 print #arrow.drawing, "color black; backcolor black" print #arrow.drawing, "circlefilled 3" next i for i = 0 to points-1 'calc distance between all points and put in dist() for j = 0 to points-1 if px(i) - px(j) = 0 then dist(i,j) = abs(py(i)-py(j)) : goto [nextpoint] 'trying to avoid 0^2 error if py(i) - py(j) = 0 then dist(i,j) = abs(px(i)-px(j)) : goto [nextpoint] dist(i,j) = ((abs(px(i)-px(j)))^2 + (abs(py(i)-py(j)))^2)^0.5 [nextpoint] next j next i for j= 0 to points-1 'create dummy arrays for i = 0 to points-1 position(i) = i array(i) = dist(j,i) next i ' start of Shell Sort to sort array() and position() index array center = int(points / 2) WHILE center > 0 boundary = points - center flag = 1 while flag <> 0 flag = 0 FOR a = 1 TO boundary IF array(a-1) > array(a + center-1) THEN temp1 = array(a-1) temp2 = array(a + center-1) array(a-1) = temp2 array(a + center-1) = temp1 temp3 = position(a-1) temp4 = position(a + center-1) position(a-1) = temp4 position(a + center-1) = temp3 flag = a END IF NEXT a boundary = flag - center wend center = int(center / 2) wend ' end of Shell Sort 'now print lines between the point and closest neighboring points 'skip first point since it is always closest to itself for k= 1 to closest x1 = px(j) y1 = py(j) x2 = px(position(k)) y2 = py(position(k)) if aFlag = 1 then gosub [startArrow] if aFlag = 1 then gosub [endArrow] gosub [drawLine] next k next j print #arrow.drawing, "flush" cursor normal goto [arrowLoop] [saveBmp] notice "Not Available!" goto [arrowLoop] [setTracker1] print #arrow.trackValue1, "!contents?" 'after user input, update textbox input #arrow.trackValue1, Var$ points = int(val(Var$)) MouseX = (points - SlideMin)/(SlideMax-SlideMin)*range+XMin if MouseX > XMax then MouseX=xstop : print #arrow.trackValue1, SlideMax if MouseX < XMin then MouseX=XMin : print #arrow.trackValue1, SlideMin xM = MouseX gosub [pointerLines] goto [arrowLoop] [arrow.LMU] 'Left Mouse Button Up If MouseY < YMin then Goto [arrowLoop] 'click too High Up If MouseY > YMax then Goto [arrowLoop] 'click too Low Down If MouseX < XMin then goto [arrowLoop] 'click too Far Left If MouseX > XMax then goto [arrowLoop] 'click too Far Right If MouseX>xstop then MouseX=xstop 'Tried to move the mouse too far to the right xM = MouseX gosub [pointerLines] points=int(((MouseX-XMin)/range)*(SlideMax-SlideMin)+SlideMin) 'Calculate Slider Value print #arrow.trackValue1, str$(points) 'Display Slider Value goto [arrowLoop] [arrow.LMM] 'Left Mouse Move If MouseY < YMin then goto [arrowLoop] If MouseY > YMax then goto [arrowLoop] If MouseX < XMin then goto [arrowLoop] If MouseX > XMax then goto [arrowLoop] If MouseX>xstop Then MouseX=xstop xM = MouseX gosub [pointerLines] points=int(((MouseX-XMin)/range)*(SlideMax-SlideMin)+SlideMin) 'Calculate Slider Value print #arrow.trackValue1, str$(points) 'Display Slider Value goto [arrowLoop] [setTracker2] print #arrow.trackValue2, "!contents?" input #arrow.trackValue2, Var$ closest = int(val(Var$)) MouseX = (closest - SlideMin2)/(SlideMax2-SlideMin2)*range2+XMin2 if MouseX > XMax2 then MouseX=xstop2 : print #arrow.trackValue2, SlideMax2 if MouseX < XMin2 then MouseX=XMin2 : print #arrow.trackValue2, SlideMin2 xM2 = MouseX gosub [pointerLines2] goto [arrowLoop] [arrow.LMU2] 'Left Mouse Button Up If MouseY < YMin2 then goto [arrowLoop] 'click too High Up If MouseY > YMax2 then goto [arrowLoop] 'click too Low Down If MouseX < XMin2 then goto [arrowLoop] 'click too Far Left If MouseX > XMax2 then goto [arrowLoop] 'click too Far Right If MouseX>xstop then MouseX=xstop 'Tried to move the mouse too far to the right xM2 = MouseX gosub [pointerLines2] closest=int(((MouseX-XMin2)/range2)*(SlideMax2-SlideMin2)+SlideMin2) 'Calculate Slider Value print #arrow.trackValue2, str$(closest) 'Display Slider Value goto [arrowLoop] [arrow.LMM2] 'Left Mouse Move If MouseY < YMin2 then goto [arrowLoop] If MouseY > YMax2 then goto [arrowLoop] If MouseX < XMin2 then goto [arrowLoop] If MouseX > XMax2 then goto [arrowLoop] If MouseX>xstop2 then MouseX=xstop2 xM2 = MouseX gosub [pointerLines2] closest=int(((MouseX-XMin2)/range2)*(SlideMax2-SlideMin2)+SlideMin2) 'Calculate Slider Value print #arrow.trackValue2, str$(closest) 'Display Slider Value goto [arrowLoop] [quitArrow] close #gdi close #user close #arrow end [drawLine] if aFlag = 0 then print #arrow.drawing, "color white; backcolor lightgray" print #arrow.drawing, "line "; x1; " "; y1+1; " "; x2; " "; y2+1 if x1 = x2 then print #arrow.drawing, "line "; x1+1; " "; y1; " "; x2+1; " "; y2 end if print #arrow.drawing, "color black; backcolor black" print #arrow.drawing, "line "; x1; " "; y1; " "; x2; " "; y2 print #arrow.drawing, "color black; backcolor black" print #arrow.drawing, "circlefilled 3" return [endArrow] 'draw arrowhead at end of line segment if x1 -x2 = 0 then degrees = 90 : goto [jump] degrees = atn((y2-y1)/(x1-x2)) * 180 / pi 'get slope of line in degrees [jump] if x1-x2 < 0 then x6=int(x2+cos((degrees+arrowAngle-180)*0.0174533)*arrowHeadLength) y6=int(y2-sin((degrees+arrowAngle-180)*0.0174533)*arrowHeadLength) x7=int(x2+cos((degrees-arrowAngle-180)*0.0174533)*arrowHeadLength) y7=int(y2-sin((degrees-arrowAngle-180)*0.0174533)*arrowHeadLength) else x6=int(x2+cos((degrees+arrowAngle)*0.0174533)*arrowHeadLength) y6=int(y2-sin((degrees+arrowAngle)*0.0174533)*arrowHeadLength) x7=int(x2+cos((degrees-arrowAngle)*0.0174533)*arrowHeadLength) y7=int(y2-sin((degrees-arrowAngle)*0.0174533)*arrowHeadLength) end if print #arrow.drawing, "color black" print #arrow.drawing, "line "; x2; " "; y2; " "; x6; " "; y6 print #arrow.drawing, "line "; x6; " "; y6; " "; x7; " "; y7 print #arrow.drawing, "line "; x7; " "; y7; " "; x2; " "; y2 centerX = int((x2+x6+x7)/3) centerY = int((y2+y6+y7)/3) gosub [floodFill] return [startArrow] 'draw arrowhead at beginning of line segment if x2 - x1 = 0 then degrees = 90 : goto [jump2] degrees = atn((y1-y2)/(x2-x1)) * 180 / pi 'get slope of line in degrees [jump2] if x1-x2 > 0 then x6=int(x1+cos((degrees+arrowAngle-180)*0.0174533)*arrowHeadLength) y6=int(y1-sin((degrees+arrowAngle-180)*0.0174533)*arrowHeadLength) x7=int(x1+cos((degrees-arrowAngle-180)*0.0174533)*arrowHeadLength) y7=int(y1-sin((degrees-arrowAngle-180)*0.0174533)*arrowHeadLength) else x6=int(x1+cos((degrees+arrowAngle)*0.0174533)*arrowHeadLength) y6=int(y1-sin((degrees+arrowAngle)*0.0174533)*arrowHeadLength) x7=int(x1+cos((degrees-arrowAngle)*0.0174533)*arrowHeadLength) y7=int(y1-sin((degrees-arrowAngle)*0.0174533)*arrowHeadLength) end if print #arrow.drawing, "color black" print #arrow.drawing, "line "; x1; " "; y1; " "; x6; " "; y6 print #arrow.drawing, "line "; x6; " "; y6; " "; x7; " "; y7 print #arrow.drawing, "line "; x7; " "; y7; " "; x1; " "; y1 centerX = int((x1+x6+x7)/3) centerY = int((y1+y6+y7)/3) gosub [floodFill] return ' Random Number Generator by Brosco ' Functions ' [RandomN] Generates Random Numbers starting with the SEED value ' supplied in RandomN.Seed ' INPUT: RandomN.Seed value of 0 to 199017 to SEED the RNG. If a ' value of 0 is given, the LB Rnd function is ' called to give a Random Seed. ' OUTPUT: RandomN.RN Returns a value between 0 and 1. ' [RandomN] if RandomN.Seed = 0 then gosub [RandomN.SeedRNG] RandomN.C1=24298 RandomN.C2=99991 RandomN.C3=199017 RandomN.SeedTmp = RandomN.C1 * RandomN.Seed + RandomN.C2 RandomN.Seed = RandomN.SeedTmp - int( RandomN.SeedTmp / RandomN.C3 ) * RandomN.C3 RandomN.RN = RandomN.Seed / RandomN.C3 return [RandomN.SeedRNG] RandomN.Seed = rnd(1) * 199017 return [pointerLines] print #arrow.tracker1, "segment" input #arrow.tracker1, segNo print #arrow.tracker1, "delsegment "; segNo-1 print #arrow.tracker1, "redraw" print #arrow.tracker1, "color red; backcolor red; place "; XMin; " "; 20 print #arrow.tracker1, "boxfilled "; xM-1; " "; 30 print #arrow.tracker1, "color lightgray; backcolor lightgray; place "; xM+2; " "; 17 print #arrow.tracker1, "boxfilled "; xM+12; " "; 34 print #arrow.tracker1, "color white"; print #arrow.tracker1, "line "; xM; " "; 15; " "; xM; " "; 35 print #arrow.tracker1, "line "; xM+1; " "; 15; " "; xM+1; " "; 34 print #arrow.tracker1, "line "; xM +7; " "; 10;" "; xM+1; " ";15 print #arrow.tracker1, "line "; xM +7; " "; 9;" "; xM; " ";15 print #arrow.tracker1, "color black"; print #arrow.tracker1, "line "; xM + 7; " "; 9; " "; xM+13; " "; 15 print #arrow.tracker1, "line "; xM+13; " "; 15; " "; xM+13; " "; 35 print #arrow.tracker1, "line "; xM; " "; 35; " "; xM+14; " "; 35 print #arrow.tracker1, "color darkgray"; print #arrow.tracker1, "line "; xM +7; " "; 10; " "; xM+12; " "; 15 print #arrow.tracker1, "line "; xM+12; " "; 16; " "; xM+12; " "; 34 print #arrow.tracker1, "line "; xM+1; " "; 34; " "; xM+13; " "; 34 print #arrow.tracker1, "flush" return [initTracker1] print #arrow.tracker1, "when leftButtonUp [arrow.LMU]" print #arrow.tracker1, "when leftButtonMove [arrow.LMM]" print #arrow.trackValue1, str$(SlideMin) 'Display Initial Slider Value print #arrow.tracker1, "fill lightgray"; print #arrow.tracker1, "down; color black"; print #arrow.tracker1, "line "; XMin-3; " "; 17; " "; XMax+3; " "; 17 print #arrow.tracker1, "line "; XMin-3; " "; 17; " "; XMin-3; " "; 33 print #arrow.tracker1, "down; color darkgray"; print #arrow.tracker1, "line "; XMin-2; " "; 18; " "; XMax+2; " "; 18 print #arrow.tracker1, "line "; XMin-2; " "; 18; " "; XMin-2; " "; 32 print #arrow.tracker1, "down; color white"; print #arrow.tracker1, "line "; XMin-3; " "; 33; " "; XMax+3; " "; 33 print #arrow.tracker1, "line "; XMax+3; " "; 17; " "; XMax+3; " "; 33 print #arrow.tracker1, "line "; XMin-2; " "; 32; " "; XMax+2; " "; 32 print #arrow.tracker1, "line "; XMax+2; " "; 18; " "; XMax+2; " "; 32 for i = 0 to range step tickMarks print #arrow.tracker1, "color black; down"; print #arrow.tracker1, "line "; XMin+7+i; " "; 5; " "; XMin+7+i; " "; 7 next i print #arrow.tracker1, "flush"; print #arrow.tracker1, "flush"; xM = XMin gosub [pointerLines] return [pointerLines2] print #arrow.tracker2, "segment" input #arrow.tracker2, segNo print #arrow.tracker2, "delsegment "; segNo-1 print #arrow.tracker2, "redraw" print #arrow.tracker2, "color red; backcolor red; place "; XMin2; " "; 20 print #arrow.tracker2, "boxfilled "; xM2-1; " "; 30 print #arrow.tracker2, "color lightgray; backcolor lightgray; place "; xM2+2; " "; 17 print #arrow.tracker2, "boxfilled "; xM2+12; " "; 34 print #arrow.tracker2, "color white"; print #arrow.tracker2, "line "; xM2; " "; 15; " "; xM2; " "; 35 print #arrow.tracker2, "line "; xM2+1; " "; 15; " "; xM2+1; " "; 34 print #arrow.tracker2, "line "; xM2 +7; " "; 10;" "; xM2+1; " ";15 print #arrow.tracker2, "line "; xM2 +7; " "; 9;" "; xM2; " ";15 print #arrow.tracker2, "color black"; print #arrow.tracker2, "line "; xM2 + 7; " "; 9; " "; xM2+13; " "; 15 print #arrow.tracker2, "line "; xM2+13; " "; 15; " "; xM2+13; " "; 35 print #arrow.tracker2, "line "; xM2; " "; 35; " "; xM2+14; " "; 35 print #arrow.tracker2, "color darkgray"; print #arrow.tracker2, "line "; xM2 +7; " "; 10; " "; xM2+12; " "; 15 print #arrow.tracker2, "line "; xM2+12; " "; 16; " "; xM2+12; " "; 34 print #arrow.tracker2, "line "; xM2+1; " "; 34; " "; xM2+13; " "; 34 print #arrow.tracker2, "flush" return [initTracker2] print #arrow.tracker2, "when leftButtonUp [arrow.LMU2]" print #arrow.tracker2, "when leftButtonMove [arrow.LMM2]" print #arrow.trackValue2, str$(SlideMin2) 'Display Initial Slider Value print #arrow.tracker2, "fill lightgray"; print #arrow.tracker2, "down; color black"; print #arrow.tracker2, "line "; XMin2-3; " "; 17; " "; XMax2+3; " "; 17 print #arrow.tracker2, "line "; XMin2-3; " "; 17; " "; XMin2-3; " "; 33 print #arrow.tracker2, "down; color darkgray"; print #arrow.tracker2, "line "; XMin2-2; " "; 18; " "; XMax2+2; " "; 18 print #arrow.tracker2, "line "; XMin2-2; " "; 18; " "; XMin2-2; " "; 32 print #arrow.tracker2, "down; color white"; print #arrow.tracker2, "line "; XMin2-3; " "; 33; " "; XMax2+3; " "; 33 print #arrow.tracker2, "line "; XMax2+3; " "; 17; " "; XMax2+3; " "; 33 print #arrow.tracker2, "line "; XMin2-2; " "; 32; " "; XMax2+2; " "; 32 print #arrow.tracker2, "line "; XMax2+2; " "; 18; " "; XMax2+2; " "; 32 for i = 0 to range step tickMarks2 print #arrow.tracker2, "color black; down"; print #arrow.tracker2, "line "; XMin2+7+i; " "; 5; " "; XMin2+7+i; " "; 7 next i print #arrow.tracker2, "flush"; print #arrow.tracker2, "flush"; xM2 = XMin2 gosub [pointerLines2] return [floodFill] print #arrow.drawing, "backcolor black" 'will fill with this color calldll #gdi, "FloodFill", _ hdc as word, _ centerX as short, _ 'x location within shape centerY as short, _ 'y location within shape 0 as long, _ '0=black bounding color results as short return