'===========================================================================
' 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
