none
Small Basic Subroutine Library Project

    General discussion

  • I sometimes use same subroutines in different programs.  For example, I used Math_CartesianToPolar() in a new program today.  Actually I used this subroutine in several programs.

    My suggestion is to collect these kind of useful subroutines here and if possible with test code like below.

    ' Math_CartesianToPolar Test Program
    GraphicsWindow.Title = "Test - Cartesian to Polar"
    gw = 598
    gh = 428
    GraphicsWindow.Width = gw
    GraphicsWindow.Height = gh
    color = "LightGray"
    dx = 10
    dy = 10
    x1 = Math.Remainder(gw / 2, dx) - dx
    x2 = gw - x1
    y1 = Math.Remainder(gh / 2, dy) - dy
    y2 = gh - y1
    DrawGrid()
    color = "Gray"
    dx = 100
    dy = 100
    x1 = Math.Remainder(gw / 2, dx) - dx
    x2 = gw - x1
    y1 = Math.Remainder(gh / 2, dy) - dy
    y2 = gh - y1
    DrawGrid()
    GraphicsWindow.BrushColor = "Black"
    xText = Shapes.AddText("")
    Shapes.Move(xText, 10, 20)
    yText = Shapes.AddText("")
    Shapes.Move(yText, 10, 40)
    rText = Shapes.AddText("")
    Shapes.Move(rText, 10, 60)
    aText = Shapes.AddText("")
    Shapes.Move(aText, 10, 80)
    x2Text = Shapes.AddText("")
    Shapes.Move(x2Text, 10, 100)
    y2Text = Shapes.AddText("")
    Shapes.Move(y2Text, 10, 120)
    GraphicsWindow.MouseMove = OnMouseMove
    While "True"
      If mouseMove Then
        x = mx - gw / 2
        y = my - gh / 2
        Math_CartesianToPolar()
        Shapes.SetText(xText, "x=" + x)
        Shapes.SetText(yText, "y=" + y)
        Shapes.SetText(aText, "a=" + a)
        Shapes.SetText(rText, "r=" + r)
        Math_PolarToCartesian()
        Shapes.SetText(x2Text, "x=" + x)
        Shapes.SetText(y2Text, "y=" + y)
        If mx <> mxLast Or my <> myLast Then
          If line <> "" Then
            Shapes.Remove(line)
          EndIf
          GraphicsWindow.PenColor = "Red"
          line = Shapes.AddLine(gw / 2, gh / 2, mx, my)
          mxLast = mx
          myLast = my
        EndIf
      EndIf
    EndWhile
    Sub OnMouseMove
      mx = GraphicsWindow.MouseX
      my = GraphicsWindow.MouseY
      mouseMove = "True"
    EndSub
    Sub DrawGrid
      ' param x1, x2 - x range
      ' param dx - delta x
      ' param y1, y2 - y range
      ' param dy - delta y
      ' param color - color for grid
      GraphicsWindow.PenColor = color
      For x = x1 To x2 Step dx
        GraphicsWindow.DrawLine(x, y1, x, y2)
      EndFor
      For y = y1 To y2 Step dy
        GraphicsWindow.DrawLine(x1, y, x2, y)
      EndFor
    EndSub
    Sub Math_PolarToCartesian
      ' Math | convert Cartesian coodinate to polar coordinate
      ' param r, a - polar Coordinate
      ' return x, y - Cartesian coordinate
      _a = Math.GetRadians(a)
      x = r * Math.Cos(_a)
      y = r * Math.Sin(_a)
    EndSub
    Sub Math_CartesianToPolar
      ' Math | convert Cartesian coodinate to polar coordinate
      ' param x, y - Cartesian coordinate
      ' return r, a - polar Coordinate (0<=a<360)
      r = Math.SquareRoot(x * x + y * y)
      If x = 0 And y > 0 Then
        a = 90 ' [degree]
      ElseIf x = 0 And y < 0 Then
        a = -90
      Else
        a = Math.ArcTan(y / x) * 180 / Math.Pi
      EndIf
      ' at this point -90<=a<=90
      If x < 0 Then
        a = a + 180
      ElseIf x >= 0 And y < 0 Then
        a = a + 360
      EndIf
      ' at this point 0<=a<360
    EndSub

    Subroutines introduced in this thread:

    • Clock_DateToJD
    • Clock_Init
    • Clock_JDNow
    • Clock_JDtoDate
    • Color_Blacken
    • Color_ColorToRGB
    • Color_NameToColor
    • Colors_Init
    • Directory_Exists
    • File_CheckResult
    • File_Exists
    • FileHelper_ShowError
    • Math_CartesianToPolar
    • Math_Hex2Dec
    • Math_PolarToCartesian
    • Parse_Char
    • Parse_Digit
    • Parse_Init
    • Parse_Integer
    • Parse_Number
    • Parse_Real
    • Parse_Sci
    • Path_GetFileName
    • Path_GetDirectoryName
    • bubblesort (by litdev)
    • shellsort (by litdev)
    • Test_Pass
    • Text_Compare
    • Text_IsNumber
    • Text_Split
    • TW_DrawLineWithChar

    Nonki Takahashi

    Friday, August 26, 2016 11:32 AM
    Moderator

All replies

  • I found a bug in this subroutine (Math_CartesianToPolar).  I uploaded the bug fixed version as JXB040.

    Nonki Takahashi

    Friday, March 03, 2017 5:21 AM
    Moderator
  • I wrote a TechNet Wiki article about this program.

    Small Basic Sample: Math.Sin, Math.Cos and Math.Tan


    Nonki Takahashi

    Friday, March 03, 2017 7:16 AM
    Moderator
  • Hello Nonki
    Very interesting program. However could you explain to me why, in the example below, when I point the mouse to the Cartesian coordinates x = and y = 100, in your JXB040 program it returns y =-100.

    Off, if I base myself on this Wikipedia article about Cartesian coordinates system, the upper right quadrant is always positive + x and y +. so why use a negative value for y?

    https://en.wikipedia.org/wiki/Cartesian_coordinate_system



    • Edited by YLedEditor Friday, March 03, 2017 2:20 PM
    Friday, March 03, 2017 2:19 PM
    Answerer
  • A few mods JXB040-0

    As the SB GraphicsWindow is quadrant IV in the cartesian system, every point has to be mirrored about the x-axis, to get pos. y values.

    Friday, March 03, 2017 10:30 PM
    Answerer
  • Nice idea Nonli,

    Here are some array sort methods.

    'Example of efficient ShellSort algorithm to sort a list, comparing with BubbleSort
    
    'Create a random 500 element array
    numVal = 500
    For i = 1 To numVal
      val[i] = Math.GetRandomNumber(numVal) 
    EndFor
    valStore = val
    
    'ShellSort it
    TextWindow.Write("ShellSort ")
    val = valStore
    start = Clock.ElapsedMilliseconds
    shellsort()
    timing = 0.001*Math.Floor(0.5+(Clock.ElapsedMilliseconds-start)) 'Nearest 1000th of a second
    TextWindow.WriteLine(timing+" sec")
    
    'BubbleSort it
    TextWindow.Write("BubbleSort ")
    val = valStore
    start = Clock.ElapsedMilliseconds
    bubblesort()
    timing = 0.001*Math.Floor(0.5+(Clock.ElapsedMilliseconds-start))
    TextWindow.WriteLine(timing+" sec")
    
    Sub shellsort
      inc = Math.Round(numVal/2)
      While inc > 0
        For i = inc To numVal
          temp = val[i]
          j = i
          while (j >= inc) and (val[j-inc] > temp)
            val[j] = val[j-inc]
            j = j - inc
          EndWhile
          val[j] = temp
        EndFor
        inc = Math.Round(inc/2.2)
      Endwhile
    Endsub
    
    Sub bubblesort
      For i = 1 To numVal
        For j = i+1 To numVal
          If (val[j] < val[i]) Then
            temp = val[i]
            val[i] = val[j]
            val[j] = temp
          EndIf
        EndFor
      EndFor
    EndSub

    Saturday, March 04, 2017 11:39 AM
    Moderator
  • YLed, I just would liked to use the subroutines for graphics window coordinate.  But if the origin is at the top left corner, x and y must be positive to see.  So I move the origin to the center of the graphics window.

    Subroutines themselves are not depend on coordinate systems.


    Nonki Takahashi


    Sunday, March 12, 2017 2:10 PM
    Moderator
  • I wrote a bowling game program (GRT732-3) for Challenge of the Month - March 2017.

    In the program, I used following subroutines.

    • Color_Blacken - blacken given color
    • Color_ColorToRGB - convert color to RGB values
    • Color_NameToColor - convert color name to color
    • Colors_Init - initialize 140 colors array
    • Math_Hex2Dec - convert hexadecimal to decimal
    • Text_Split - split text to array by delimiter

    Nonki Takahashi


    Sunday, March 12, 2017 2:34 PM
    Moderator
  • This is a sample with TextWindow:  QGK077-0.

    Subroutine in this program:

    • TW_DrawLineWithChar

    Nonki Takahashi

    Monday, March 13, 2017 1:08 AM
    Moderator
  • This is a text compare sample: JLS539.

    Subroutine in this program:

    • Text_Compare
    • Text_CompareText (internal use)

    Nonki Takahashi

    Monday, March 13, 2017 1:38 AM
    Moderator
  • This a really good idea but you need to be careful with variable names. For example, x and y are pretty generic names that might be used somewhere else in the program. If you then call a subroutine that uses x or y,its value maybe overridden.  You need to be very disciplined in the use of variables. I can think of two solutions to this. The first is that you publish a dictionary of variable names and what they are used for (so they don't get used for something inappropriate) or change the names in the subroutines to be unique by, for example, prefixing them with the subroutine name.

    The problem occurs, of course, because SB doesn't support local variables or subroutine parameters.

    Saturday, March 18, 2017 11:27 AM
  • This a really good idea but you need to be careful with variable names. For example, x and y are pretty generic names that might be used somewhere else in the program. If you then call a subroutine that uses x or y,its value maybe overridden.  You need to be very disciplined in the use of variables. I can think of two solutions to this. The first is that you publish a dictionary of variable names and what they are used for (so they don't get used for something inappropriate) or change the names in the subroutines to be unique by, for example, prefixing them with the subroutine name.

    The problem occurs, of course, because SB doesn't support local variables or subroutine parameters.


    Good point, parhaps start all local variables in subroutines with _, eg _x, _y etc.  This kind of discipline can help to create good reusable code.
    Saturday, March 18, 2017 6:21 PM
    Moderator
  • Yes, that is better, litdev, but still has potential for overwriting of one 'local' variable by one in another subroutine.  I was thinking that if you had, say, a subroutine called 'add', then its local variables could be called add_x, add_y, etc. This way if the subroutine names are unique then the variables will be, too.
    Sunday, March 19, 2017 2:14 PM
  • It is also possible to push all local variables on a stack at the start of the Sub and pop them at the end

    a=1 b=2 s="stack1" s() TextWindow.WriteLine("A = "+a) TextWindow.WriteLine("B = "+b)

    TextWindow.WriteLine("C = "+c)

    TextWindow.Pause() Sub s Stack.PushValue(s,a) Stack.PushValue(s,b) a=101 b=102

    c=103 TextWindow.WriteLine("in sub A = "+a) TextWindow.WriteLine("in sub B = "+b) TextWindow.WriteLine("in sub C = "+c) c=stack.PopValue(s) b=stack.PopValue(s) a=stack.PopValue(s) EndSub

    Edit: added c ( unused in the main program)



    Jan [ WhTurner ] The Netherlands






    Sunday, March 19, 2017 2:18 PM
    Answerer
  • Good thinking, Jan, in principle it's a good idea, though to be safe you would need to push an pop every variable from the main program, which could be tedious.

    Another good use of the stack would be to pass parameters to a subroutine by pushing values before the call and popping them into local variables inside the subroutine.


    • Edited by outbyone Tuesday, March 21, 2017 9:33 AM typo
    Tuesday, March 21, 2017 9:32 AM
  • I've put a short tutorial about how you can implement local variables, as well as parameters and return values, on my blog here: http://programmingprof.blogspot.com.es
    Sunday, March 26, 2017 3:31 PM
  • I wrote this program (PMQ660-1) for Challenge of the Month - May 2015.

    This program has following subroutines.

    • Directory_Exists
    • File_CheckResult
    • File_Exists
    • FileHelper_ShowError
    • Path_GetFileName
    • Path_GetDirectoryName
    • Test_Pass

    Nonki Takahashi

    Wednesday, April 19, 2017 1:14 AM
    Moderator
  • Nonki,

    If I try to import the above program as "PMQ660-1" it says this file can't be found. But if I import "PMQ660" it does find that file. Maybe I am wrong, but shouldn't you be able to import the former file if it is actually there? Also, you said that the above has the following subroutines. When I look at the subroutines in the file that I can actually import it does not show "File_CheckResult" or "FileHelper_ShowError" subroutines. So, I'm thinking I'm not actually able to import the file that you want us to import.


    JR

    Thursday, April 20, 2017 2:17 AM
    Answerer
  • Sorry, JR.  I've forgotten to publish PMQ660-0 and PMQ660-1.  I just published them.  Thanks.

    Nonki Takahashi

    Thursday, April 20, 2017 12:07 PM
    Moderator
  • Nonki,

    Got it! PMQ660-1 is great. Good example of how to use some of the file and directory commands and how to test for errors.

    Thanks,


    JR

    Thursday, April 20, 2017 12:52 PM
    Answerer
  • I will add a program Date Calculator JQQ629-0.

    You can enable testing with doTest = "True".  Added subroutines:

    • Clock_Init
    • Clock_DateToJD
    • Clock_JDToDate
    • Clock_JDNow

    Nonki Takahashi

    Friday, June 30, 2017 1:38 AM
    Moderator
  • I wrote a IsNumber subroutine: GKR726.

    Screen shot of a program IsNumber

    This program has following subroutines.

    • Text_IsNumber
    • Parse_Init
    • Parse_Char
    • Parse_Digit
    • Parse_Integer
    • Parse_Real
    • Parse_Sci
    • Parse_Number

    Nonki Takahashi

    Saturday, July 08, 2017 1:06 AM
    Moderator