Author Topic: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees  (Read 2266 times)

0 Members and 1 Guest are viewing this topic.

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
re: @SMcNeill and @STxAxTIC

Here's the latest monster in this series,
see options 19 + 20 from the menu to try ShearRotate4,
which only looks for missing pixels if the angle
of rotation is 30, 60, 120, 150, 210, 240, 300, 330,
and finds an empty space based on which quarter of the screen
and whether rotation is clockwise / counter-clockwise.

Maybe @SMcNeill 's little rotation algorithm can help simplify this,
or @STxAxTIC 's idea of combining the adjacent angle-1 and angle+1,
but my attention is currently divided and I'm a little busy to wrap my head around these
(this is where "I'm not a math person" starts to become a challenge!)

The output of ShearRotate2, ShearRotate3, and ShearRotate4 all look identical in the tests, but
ShearRotate2 does more calculations (inefficient) and the logic to find points is not great,
ShearRotate3 does less calculations but the logic wrongly uses the angle not the _direction_ or screen area,
and ShearRotate4 seems to be the most accurate logic.

Anyway, here it is if you want to try it, now includes semicircles and plot circles to top/left x,y:
  • Plot a point
  • Plot a square
  • Plot a circle (specifying center x,y)
  • Plot a circle (specifying top left x,y)
  • Plot a semicircle
  • Plot a solid circle (specifying center x,y)
  • Plot a solid circle (specifying top left x,y)
  • Plot a solid semicircle
  • Plot an ellipse
  • Plot a solid ellipse
  • Plot a line
  • Rotate (4 different variations)

Enjoy...

Code: QB64: [Select]
  1. ' ################################################################################################################################################################
  2. ' #TOP
  3.  
  4. ' Basic 2D plotting functions
  5. ' Version 1.00 by madscijr
  6. ' with help from various (sources cited below).
  7. ' ################################################################################################################################################################
  8.  
  9. ' =============================================================================
  10. ' GLOBAL DECLARATIONS
  11. ' =============================================================================
  12.  
  13. ' boolean constants
  14. Const FALSE = 0
  15. Const TRUE = Not FALSE
  16.  
  17. ' rotational constants
  18. Const cCounterClockwise = -1
  19. Const cClockwise = 1
  20.  
  21. ' -----------------------------------------------------------------------------
  22. ' USER DEFINED TYPES
  23. ' -----------------------------------------------------------------------------
  24. Type RotationType
  25.     origx As Integer
  26.     origy As Integer
  27.     c As Integer
  28.     z as integer ' which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  29. End Type ' RotationType
  30.  
  31. ' -----------------------------------------------------------------------------
  32. ' GLOBAL VARIABLES
  33. ' -----------------------------------------------------------------------------
  34. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  35. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  36. Dim Shared m_bDebug: m_bDebug = TRUE
  37.  
  38. ' =============================================================================
  39. ' BEGIN MAIN PROGRAM
  40. ' =============================================================================
  41. Dim in$
  42.  
  43. ' ****************************************************************************************************************************************************************
  44. ' ACTIVATE DEBUGGING WINDOW
  45. If m_bDebug = TRUE Then
  46.     $Console
  47.     _Delay 4
  48.     _Console On
  49.     _Echo "Started " + m_ProgramName$
  50.     _Echo "Debugging on..."
  51. ' ****************************************************************************************************************************************************************
  52.  
  53. ' -----------------------------------------------------------------------------
  54. ' START THE MENU
  55. main
  56.  
  57. ' -----------------------------------------------------------------------------
  58. ' DONE
  59. Print m_ProgramName$ + " finished."
  60. 'Screen 0
  61. Input "Press <ENTER> to continue", in$
  62.  
  63. ' ****************************************************************************************************************************************************************
  64. ' DEACTIVATE DEBUGGING WINDOW
  65. If m_bDebug = TRUE Then
  66. ' ****************************************************************************************************************************************************************
  67.  
  68. ' -----------------------------------------------------------------------------
  69. ' EXIT
  70. System ' return control to the operating system
  71.  
  72. ' =============================================================================
  73. ' END MAIN PROGRAM
  74. ' =============================================================================
  75.  
  76. ' /////////////////////////////////////////////////////////////////////////////
  77. ' MAIN MENU
  78.  
  79. Sub main
  80.     Dim RoutineName As String: RoutineName = "main"
  81.     Dim in$
  82.  
  83.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  84.     Do
  85.         Cls
  86.         Print m_ProgramName$
  87.         Print
  88.         Print "Some basic 2D plotting"
  89.         Print
  90.         Print " 1. PlotPointTest"
  91.         Print " 2. PlotSquareTest"
  92.         Print " 3. PlotCircleTest"
  93.                 Print " 4. PlotCircleTopLeftTest"
  94.         Print " 5. PlotSemicircleTest"
  95.         Print " 6. CircleFillTest"
  96.         Print " 7. CircleFillTopLeftTest"
  97.                 Print " 8. SemiCircleFillTest"
  98.                 Print " 9. EllipseTest"
  99.         Print "10. EllipseFillTest"
  100.         Print "11. PlotLineTest"
  101.         Print "12. ShearRotate1Test1"
  102.         Print "13. ShearRotate1Test2 (auto advances 0-360 degrees)"
  103.         Print "14. ShearRotate1Test2 (auto advances 0-360 degrees) (uses Petr's text)"
  104.         Print "15. ShearRotate2Test1 (correct for missing points logic v1)"
  105.         Print "16. ShearRotate2Test1 (correct for missing points logic v1) (uses Petr's text)"
  106.         Print "17. ShearRotate3Test1 (correct for missing points logic v2)"
  107.         Print "18. ShearRotate3Test1 (correct for missing points logic v2) (uses Petr's text)"
  108.         Print "19. ShearRotate4Test1 (correct for missing points logic v3)"
  109.         Print "20. ShearRotate4Test1 (correct for missing points logic v3) (uses Petr's text)"
  110.         Print
  111.         Print "What to do? ('q' to exit)"
  112.  
  113.         Input in$: in$ = LCase$(_Trim$(in$))
  114.        
  115.         If in$ = "1" Then
  116.             PlotPointTest
  117.         ElseIf in$ = "2" Then
  118.             PlotSquareTest
  119.         ElseIf in$ = "3" Then
  120.             PlotCircleTest
  121.         ElseIf in$ = "4" Then
  122.             PlotCircleTopLeftTest
  123.         ElseIf in$ = "5" Then
  124.             PlotSemicircleTest
  125.                 ElseIf in$ = "6" Then
  126.             CircleFillTest
  127.         ElseIf in$ = "7" Then
  128.             CircleFillTopLeftTest
  129.                 Elseif in$ = "8" then
  130.                         SemiCircleFillTest
  131.         ElseIf in$ = "9" Then
  132.             EllipseTest
  133.         ElseIf in$ = "10" Then
  134.             EllipseFillTest
  135.         ElseIf in$ = "11" Then
  136.             PlotLineTest
  137.         ElseIf in$ = "12" Then
  138.             ShearRotate1Test1
  139.         ElseIf in$ = "13" Then
  140.             ShearRotate1Test2 TestSprite1$
  141.         ElseIf in$ = "14" Then
  142.             ShearRotate1Test2 PetrText1$
  143.         ElseIf in$ = "15" Then
  144.             ShearRotate2Test1 TestSprite1$
  145.         ElseIf in$ = "16" Then
  146.             ShearRotate2Test1 PetrText1$
  147.         ElseIf in$ = "17" Then
  148.             ShearRotate3Test1 TestSprite1$
  149.         ElseIf in$ = "18" Then
  150.             ShearRotate3Test1 PetrText1$
  151.         ElseIf in$ = "19" Then
  152.             ShearRotate4Test1 TestSprite1$
  153.         ElseIf in$ = "20" Then
  154.             ShearRotate4Test1 PetrText1$
  155.         End If
  156.     Loop Until in$ = "q"
  157. End Sub ' main
  158.  
  159.  
  160.  
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169. ' /////////////////////////////////////////////////////////////////////////////
  170. ' MyArray(1 To 32, 1 To 32) AS STRING
  171. ' where index is MyArray(Y, X)
  172.  
  173. Sub PlotPoint (X As Integer, Y As Integer, S As String, MyArray() As String)
  174. _echo "PlotPoint X=" + cstr$(X) + ", Y=" + cstr$(Y) + ", S=" + chr$(34) + S + chr$(34) + ", MyArray()"
  175.     If (X >= LBound(MyArray, 2)) Then
  176.         If (X <= UBound(MyArray, 2)) Then
  177.             If (Y >= LBound(MyArray, 1)) Then
  178.                 If (Y <= UBound(MyArray, 1)) Then
  179.                     If Len(S) = 1 Then
  180.                         MyArray(Y, X) = S
  181.                     Else
  182.                         If Len(S) > 1 Then
  183.                             MyArray(Y, X) = Left$(S, 1)
  184.                         End If
  185.                     End If
  186.                 End If
  187.             End If
  188.         End If
  189.     End If
  190. End Sub ' PlotPoint
  191.  
  192. ' /////////////////////////////////////////////////////////////////////////////
  193.  
  194. Sub PlotPointTest
  195.     Dim MyArray(1 To 32, 1 To 32) As String
  196.     Dim iX As Integer
  197.     Dim iY As Integer
  198.     Dim in$
  199.     Dim X As Integer
  200.     Dim Y As Integer
  201.     Dim L As Integer
  202.     Dim iChar As Integer
  203.    
  204.     ClearArray MyArray(), "."
  205.     iChar = 64
  206.    
  207.     Cls
  208.     Print "Plot a point."
  209.     Print ArrayToStringTest(MyArray())
  210.     Print
  211.    
  212.     Do
  213.         Print "Type x,y (1-32, 1-32) coordinate to plot point at."
  214.         Input "X,Y OR 0 TO QUIT? "; X, Y
  215.         If X > 0 And Y > 0 Then
  216.             iChar = iChar + 1
  217.             If iChar > 90 Then iChar = 65
  218.            
  219.             Print "X=" + cstr$(X) + ", Y=" + cstr$(Y)
  220.             PlotPoint X, Y, chr$(iChar), MyArray()
  221.  
  222.             Print "Current point plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  223.             Print ArrayToStringTest(MyArray())
  224.             Print
  225.            
  226.         Else
  227.             Exit Do
  228.         End If
  229.     Loop
  230. End Sub ' PlotPointTest
  231.  
  232. ' /////////////////////////////////////////////////////////////////////////////
  233.  
  234. Sub PlotSquare (X1 As Integer, Y1 As Integer, L As Integer, S As String, MyArray() As String)
  235.     Dim X As Integer
  236.     Dim X2 As Integer
  237.     Dim Y As Integer
  238.     Dim Y2 As Integer
  239.     Dim sChar$
  240.  
  241.     If Len(S) = 1 Then
  242.         sChar$ = S
  243.     Else
  244.         If Len(S) = 0 Then
  245.             sChar$ = " "
  246.         Else
  247.             sChar$ = Left$(S, 1)
  248.         End If
  249.     End If
  250.  
  251.     X2 = (X1 + L) - 1
  252.     Y2 = (Y1 + L) - 1
  253.     For X = X1 To X2
  254.         For Y = Y1 To Y2
  255.             PlotPoint X, Y, sChar$, MyArray()
  256.         Next Y
  257.     Next X
  258. End Sub ' PlotSquare
  259.  
  260. ' /////////////////////////////////////////////////////////////////////////////
  261.  
  262. Sub PlotSquareTest
  263.     Dim MyArray(1 To 32, 1 To 32) As String
  264.     Dim iX As Integer
  265.     Dim iY As Integer
  266.     Dim in$
  267.     Dim X As Integer
  268.     Dim Y As Integer
  269.     Dim L As Integer
  270.     Dim iChar As Integer
  271.    
  272.     ClearArray MyArray(), "."
  273.     iChar = 64
  274.    
  275.     Cls
  276.     Print "Enter parameters to draw a square."
  277.     Print ArrayToStringTest(MyArray())
  278.     Print
  279.     Do
  280.         Print "Type top left x,y (1-32, 1-32) coordinate to plot square,"
  281.         Print "and size (1-32) of square."
  282.         Input "X,Y,L OR 0 TO QUIT? "; X, Y, L
  283.         If X>0 AND Y>0 AND L > 0 Then
  284.             iChar = iChar + 1
  285.             If iChar > 90 Then iChar = 65
  286.            
  287.             Print
  288.             Print "X=" + cstr$(X)
  289.             Print "Y=" + cstr$(Y)
  290.             Print "L=" + cstr$(L)
  291.             Print
  292.             PlotSquare X, Y, L, chr$(iChar), MyArray()
  293.            
  294.             Print "Square plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  295.             Print ArrayToStringTest(MyArray())
  296.             Print
  297.         Else
  298.             Exit Do
  299.         End If
  300.     Loop
  301. End Sub ' PlotSquareTest
  302.  
  303. ' /////////////////////////////////////////////////////////////////////////////
  304. ' Fast circle drawing in pure Atari BASIC#
  305. ' https://atariwiki.org/wiki/Wiki.jsp?page=Super%20fast%20circle%20routine
  306.  
  307. ' * Magazine: Moj Mikro, 1989/3
  308. ' * Author : Zlatko Bleha
  309. ' * Page : 27 - 31
  310. ' * Atari BASIC listing on disk (tokenized): M8903282.BAS
  311. ' * Atari BASIC listing (listed): M8903282.LST
  312.  
  313. ' Next example is demonstration of implementing mentioned circle algorithm
  314. ' in pure Atari BASIC. This program shows how much faster it is compared to
  315. ' classic program using sine and cosine functions from Atari BASIC
  316. ' (shown in last example).
  317.  
  318. ' Basic Listing M8903282.LST#
  319. '1 REM *******************************
  320. '2 REM PROGRAM  : FAST CIRCLE DRAWING
  321. '3 REM AUTHOR   : ZLATKO BLEHA
  322. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  323. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  324. '6 REM *******************************
  325. '7 REM
  326. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  327. '20 PRINT "ENTER X, Y AND R"
  328. '30 INPUT X,Y,R
  329. '40 IF R=0 THEN PLOT X,Y:END
  330. '50 B=R:C=0:A=R-1
  331. '60 PLOT X+C,Y+B
  332. '70 PLOT X+C,Y-B
  333. '80 PLOT X-C,Y-B
  334. '90 PLOT X-C,Y+B
  335. '100 PLOT X+B,Y+C
  336. '110 PLOT X+B,Y-C
  337. '120 PLOT X-B,Y-C
  338. '130 PLOT X-B,Y+C
  339. '140 C=C+1
  340. '150 A=A+1-C-C
  341. '160 IF A>=0 THEN 190
  342. '170 B=B-1
  343. '180 A=A+B+B
  344. '190 IF B>=C THEN 60
  345.  
  346. ' Use some valid values for coordinates and radius, for example:
  347. ' X=40, Y=40, R=30
  348. ' X=130, Y=90, R=60
  349. ' Slow circle drawing in Atari BASIC#
  350. ' * Magazine: Moj Mikro, 1989/3
  351. ' * Author : Zlatko Bleha
  352. ' * Page : 27 - 31
  353. ' * Atari BASIC listing on disk (tokenized): M8903281.BAS
  354. ' * Atari BASIC listing (listed): M8903281.LST
  355.  
  356. ' This is classic example for drawing circles from Atari BASIC
  357. ' using sine and cosine functions. Unfortunatelly, this is very slow
  358. ' way of doing it and not recommended.
  359. ' Just use routine shown above and everybody will be happy
  360.  
  361. ' Basic Listing M8903281.LST#
  362. '1 REM *******************************
  363. '2 REM PROGRAM  : SLOW CIRCLE DRAWING
  364. '3 REM AUTHOR   : ZLATKO BLEHA
  365. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  366. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  367. '6 REM *******************************
  368. '7 REM
  369. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  370. '20 FOR A=0 TO 6.28 STEP 0.02
  371. '30 X=SIN(A)*50+150
  372. '40 Y=COS(A)*50+80
  373. '50 PLOT X,Y
  374. '60 NEXT A
  375.  
  376. ' Conclusion#
  377. ' Returning back to first program with the fastest way of drawing circles...
  378. ' There is one more thing to note. In case you want to use PLOT subroutine,
  379. ' which is part of the main circle routine, then read following explanation.
  380. ' PLOT routine is written so it can be used easily from Atari BASIC program
  381. ' independently from main circle routine, by using like this:
  382. ' A=USR(30179,POK,X,Y)
  383. '
  384. ' POK   1 (drawing a pixel), 0 (erasing a pixel)
  385. ' X     X coordinate of the pixel
  386. ' Y     Y coordinate of the pixel
  387. '
  388. ' The routine alone is not any faster than normal PLOT command
  389. ' from Atari BASIC, because USR command takes approximately 75%
  390. ' of whole execution. But, used as part of the main circle routine
  391. ' it does not matter anymore, because it is integrated in one larger
  392. ' entity. There the execution is very fast, with no overhead.
  393. ' PLOT routine is here for you to examine anyway.
  394. ' You never know if you will maybe need it in the future.
  395.  
  396. ' More on plotting circles:
  397. '     Drawing a circle in BASIC - fast
  398. '     https://www.cpcwiki.eu/forum/programming/drawing-a-circle-in-basic-fast/
  399.  
  400. ' X,Y     = center point of circle
  401. ' R       = radius
  402. ' S       = char to draw
  403. ' MyArray = 2D string array to plot circle in
  404.  
  405. Sub PlotCircle (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  406.     Dim A As Integer
  407.     Dim B As Integer
  408.     Dim C As Integer
  409.     Dim S2 As String
  410.  
  411.     If Len(S) = 1 Then
  412.         S2 = S
  413.     Else
  414.         If Len(S) = 0 Then
  415.             S2 = " "
  416.         Else
  417.             S2 = Left$(S, 1)
  418.         End If
  419.     End If
  420.  
  421.     If R > 0 Then
  422.         B = R
  423.         C = 0
  424.         A = R - 1
  425.         Do
  426.             PlotPoint X + C, Y + B, S2, MyArray()
  427.             PlotPoint X + C, Y - B, S2, MyArray()
  428.             PlotPoint X - C, Y - B, S2, MyArray()
  429.             PlotPoint X - C, Y + B, S2, MyArray()
  430.             PlotPoint X + B, Y + C, S2, MyArray()
  431.             PlotPoint X + B, Y - C, S2, MyArray()
  432.             PlotPoint X - B, Y - C, S2, MyArray()
  433.             PlotPoint X - B, Y + C, S2, MyArray()
  434.             C = C + 1
  435.             A = A + 1 - C - C
  436.             If A < 0 Then ' IF A>=0 THEN 190
  437.                 B = B - 1
  438.                 A = A + B + B
  439.             End If
  440.             If B < C Then Exit Do ' 190 IF B>=C THEN 60
  441.         Loop
  442.     End If
  443. End Sub ' PlotCircle
  444.  
  445. ' /////////////////////////////////////////////////////////////////////////////
  446.  
  447. Sub PlotCircleTest
  448.     Dim MyArray(1 To 32, 1 To 32) As String
  449.     Dim iX As Integer
  450.     Dim iY As Integer
  451.     Dim in$
  452.     Dim X As Integer
  453.     Dim Y As Integer
  454.     Dim R As Integer
  455.     Dim iChar As Integer
  456.    
  457.     ClearArray MyArray(), "."
  458.     iChar = 64
  459.    
  460.     Cls
  461.     Print "Plot a raster circle"
  462.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  463.     Print
  464.     Print "Enter parameters to draw a circle."
  465.     Print ArrayToStringTest(MyArray())
  466.     Print
  467.    
  468.     Do
  469.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  470.         Print "and radius (1-32) of circle."
  471.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  472.         If X > 0 AND Y > 0 AND R > 0 Then
  473.             iChar = iChar + 1
  474.             If iChar > 90 Then iChar = 65
  475.            
  476.             Print "X=" + cstr$(X)
  477.             Print "Y=" + cstr$(Y)
  478.             Print "R=" + cstr$(R)
  479.            
  480.             PlotCircle X, Y, R, Chr$(iChar), MyArray()
  481.            
  482.             Print "Circle plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  483.             Print ArrayToStringTest(MyArray())
  484.             Print
  485.         Else
  486.             Exit Do
  487.         End If
  488.     Loop
  489.    
  490. End Sub ' PlotCircleTest
  491.  
  492. ' /////////////////////////////////////////////////////////////////////////////
  493. ' X,Y     = top left point of circle
  494. ' R       = radius
  495. ' S       = char to draw
  496. ' MyArray = 2D string array to plot circle in
  497.  
  498. Sub PlotCircleTopLeft (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  499.     Dim RoutineName As String : RoutineName = "PlotCircleTopLeft"
  500.     Dim A As Integer
  501.     Dim B As Integer
  502.     Dim C As Integer
  503.     Dim S2 As String
  504.     Dim W As Integer
  505.     ReDim arrTemp(0, 0) As String
  506.     Dim DY As Integer
  507.     Dim DX As Integer
  508.         DIM TX As Integer
  509.         DIM TY As Integer
  510.         Dim MinY As Integer
  511.         Dim MaxY As Integer
  512.         Dim MinX As Integer
  513.         Dim MaxX As Integer
  514.    
  515.     ' Get total width
  516.     W = (R * 2) + 1
  517.    
  518.     ' Define a temp array
  519.     ReDim arrTemp(0 To W, 0 To W) As String
  520.    
  521.         ' Get minimum X, Y of target array
  522.         MinY = lbound(MyArray, 1)
  523.         MaxY = ubound(MyArray, 1)
  524.         MinX = lbound(MyArray, 2)
  525.         MaxX = ubound(MyArray, 2)
  526.        
  527.     If Len(S) = 1 Then
  528.         S2 = S
  529.     Else
  530.         If Len(S) = 0 Then
  531.             S2 = " "
  532.         Else
  533.             S2 = Left$(S, 1)
  534.         End If
  535.     End If
  536.    
  537.     If R > 0 Then
  538.         ' Draw circle to temporary array
  539.         B = R
  540.         C = 0
  541.         A = R - 1
  542.         Do
  543.             ' PORTIONS OF CIRCLE:
  544.             ' .......3333222.......
  545.             ' .....33.......22.....
  546.             ' ....3...........2....
  547.             ' ...7.............6...
  548.             ' ..7...............6..
  549.             ' .7.................6.
  550.             ' .7.................6.
  551.             ' 7...................6
  552.             ' 7...................6
  553.             ' 7...................6
  554.             ' 8...................6
  555.             ' 8...................5
  556.             ' 8...................5
  557.             ' 8...................5
  558.             ' .8.................5.
  559.             ' .8.................5.
  560.             ' ..8...............5..
  561.             ' ...8.............5...
  562.             ' ....4...........1....
  563.             ' .....44.......11.....
  564.             ' .......4444111.......
  565.             PlotPoint R + C, R + B, S2, arrTemp() ' 1
  566.             PlotPoint R + C, R - B, S2, arrTemp() ' 2
  567.             PlotPoint R - C, R - B, S2, arrTemp() ' 3
  568.             PlotPoint R - C, R + B, S2, arrTemp() ' 4
  569.             PlotPoint R + B, R + C, S2, arrTemp() ' 5
  570.             PlotPoint R + B, R - C, S2, arrTemp() ' 6
  571.             PlotPoint R - B, R - C, S2, arrTemp() ' 7
  572.             PlotPoint R - B, R + C, S2, arrTemp() ' 8
  573.             C = C + 1
  574.             A = A + 1 - C - C
  575.             If A < 0 Then
  576.                 B = B - 1
  577.                 A = A + B + B
  578.             End If
  579.             If B < C Then Exit Do
  580.         Loop
  581.        
  582.         ' Copy circle to destination Y,X
  583.         For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  584.             For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  585.                 IF LEN(arrTemp(DY, DX)) > 0 THEN
  586.                                         TY = Y + DY
  587.                                         If TY >= MinY Then
  588.                                                 If TY <= MaxY Then
  589.                                                         TX = X + DX
  590.                                                         If TX >= MinX Then
  591.                                                                 If TX <= MaxX Then
  592.                                                                         MyArray(TY, TX) = arrTemp(DY, DX)
  593.                                                                 End If
  594.                                                         End If
  595.                                                 End If
  596.                                         End If
  597.                                        
  598.                 END IF
  599.             Next DX
  600.         Next DY
  601.     End If
  602. End Sub ' PlotCircleTopLeft
  603.  
  604. ' /////////////////////////////////////////////////////////////////////////////
  605.  
  606. Sub PlotCircleTopLeftTest
  607.     Dim MyArray(1 To 32, 1 To 32) As String
  608.     Dim iX As Integer
  609.     Dim iY As Integer
  610.     Dim in$
  611.     Dim X As Integer
  612.     Dim Y As Integer
  613.     Dim R As Integer
  614.     Dim iChar As Integer
  615.    
  616.     ClearArray MyArray(), "."
  617.     iChar = 64
  618.    
  619.     Cls
  620.     Print "Plot a raster circle, specifying top left x,y position"
  621.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  622.     Print
  623.     Print "Enter parameters to draw a circle."
  624.     Print ArrayToStringTest(MyArray())
  625.     Print
  626.    
  627.     Do
  628.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot circle,"
  629.         Print "and radius (1-32) of circle."
  630.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  631.         If X > 0 AND Y > 0 AND R > 0 Then
  632.             iChar = iChar + 1
  633.             If iChar > 90 Then iChar = 65
  634.            
  635.             Print "X=" + cstr$(X)
  636.             Print "Y=" + cstr$(Y)
  637.             Print "R=" + cstr$(R)
  638.            
  639.             PlotCircleTopLeft X, Y, R, Chr$(iChar), MyArray()
  640.            
  641.             Print "Circle plotted (from top left), drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  642.             Print ArrayToStringTest(MyArray())
  643.             Print
  644.         Else
  645.             Exit Do
  646.         End If
  647.     Loop
  648.    
  649. End Sub ' PlotCircleTopLeftTest
  650.  
  651. ' /////////////////////////////////////////////////////////////////////////////
  652. ' Based on PlotCircleTopLeft.
  653.  
  654. ' X,Y     = top left point of circle
  655. ' R       = radius
  656. ' Q       = which quarter of the circle to return
  657. '           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
  658. '           like this:
  659.             ' .......4444111.......
  660.             ' .....44.......11.....
  661.             ' ....4...........1....
  662.             ' ...4.............1...
  663.             ' ..4...............1..
  664.             ' .4.................1.
  665.             ' .4.................1.
  666.             ' 4...................1
  667.             ' 4...................1
  668.             ' 4...................1
  669.             ' 3...................1
  670.             ' 3...................2
  671.             ' 3...................2
  672.             ' 3...................2
  673.             ' .3.................2.
  674.             ' .3.................2.
  675.             ' ..3...............2..
  676.             ' ...3.............2...
  677.             ' ....3...........2....
  678.             ' .....33.......22.....
  679.             ' .......3333222.......
  680. ' S       = char to draw
  681. ' MyArray = 2D string array to plot circle in
  682.  
  683. Sub PlotSemicircle (X As Integer, Y As Integer, R As Integer, Q As Integer, S As String, MyArray() As String)
  684.     Dim RoutineName As String : RoutineName = "PlotCircleTopLeft"
  685.     Dim A As Integer
  686.     Dim B As Integer
  687.     Dim C As Integer
  688.     Dim S2 As String
  689.     Dim W As Integer
  690.     ReDim arrTemp(0, 0) As String
  691.     Dim DY As Integer
  692.     Dim DX As Integer
  693.         DIM TX As Integer
  694.         DIM TY As Integer
  695.         Dim MinY As Integer
  696.         Dim MaxY As Integer
  697.         Dim MinX As Integer
  698.         Dim MaxX As Integer
  699.    
  700.     ' Get total width
  701.     W = (R * 2) + 1
  702.    
  703.     ' Define a temp array
  704.     ReDim arrTemp(0 To W, 0 To W) As String
  705.    
  706.         ' Get minimum X, Y of target array
  707.         MinY = lbound(MyArray, 1)
  708.         MaxY = ubound(MyArray, 1)
  709.         MinX = lbound(MyArray, 2)
  710.         MaxX = ubound(MyArray, 2)
  711.        
  712.     If Len(S) = 1 Then
  713.         S2 = S
  714.     Else
  715.         If Len(S) = 0 Then
  716.             S2 = " "
  717.         Else
  718.             S2 = Left$(S, 1)
  719.         End If
  720.     End If
  721.    
  722.     If R > 0 Then
  723.         ' Draw circle to temporary array
  724.         B = R
  725.         C = 0
  726.         A = R - 1
  727.         Do
  728.             ' PORTIONS OF CIRCLE:
  729.             ' .......3333222.......
  730.             ' .....33.......22.....
  731.             ' ....3...........2....
  732.             ' ...7.............6...
  733.             ' ..7...............6..
  734.             ' .7.................6.
  735.             ' .7.................6.
  736.             ' 7...................6
  737.             ' 7...................6
  738.             ' 7...................6
  739.             ' 8...................6
  740.             ' 8...................5
  741.             ' 8...................5
  742.             ' 8...................5
  743.             ' .8.................5.
  744.             ' .8.................5.
  745.             ' ..8...............5..
  746.             ' ...8.............5...
  747.             ' ....4...........1....
  748.             ' .....44.......11.....
  749.             ' .......4444111.......
  750.            
  751.             ' JUST PLOT SELECTED QUADRANT:
  752.             Select Case Q
  753.                 Case 1:
  754.                     ' quadrant #1
  755.                     PlotPoint C, R - B, S2, arrTemp() ' 2
  756.                     PlotPoint B, R - C, S2, arrTemp() ' 6
  757.                 Case 2:
  758.                     ' quadrant #2
  759.                     PlotPoint B, C, S2, arrTemp() ' 5
  760.                     PlotPoint C, B, S2, arrTemp() ' 1
  761.                 Case 3:
  762.                     ' quadrant #3
  763.                     PlotPoint R - C, B, S2, arrTemp() ' 4
  764.                     PlotPoint R - B, C, S2, arrTemp() ' 8
  765.                 Case 4:
  766.                     ' quadrant #4
  767.                     PlotPoint R - B, R - C, S2, arrTemp() ' 7
  768.                     PlotPoint R - C, R - B, S2, arrTemp() ' 3
  769.                 Case Else:
  770.                     ' (DO NOTHING)
  771.             End Select
  772.            
  773.             '' PLOT CIRCLE:
  774.             '' quadrant #1
  775.             'PlotPoint R + C, R - B, S2, arrTemp() ' 2
  776.             'PlotPoint R + B, R - C, S2, arrTemp() ' 6
  777.             '
  778.             '' quadrant #2
  779.             'PlotPoint R + B, R + C, S2, arrTemp() ' 5
  780.             'PlotPoint R + C, R + B, S2, arrTemp() ' 1
  781.             '
  782.             '' quadrant #3
  783.             'PlotPoint R - C, R + B, S2, arrTemp() ' 4
  784.             'PlotPoint R - B, R + C, S2, arrTemp() ' 8
  785.             '
  786.             '' quadrant #4
  787.             'PlotPoint R - B, R - C, S2, arrTemp() ' 7
  788.             'PlotPoint R - C, R - B, S2, arrTemp() ' 3
  789.            
  790.             C = C + 1
  791.             A = A + 1 - C - C
  792.             If A < 0 Then
  793.                 B = B - 1
  794.                 A = A + B + B
  795.             End If
  796.             If B < C Then Exit Do
  797.         Loop
  798.        
  799.         ' Copy semicircle to destination Y,X
  800.         For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  801.             For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  802.                 IF LEN(arrTemp(DY, DX)) > 0 THEN
  803.                                         TY = Y + DY
  804.                                         If TY >= MinY Then
  805.                                                 If TY <= MaxY Then
  806.                                                         TX = X + DX
  807.                                                         If TX >= MinX Then
  808.                                                                 If TX <= MaxX Then
  809.                                                                         MyArray(TY, TX) = arrTemp(DY, DX)
  810.                                                                 End If
  811.                                                         End If
  812.                                                 End If
  813.                                         End If
  814.                 END IF
  815.             Next DX
  816.         Next DY
  817.     End If
  818. End Sub ' PlotSemicircle
  819.  
  820. ' /////////////////////////////////////////////////////////////////////////////
  821.  
  822. Sub PlotSemicircleTest
  823.     Dim MyArray(1 To 32, 1 To 32) As String
  824.     Dim iX As Integer
  825.     Dim iY As Integer
  826.     Dim in$
  827.     Dim X As Integer
  828.     Dim Y As Integer
  829.     Dim R As Integer
  830.     Dim Q As Integer
  831.     Dim iChar As Integer
  832.    
  833.     ClearArray MyArray(), "."
  834.     iChar = 64
  835.    
  836.     Cls
  837.     Print "Plot a semicircle"
  838.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  839.     Print
  840.     Print "Enter parameters to draw a semicircle."
  841.     Print ArrayToStringTest(MyArray())
  842.     Print
  843.    
  844.     Do
  845.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot semicircle,"
  846.         Print "radius (1-32) of semicircle, and quadrant of circle to use:"
  847.         Print "41"
  848.         Print "32"
  849.         Input "X,Y,R,Q OR 0 TO QUIT: "; X, Y, R, Q
  850.         If X > 0 AND Y > 0 AND R > 0 Then
  851.             iChar = iChar + 1
  852.             If iChar > 90 Then iChar = 65
  853.            
  854.             Print "X=" + cstr$(X)
  855.             Print "Y=" + cstr$(Y)
  856.             Print "R=" + cstr$(R)
  857.            
  858.             PlotSemicircle X, Y, R, Q, Chr$(iChar), MyArray()
  859.            
  860.             Print "Semicircle plotted (from top left), drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  861.             Print ArrayToStringTest(MyArray())
  862.             Print
  863.         Else
  864.             Exit Do
  865.         End If
  866.     Loop
  867.    
  868. End Sub ' PlotSemicircleTest
  869.  
  870. ' /////////////////////////////////////////////////////////////////////////////
  871. ' Re: Is this fast enough as general circle fill?
  872. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg1913#msg1913
  873.  
  874. ' From: SMcNeill
  875. ' Date: « Reply #30 on: June 26, 2018, 03:34:18 pm »
  876. '
  877. ' Sometimes, computers do things that are completely counter-intuitive to us, and
  878. ' we find ourselves having to step back as programmers and simply say, "WOW!!"  
  879. ' Here's a perfect example of that:
  880. ' Here we look at two different circle fill routines -- one, which I'd assume to
  881. ' be faster, which precalculates the offset needed to find the endpoints for each
  882. ' line which composes a circle, and another, which is the same old CircleFill
  883. ' program which I've shared countless times over the years with people on various
  884. ' QB64 forums.
  885. '
  886. ' When all is said and done though, CircleFill is STILL even faster than
  887. ' CircleFillFast, which pregenerates those end-points for us!
  888.  
  889. ' CX,CY     = center point of circle
  890. ' R         = radius
  891. ' S         = char to draw
  892. ' MyArray = 2D string array to plot circle in
  893.  
  894. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, S As String, MyArray() As String)
  895.     DIM Radius AS INTEGER
  896.     Dim RadiusError AS INTEGER
  897.     DIM X AS INTEGER
  898.     Dim Y AS INTEGER
  899.     Dim iLoopX as INTEGER
  900.     Dim iLoopY as INTEGER
  901.    
  902.     Radius = ABS(R)
  903.     RadiusError = -Radius
  904.     X = Radius
  905.     Y = 0
  906.    
  907.     IF Radius = 0 THEN
  908.         'PSET (CX, CY), C
  909.         'PlotPoint CX, CY, S, MyArray()
  910.         EXIT SUB
  911.     END IF
  912.    
  913.     ' Draw the middle span here so we don't draw it twice in the main loop,
  914.     ' which would be a problem with blending turned on.
  915.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  916.     FOR iLoopX = CX - X TO CX + X
  917.         PlotPoint iLoopX, CY, S, MyArray()
  918.     NEXT iLoopX
  919.    
  920.     WHILE X > Y
  921.         RadiusError = RadiusError + Y * 2 + 1
  922.         IF RadiusError >= 0 THEN
  923.             IF X <> Y + 1 THEN
  924.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  925.                 iLoopY = CY - X
  926.                 FOR iLoopX = CX - Y TO CX + Y
  927.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  928.                 NEXT iLoopX
  929.                
  930.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  931.                 iLoopY = CY + X
  932.                 FOR iLoopX = CX - Y TO CX + Y
  933.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  934.                 NEXT iLoopX
  935.             END IF
  936.             X = X - 1
  937.             RadiusError = RadiusError - X * 2
  938.         END IF
  939.         Y = Y + 1
  940.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  941.         iLoopY = CY - Y
  942.         FOR iLoopX = CX - X TO CX + X
  943.             PlotPoint iLoopX, iLoopY, S, MyArray()
  944.         NEXT iLoopX
  945.        
  946.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  947.         iLoopY = CY + Y
  948.         FOR iLoopX = CX - X TO CX + X
  949.             PlotPoint iLoopX, iLoopY, S, MyArray()
  950.         NEXT iLoopX
  951.     WEND
  952. END SUB ' CircleFill
  953.  
  954. ' /////////////////////////////////////////////////////////////////////////////
  955.  
  956. Sub CircleFillTest
  957.     Dim MyArray(1 To 32, 1 To 32) As String
  958.     Dim iX As Integer
  959.     Dim iY As Integer
  960.     Dim in$
  961.     Dim X As Integer
  962.     Dim Y As Integer
  963.     Dim R As Integer
  964.     Dim iChar As Integer
  965.    
  966.     ClearArray MyArray(), "."
  967.     iChar = 64
  968.    
  969.     Cls
  970.     Print "Plot a filled circle"
  971.     Print "Based on CircleFill by SMcNeill."
  972.     Print
  973.     Print "Enter parameters to draw a circle."
  974.     Print ArrayToStringTest(MyArray())
  975.     Print
  976.    
  977.     Do
  978.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  979.         Print "and radius (1-32) of circle."
  980.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  981.         If X > 0 AND Y > 0 AND R > 0 Then
  982.             iChar = iChar + 1
  983.             If iChar > 90 Then iChar = 65
  984.            
  985.             Print "X=" + cstr$(X)
  986.             Print "Y=" + cstr$(Y)
  987.             Print "R=" + cstr$(R)
  988.            
  989.             'PlotCircle X, Y, R, Chr$(iChar), MyArray()
  990.             CircleFill X, Y, R, Chr$(iChar), MyArray()
  991.            
  992.             Print "Circle plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  993.             Print ArrayToStringTest(MyArray())
  994.             Print
  995.         Else
  996.             Exit Do
  997.         End If
  998.     Loop
  999.    
  1000. End Sub ' CircleFillTest
  1001.  
  1002. ' /////////////////////////////////////////////////////////////////////////////
  1003. ' Based on CircleFill and PlotCircleTopLeft.
  1004. ' CX,CY     = top left point of circle
  1005. ' R         = radius
  1006. ' S         = char to draw
  1007. ' MyArray = 2D string array to plot circle in
  1008.  
  1009. SUB CircleFillTopLeft (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, S As String, MyArray() As String)
  1010.     DIM Radius AS INTEGER
  1011.     Dim RadiusError AS INTEGER
  1012.     DIM X AS INTEGER
  1013.     Dim Y AS INTEGER
  1014.     Dim iLoopX as INTEGER
  1015.     Dim iLoopY as INTEGER
  1016.     ReDim arrTemp(0, 0) As String
  1017.     Dim DY As Integer
  1018.     Dim DX As Integer
  1019.     DIM W As Integer
  1020.         DIM TX As Integer
  1021.         DIM TY As Integer
  1022.         Dim MinY As Integer
  1023.         Dim MaxY As Integer
  1024.         Dim MinX As Integer
  1025.         Dim MaxX As Integer
  1026.    
  1027.     Radius = ABS(R)
  1028.     RadiusError = -Radius
  1029.     X = Radius
  1030.     Y = 0
  1031.    
  1032.     IF Radius = 0 THEN
  1033.         'PSET (CX, CY), C
  1034.         'PlotPoint CX, CY, S, MyArray()
  1035.         EXIT SUB
  1036.     END IF
  1037.    
  1038.     ' Get total width
  1039.     W = (Radius * 2) + 1
  1040.    
  1041.     ' Define a temp array
  1042.     ReDim arrTemp(0 To W, 0 To W) As String
  1043.    
  1044.         ' Get minimum X, Y of target array
  1045.         MinY = lbound(MyArray, 1)
  1046.         MaxY = ubound(MyArray, 1)
  1047.         MinX = lbound(MyArray, 2)
  1048.         MaxX = ubound(MyArray, 2)
  1049.        
  1050.     ' Draw the middle span here so we don't draw it twice in the main loop,
  1051.     ' which would be a problem with blending turned on.
  1052.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  1053.     'FOR iLoopX = CX - X TO CX + X
  1054.     FOR iLoopX = R - X TO R + X
  1055.         'PlotPoint iLoopX, CY, S, MyArray()
  1056.         'PlotPoint iLoopX, CY, S, arrTemp()
  1057.         PlotPoint iLoopX, R, S, arrTemp()
  1058.     NEXT iLoopX
  1059.    
  1060.     WHILE X > Y
  1061.         RadiusError = RadiusError + Y * 2 + 1
  1062.         IF RadiusError >= 0 THEN
  1063.             IF X <> Y + 1 THEN
  1064.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1065.                 'iLoopY = CY - X
  1066.                 iLoopY = R - X
  1067.                 'FOR iLoopX = CX - Y TO CX + Y
  1068.                 FOR iLoopX = R - Y TO R + Y
  1069.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1070.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1071.                 NEXT iLoopX
  1072.                
  1073.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1074.                 'iLoopY = CY + X
  1075.                 iLoopY = R + X
  1076.                 'FOR iLoopX = CX - Y TO CX + Y
  1077.                 FOR iLoopX = R - Y TO R + Y
  1078.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1079.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1080.                 NEXT iLoopX
  1081.             END IF
  1082.             X = X - 1
  1083.             RadiusError = RadiusError - X * 2
  1084.         END IF
  1085.         Y = Y + 1
  1086.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1087.         'iLoopY = CY - Y
  1088.         iLoopY = R - Y
  1089.         'FOR iLoopX = CX - X TO CX + X
  1090.         FOR iLoopX = R - X TO R + X
  1091.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1092.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1093.         NEXT iLoopX
  1094.        
  1095.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1096.         'iLoopY = CY + Y
  1097.         iLoopY = R + Y
  1098.         'FOR iLoopX = CX - X TO CX + X
  1099.         FOR iLoopX = R - X TO R + X
  1100.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1101.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1102.         NEXT iLoopX
  1103.     WEND
  1104.    
  1105.     ' Copy circle to destination Y,X
  1106.     For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  1107.         For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  1108.             IF LEN(arrTemp(DY, DX)) > 0 THEN
  1109.                 TY = DY + CY
  1110.                                 If TY >= MinY Then
  1111.                                         If TY <= MaxY Then
  1112.                                                 TX = DX + CX
  1113.                                                 If TX >= MinX Then
  1114.                                                         If TX <= MaxX Then
  1115.                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1116.                                                         End If
  1117.                                                 End If
  1118.                                         End If
  1119.                                 End If
  1120.             END IF
  1121.         Next DX
  1122.     Next DY
  1123.    
  1124. END SUB ' CircleFillTopLeft
  1125.  
  1126. ' /////////////////////////////////////////////////////////////////////////////
  1127.  
  1128. Sub CircleFillTopLeftTest
  1129.     Dim MyArray(1 To 32, 1 To 32) As String
  1130.     Dim iX As Integer
  1131.     Dim iY As Integer
  1132.     Dim in$
  1133.     Dim X As Integer
  1134.     Dim Y As Integer
  1135.     Dim R As Integer
  1136.     Dim iChar As Integer
  1137.    
  1138.     ClearArray MyArray(), "."
  1139.     iChar = 64
  1140.    
  1141.     Cls
  1142.     Print "Plot a solid circle, specifying top left x,y position"
  1143.     Print "Based on CircleFill by SMcNeill."
  1144.     Print
  1145.     Print "Enter parameters to draw a circle."
  1146.     Print ArrayToStringTest(MyArray())
  1147.     Print
  1148.    
  1149.     Do
  1150.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot circle,"
  1151.         Print "and radius (1-32) of circle."
  1152.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  1153.         If X > 0 AND Y > 0 AND R > 0 Then
  1154.             iChar = iChar + 1
  1155.             If iChar > 90 Then iChar = 65
  1156.            
  1157.             Print "X=" + cstr$(X)
  1158.             Print "Y=" + cstr$(Y)
  1159.             Print "R=" + cstr$(R)
  1160.            
  1161.             CircleFillTopLeft X, Y, R, Chr$(iChar), MyArray()
  1162.            
  1163.             Print "Circle plotted (from top left), drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1164.             Print ArrayToStringTest(MyArray())
  1165.             Print
  1166.         Else
  1167.             Exit Do
  1168.         End If
  1169.     Loop
  1170.    
  1171. End Sub ' CircleFillTopLeftTest
  1172.  
  1173. ' /////////////////////////////////////////////////////////////////////////////
  1174. ' Based on CircleFill and PlotSemiCircle
  1175.  
  1176. ' CX,CY   = top left point of circle
  1177. ' R       = radius
  1178. ' Q       = which quarter of the circle to return semicircle from
  1179. '           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
  1180. '           like this:
  1181.             ' .......4444111.......
  1182.             ' .....44444411111.....
  1183.             ' ....4444444111111....
  1184.             ' ...444444441111111...
  1185.             ' ..44444444411111111..
  1186.             ' .4444444444111111111.
  1187.             ' .4444444444111111111.
  1188.             ' 444444444441111111111
  1189.             ' 444444444441111111111
  1190.             ' 444444444441111111111
  1191.             ' 333333333331111111111
  1192.             ' 333333333332222222222
  1193.             ' 333333333332222222222
  1194.             ' 333333333332222222222
  1195.             ' .3333333333222222222.
  1196.             ' .3333333333222222222.
  1197.             ' ..33333333322222222..
  1198.             ' ...333333332222222...
  1199.             ' ....3333333222222....
  1200.             ' .....33333322222.....
  1201.             ' .......3333222.......
  1202. ' S       = char to draw
  1203. ' MyArray = 2D string array to plot semicircle in
  1204.  
  1205. SUB SemiCircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, Q AS INTEGER, S As String, MyArray() As String)
  1206.     DIM Radius AS INTEGER
  1207.     Dim RadiusError AS INTEGER
  1208.     DIM X AS INTEGER
  1209.     Dim Y AS INTEGER
  1210.     Dim iLoopX as INTEGER
  1211.     Dim iLoopY as INTEGER
  1212.     ReDim arrTemp(0, 0) As String
  1213.     Dim DY As Integer
  1214.     Dim DX As Integer
  1215.     DIM W As Integer
  1216.     DIM AX As Integer
  1217.         DIM AY As Integer
  1218.         DIM TX As Integer
  1219.         DIM TY As Integer
  1220.         Dim MinY As Integer
  1221.         Dim MaxY As Integer
  1222.         Dim MinX As Integer
  1223.         Dim MaxX As Integer
  1224.        
  1225.     Radius = ABS(R)
  1226.     RadiusError = -Radius
  1227.     X = Radius
  1228.     Y = 0
  1229.    
  1230.     IF Radius = 0 THEN
  1231.         'PSET (CX, CY), C
  1232.         'PlotPoint CX, CY, S, MyArray()
  1233.         EXIT SUB
  1234.     END IF
  1235.    
  1236.     ' Get total width
  1237.     W = (Radius * 2) + 1
  1238.    
  1239.     ' Define a temp array
  1240.     ReDim arrTemp(0 To W, 0 To W) As String
  1241.    
  1242.         ' Get minimum X, Y of target array
  1243.         MinY = lbound(MyArray, 1)
  1244.         MaxY = ubound(MyArray, 1)
  1245.         MinX = lbound(MyArray, 2)
  1246.         MaxX = ubound(MyArray, 2)
  1247.        
  1248.         ' Temp array's lbound is 0
  1249.         ' Calculate difference from MyArray the indices of arrTemp are
  1250.         AY = 0 - MinY
  1251.         AX = 0 - MinX
  1252.        
  1253.     ' Draw the middle span here so we don't draw it twice in the main loop,
  1254.     ' which would be a problem with blending turned on.
  1255.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  1256.     'FOR iLoopX = CX - X TO CX + X
  1257.     FOR iLoopX = R - X TO R + X
  1258.         'PlotPoint iLoopX, CY, S, MyArray()
  1259.         'PlotPoint iLoopX, CY, S, arrTemp()
  1260.         PlotPoint iLoopX, R, S, arrTemp()
  1261.     NEXT iLoopX
  1262.    
  1263.     WHILE X > Y
  1264.         RadiusError = RadiusError + Y * 2 + 1
  1265.         IF RadiusError >= 0 THEN
  1266.             IF X <> Y + 1 THEN
  1267.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1268.                 'iLoopY = CY - X
  1269.                 iLoopY = R - X
  1270.                 'FOR iLoopX = CX - Y TO CX + Y
  1271.                 FOR iLoopX = R - Y TO R + Y
  1272.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1273.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1274.                 NEXT iLoopX
  1275.                
  1276.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1277.                 'iLoopY = CY + X
  1278.                 iLoopY = R + X
  1279.                 'FOR iLoopX = CX - Y TO CX + Y
  1280.                 FOR iLoopX = R - Y TO R + Y
  1281.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1282.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1283.                 NEXT iLoopX
  1284.             END IF
  1285.             X = X - 1
  1286.             RadiusError = RadiusError - X * 2
  1287.         END IF
  1288.         Y = Y + 1
  1289.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1290.         'iLoopY = CY - Y
  1291.         iLoopY = R - Y
  1292.         'FOR iLoopX = CX - X TO CX + X
  1293.         FOR iLoopX = R - X TO R + X
  1294.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1295.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1296.         NEXT iLoopX
  1297.        
  1298.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1299.         'iLoopY = CY + Y
  1300.         iLoopY = R + Y
  1301.         'FOR iLoopX = CX - X TO CX + X
  1302.         FOR iLoopX = R - X TO R + X
  1303.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1304.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1305.         NEXT iLoopX
  1306.     WEND
  1307.        
  1308.         '_echo "MyArray(" + _Trim$(Str$(lbound(MyArray,1))) + " To " + _Trim$(Str$(ubound(MyArray,1))) + ", " + _Trim$(Str$(lbound(MyArray,2))) + " To " + _Trim$(Str$(ubound(MyArray,2))) + ")"
  1309.        
  1310.     ' Copy semicircle to destination Y,X
  1311.         ' JUST COPY SELECTED QUADRANT:
  1312.         Select Case Q
  1313.                 Case 1:
  1314.                         ' quadrant #1
  1315.                         For DY = 0 to Radius
  1316.                                 For DX = Radius to W
  1317.                                         '_echo "DY=" + cstr$(DY) + ", DX=" + cstr$(DX)
  1318.                                         IF LEN(arrTemp(DY, DX)) > 0 THEN
  1319.                                                 TY = (DY + CY) - (AY+1)
  1320.                                                 If TY >= MinY Then
  1321.                                                         If TY <= MaxY Then
  1322.                                                                 TX = (DX - Radius) - AX
  1323.                                                                 If TX >= MinX Then
  1324.                                                                         If TX <= MaxX Then
  1325.                                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1326.                                                                         End If
  1327.                                                                 End If
  1328.                                                         End If
  1329.                                                 End If
  1330.                                         END IF
  1331.                                 Next DX
  1332.                         Next DY
  1333.                 Case 2:
  1334.                         ' quadrant #2
  1335.                         For DY = Radius to W
  1336.                                 For DX = Radius to W
  1337.                                         IF LEN(arrTemp(DY, DX)) > 0 THEN
  1338.                                                 TY = (DY - Radius) - AY
  1339.                                                 If TY >= MinY Then
  1340.                                                         If TY <= MaxY Then
  1341.                                                                 TX = (DX - Radius) - AX
  1342.                                                                 If TX >= MinX Then
  1343.                                                                         If TX <= MaxX Then
  1344.                                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1345.                                                                         End If
  1346.                                                                 End If
  1347.                                                         End If
  1348.                                                 End If
  1349.                                         END IF
  1350.                                 Next DX
  1351.                         Next DY
  1352.                 Case 3:
  1353.                         ' quadrant #3
  1354.                         For DY = Radius to W
  1355.                                 For DX = 0 to Radius
  1356.                                         IF LEN(arrTemp(DY, DX)) > 0 THEN
  1357.                                                 TY = (DY - Radius) - AY
  1358.                                                 If TY >= MinY Then
  1359.                                                         If TY <= MaxY Then
  1360.                                                                 TX = (DX + CX) - (AX+1)
  1361.                                                                 If TX >= MinX Then
  1362.                                                                         If TX <= MaxX Then
  1363.                                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1364.                                                                         End If
  1365.                                                                 End If
  1366.                                                         End If
  1367.                                                 End If
  1368.                                         END IF
  1369.                                 Next DX
  1370.                         Next DY
  1371.                 Case 4:
  1372.                         ' quadrant #4
  1373.                         For DY = 0 to Radius
  1374.                                 For DX = 0 to Radius
  1375.                                         IF LEN(arrTemp(DY, DX)) > 0 THEN
  1376.                                                 TY = (DY + CY) - (AY+1)
  1377.                                                 If TY >= MinY Then
  1378.                                                         If TY <= MaxY Then
  1379.                                                                 TX = (DX + CX) - (AX+1)
  1380.                                                                 If TX >= MinX Then
  1381.                                                                         If TX <= MaxX Then
  1382.                                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1383.                                                                         End If
  1384.                                                                 End If
  1385.                                                         End If
  1386.                                                 End If
  1387.                                         END IF
  1388.                                 Next DX
  1389.                         Next DY
  1390.                 Case Else:
  1391.                         ' (DO NOTHING)
  1392.         End Select
  1393.    
  1394.         '' Copy circle to destination:
  1395.         'For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  1396.     '    For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  1397.     '        IF LEN(arrTemp(DY, DX)) > 0 THEN
  1398.     '            MyArray(DY + CY, DX + CX) = arrTemp(DY, DX)
  1399.     '        END IF
  1400.     '    Next DX
  1401.     'Next DY
  1402.    
  1403. END SUB ' SemiCircleFill
  1404.  
  1405. ' /////////////////////////////////////////////////////////////////////////////
  1406.  
  1407. Sub SemiCircleFillTest
  1408.     Dim MyArray(1 To 32, 1 To 32) As String
  1409.     Dim iX As Integer
  1410.     Dim iY As Integer
  1411.     Dim in$
  1412.     Dim X As Integer
  1413.     Dim Y As Integer
  1414.     Dim R As Integer
  1415.     Dim Q As Integer
  1416.     Dim iChar As Integer
  1417.    
  1418.     ClearArray MyArray(), "."
  1419.     iChar = 64
  1420.    
  1421.     Cls
  1422.     Print "Plot a solid semicircle"
  1423.     Print "Based on CircleFill by SMcNeill."
  1424.     Print
  1425.     Print "Enter parameters to draw a semicircle."
  1426.     Print ArrayToStringTest(MyArray())
  1427.     Print
  1428.    
  1429.     Do
  1430.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot semicircle,"
  1431.         Print "radius (1-32) of semicircle, and quadrant of circle to use:"
  1432.         Print "41"
  1433.         Print "32"
  1434.         Input "X,Y,R,Q OR 0 TO QUIT: "; X, Y, R, Q
  1435.         If X > 0 AND Y > 0 AND R > 0 Then
  1436.             iChar = iChar + 1
  1437.             If iChar > 90 Then iChar = 65
  1438.            
  1439.             Print "X=" + cstr$(X)
  1440.             Print "Y=" + cstr$(Y)
  1441.             Print "R=" + cstr$(R)
  1442.            
  1443.             SemiCircleFill X, Y, R, Q, Chr$(iChar), MyArray()
  1444.            
  1445.             Print "Semicircle plotted (from top left), drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1446.             Print ArrayToStringTest(MyArray())
  1447.             Print
  1448.         Else
  1449.             Exit Do
  1450.         End If
  1451.     Loop
  1452.    
  1453. End Sub ' SemiCircleFillTest
  1454.  
  1455. ' /////////////////////////////////////////////////////////////////////////////
  1456. ' Re: Is this fast enough as general circle fill?
  1457. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  1458.  
  1459. ' From: bplus
  1460. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  1461.  
  1462. SUB Ellipse (CX AS INTEGER, CY AS INTEGER, xRadius AS INTEGER, yRadius AS INTEGER, S As String, MyArray() As String)
  1463.     DIM scale AS SINGLE
  1464.     DIM xs AS INTEGER
  1465.     DIM x AS INTEGER
  1466.     DIM y AS INTEGER
  1467.     DIM lastx AS INTEGER
  1468.     DIM lasty AS INTEGER
  1469.     Dim iLoopX as INTEGER
  1470.     Dim iLoopY as INTEGER
  1471.    
  1472.     scale = yRadius / xRadius
  1473.     xs = xRadius * xRadius
  1474.    
  1475.     'PSET (CX, CY - yRadius)
  1476.     PlotPoint CX, CY - yRadius, S, MyArray()
  1477.    
  1478.     'PSET (CX, CY + yRadius)
  1479.     PlotPoint CX, CY + yRadius, S, MyArray()
  1480.    
  1481.     lastx = 0: lasty = yRadius
  1482.     FOR x = 1 TO xRadius
  1483.         y = scale * SQR(xs - x * x)
  1484.         'LINE (CX + lastx, CY - lasty)-(CX + x, CY - y)
  1485.         PlotLine CX + lastx, CY - lasty, CX + x, CY - y, S, MyArray()
  1486.        
  1487.         'LINE (CX + lastx, CY + lasty)-(CX + x, CY + y)
  1488.         PlotLine CX + lastx, CY + lasty, CX + x, CY + y, S, MyArray()
  1489.        
  1490.         'LINE (CX - lastx, CY - lasty)-(CX - x, CY - y)
  1491.         PlotLine CX - lastx, CY - lasty, CX - x, CY - y, S, MyArray()
  1492.        
  1493.         'LINE (CX - lastx, CY + lasty)-(CX - x, CY + y)
  1494.         PlotLine CX - lastx, CY + lasty, CX - x, CY + y, S, MyArray()
  1495.        
  1496.         lastx = x
  1497.         lasty = y
  1498.     NEXT x
  1499. END SUB ' Ellipse
  1500.  
  1501. ' /////////////////////////////////////////////////////////////////////////////
  1502.  
  1503. Sub EllipseTest
  1504.     Dim MyArray(1 To 32, 1 To 32) As String
  1505.     Dim iX As Integer
  1506.     Dim iY As Integer
  1507.     Dim in$
  1508.     Dim X As Integer
  1509.     Dim Y As Integer
  1510.     Dim RX As Integer
  1511.     Dim RY As Integer
  1512.     Dim iChar As Integer
  1513.    
  1514.     ClearArray MyArray(), "."
  1515.     iChar = 64
  1516.    
  1517.     Cls
  1518.     Print "Plot an ellipse"
  1519.     Print "Based on ellipse by bplus."
  1520.     Print
  1521.     Print "Enter parameters to draw an ellipse."
  1522.     Print ArrayToStringTest(MyArray())
  1523.     Print
  1524.    
  1525.     Do
  1526.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  1527.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  1528.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  1529.         If X > 0 AND Y > 0 AND RX > 0 AND RY > 0 Then
  1530.             iChar = iChar + 1
  1531.             If iChar > 90 Then iChar = 65
  1532.            
  1533.             Print "X =" + cstr$(X)
  1534.             Print "Y =" + cstr$(Y)
  1535.             Print "RX=" + cstr$(RX)
  1536.             Print "RY=" + cstr$(RY)
  1537.            
  1538.             Ellipse X, Y, RX, RY, Chr$(iChar), MyArray()
  1539.            
  1540.             Print "Ellipse plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1541.             Print ArrayToStringTest(MyArray())
  1542.             Print
  1543.         Else
  1544.             Exit Do
  1545.         End If
  1546.     Loop
  1547.    
  1548. End Sub ' EllipseTest
  1549.  
  1550. ' /////////////////////////////////////////////////////////////////////////////
  1551. ' Re: Is this fast enough as general circle fill?
  1552. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  1553.  
  1554. ' From: bplus
  1555. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  1556. '
  1557. ' Here is my ellipse and filled ellipse routines, no where near
  1558. ' Steve's level of performance. The speed is cut in half at
  1559. ' least because you probably have to do a whole quadrants worth
  1560. ' of calculations (ellipse not as symmetric as circle).
  1561. '
  1562. ' But I am sure this code can be optimized more than it is:
  1563.  
  1564. SUB EllipseFill (CX AS INTEGER, CY AS INTEGER, xRadius AS INTEGER, yRadius AS INTEGER, S As String, MyArray() As String)
  1565.     DIM scale AS SINGLE
  1566.     DIM x AS INTEGER
  1567.     DIM y AS INTEGER
  1568.     Dim iLoopX as INTEGER
  1569.     Dim iLoopY as INTEGER
  1570.    
  1571.     scale = yRadius / xRadius
  1572.    
  1573.     'LINE (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  1574.     FOR iLoopY = CY - yRadius TO CY + yRadius
  1575.         PlotPoint CX, iLoopY, S, MyArray()
  1576.     NEXT iLoopY
  1577.    
  1578.     FOR x = 1 TO xRadius
  1579.         y = scale * SQR(xRadius * xRadius - x * x)
  1580.        
  1581.         'LINE (CX + x, CY - y)-(CX + x, CY + y), , BF
  1582.         iLoopX = CX + x
  1583.         FOR iLoopY = CY - y TO  CY + y
  1584.             PlotPoint iLoopX, iLoopY, S, MyArray()
  1585.         NEXT iLoopY
  1586.        
  1587.         'LINE (CX - x, CY - y)-(CX - x, CY + y), , BF
  1588.         iLoopX = CX - x
  1589.         FOR iLoopY = CY - y TO CY + y
  1590.             PlotPoint iLoopX, iLoopY, S, MyArray()
  1591.         NEXT iLoopY
  1592.     NEXT x
  1593. END SUB ' EllipseFill
  1594.  
  1595. ' /////////////////////////////////////////////////////////////////////////////
  1596.  
  1597. Sub EllipseFillTest
  1598.     Dim MyArray(1 To 32, 1 To 32) As String
  1599.     Dim iX As Integer
  1600.     Dim iY As Integer
  1601.     Dim in$
  1602.     Dim X As Integer
  1603.     Dim Y As Integer
  1604.     Dim RX As Integer
  1605.     Dim RY As Integer
  1606.     Dim iChar As Integer
  1607.    
  1608.     ClearArray MyArray(), "."
  1609.     iChar = 64
  1610.    
  1611.     Cls
  1612.     Print "Plot a filled ellipse"
  1613.     Print "Based on fellipse by bplus."
  1614.     Print
  1615.     Print "Enter parameters to draw an ellipse."
  1616.     Print ArrayToStringTest(MyArray())
  1617.     Print
  1618.    
  1619.     Do
  1620.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  1621.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  1622.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  1623.         If X > 0 AND Y > 0 AND RX > 0 AND RY > 0 Then
  1624.             iChar = iChar + 1
  1625.             If iChar > 90 Then iChar = 65
  1626.            
  1627.             Print "X =" + cstr$(X)
  1628.             Print "Y =" + cstr$(Y)
  1629.             Print "RX=" + cstr$(RX)
  1630.             Print "RY=" + cstr$(RY)
  1631.            
  1632.             EllipseFill X, Y, RX, RY, Chr$(iChar), MyArray()
  1633.            
  1634.             Print "Ellipse plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1635.             Print ArrayToStringTest(MyArray())
  1636.             Print
  1637.         Else
  1638.             Exit Do
  1639.         End If
  1640.     Loop
  1641.    
  1642. End Sub ' EllipseFillTest
  1643.  
  1644. ' /////////////////////////////////////////////////////////////////////////////
  1645. ' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
  1646. ' From: http://www.thedubber.altervista.org/qbsrc.htm
  1647.  
  1648. Sub PlotLine (x1%, y1%, x2%, y2%, c$, MyArray() As String)
  1649.     Dim iLoop%
  1650.     Dim steep%: steep% = 0
  1651.     Dim ev%: ev% = 0
  1652.     Dim sx%
  1653.     Dim sy%
  1654.     Dim dx%
  1655.     Dim dy%
  1656.    
  1657.     If (x2% - x1%) > 0 Then
  1658.         sx% = 1
  1659.     Else
  1660.         sx% = -1
  1661.     End If
  1662.  
  1663.     dx% = Abs(x2% - x1%)
  1664.     If (y2% - y1%) > 0 Then
  1665.         sy% = 1
  1666.     Else
  1667.         sy% = -1
  1668.     End If
  1669.  
  1670.     dy% = Abs(y2% - y1%)
  1671.     If (dy% > dx%) Then
  1672.         steep% = 1
  1673.         Swap x1%, y1%
  1674.         Swap dx%, dy%
  1675.         Swap sx%, sy%
  1676.     End If
  1677.  
  1678.     ev% = 2 * dy% - dx%
  1679.     For iLoop% = 0 To dx% - 1
  1680.         If steep% = 1 Then
  1681.             ''PSET (y1%, x1%), c%:
  1682.             'LOCATE y1%, x1%
  1683.             'PRINT c$;
  1684.             PlotPoint y1%, x1%, c$, MyArray()
  1685.         Else
  1686.             ''PSET (x1%, y1%), c%
  1687.             'LOCATE x1%, y1%
  1688.             'PRINT c$;
  1689.             PlotPoint x1%, y1%, c$, MyArray()
  1690.         End If
  1691.  
  1692.         While ev% >= 0
  1693.             y1% = y1% + sy%
  1694.             ev% = ev% - 2 * dx%
  1695.         Wend
  1696.         x1% = x1% + sx%
  1697.         ev% = ev% + 2 * dy%
  1698.     Next iLoop%
  1699.     ''PSET (x2%, y2%), c%
  1700.     'LOCATE x2%, y2%
  1701.     'PRINT c$;
  1702.     PlotPoint x2%, y2%, c$, MyArray()
  1703. End Sub ' PlotLine
  1704.  
  1705. ' /////////////////////////////////////////////////////////////////////////////
  1706.  
  1707. Sub PlotLineTest
  1708.     Dim MyArray(1 To 32, 1 To 32) As String
  1709.     Dim in$
  1710.     Dim X1 As Integer
  1711.     Dim Y1 As Integer
  1712.     Dim X2 As Integer
  1713.     Dim Y2 As Integer
  1714.     Dim iChar As Integer
  1715.    
  1716.     ClearArray MyArray(), "."
  1717.     iChar = 64
  1718.    
  1719.     Cls
  1720.     Print "Plot line with Bresenham Algorithm"
  1721.     Print "based on BRESNHAM.BAS by Kurt Kuzba (4/16/96)."
  1722.     Print
  1723.     Print ArrayToStringTest(MyArray())
  1724.     Do
  1725.         Print "Enter coordinate values for "
  1726.         Print "line start point x1, y1 (1-32, 1-32)"
  1727.         Print "line end   point x2, y2 (1-32, 1-32)"
  1728.         Input "ENTER X1,Y1,X2,Y2 OR 0 TO QUIT: "; X1, Y1, X2, Y2
  1729.         If X1 > 0 And Y1 > 0 And X2 > 0 And Y2 > 0 Then
  1730.             iChar = iChar + 1
  1731.             If iChar > 90 Then iChar = 65
  1732.            
  1733.             Print "X1=" + cstr$(X1)
  1734.             Print "Y1=" + cstr$(Y1)
  1735.             Print "X2=" + cstr$(X2)
  1736.             Print "Y2=" + cstr$(Y2)
  1737.            
  1738.             PlotLine X1, Y1, X2, Y2, Chr$(iChar), MyArray()
  1739.            
  1740.             Print "Line plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1741.             Print ArrayToStringTest(MyArray())
  1742.            
  1743.         Else
  1744.             Exit Do
  1745.         End If
  1746.     Loop
  1747. End Sub ' PlotLineTest
  1748.  
  1749. ' /////////////////////////////////////////////////////////////////////////////
  1750. ' 3 shear method testing
  1751.  
  1752. ' _PUT Rotation Help
  1753. ' https://www.qb64.org/forum/index.php?topic=1959.0
  1754.  
  1755. ' 3 Shear Rotation - rotates without any aliasing(holes)
  1756. ' https://www.freebasic.net/forum/viewtopic.php?t=24557
  1757.  
  1758. ' From: leopardpm
  1759. ' Date: Apr 02, 2016 1:21
  1760. ' Last edited by leopardpm on Apr 02, 2016 17:18, edited 1 time in total.
  1761. '
  1762. ' This is just a little 3-shear rotation routine
  1763. ' (I am using 3-shear because it leaves no gaps/aliasing)
  1764. ' that I was wondering if anyone sees how to make it faster.
  1765. ' Obviously, I am just thinking about inside the double loop.
  1766.  
  1767. ' Thanks again to BasicCoder2 for linking me to this little routine, it is wonderful so far!
  1768.  
  1769. '''                      roto-zooming algorithm
  1770. '''                    coded by Michael S. Nissen
  1771. '''                        jernmager@yahoo.dk
  1772. '
  1773. ''' ===============================================================
  1774. ''' Recoded to run on FBC 32/64 bit WIN, Version 1.05.0, 2016, by MrSwiss
  1775. ''' Heavy flickering before going Full-Screen on 64 Bit !!!
  1776. ''' This seems NOT to be the Case on 32 Bit ...
  1777. ''' ===============================================================
  1778. '
  1779. 'Type Pixel
  1780. '  As Single   X, Y
  1781. '  As ULong    C
  1782. 'End Type
  1783. '
  1784. '''  dim vars
  1785. 'Dim shared as Any Ptr Img_Buffer
  1786. '''  write the name of the .bmp image you want to rotozoom here:
  1787. '''  (it has to be sqare ie. 100x100 pixels, 760x760 pixels or whatever)
  1788. 'Dim As String Img_Name = "phobos.bmp"
  1789. 'Dim shared as Integer X_Mid, Y_Mid, scrn_wid, scrn_hgt, P1, P2, P3, P4, C
  1790. 'Dim shared as Short Img_Hgt, Img_Wid, Img_Lft, Img_Rgt, Img_Top, Img_Btm, X, Y
  1791. 'Dim Shared As Single Cos_Ang, Sin_Ang, Rot_Fac_X, Rot_Fac_Y, Angle = 0, Scale = 1
  1792. '
  1793. ''' changed Function to Sub (+ recoded arguments list)
  1794. 'Sub Calc_rotozoom ( ByRef Cos_Ang As Single, _
  1795. '               ByRef Sin_Ang As Single, _
  1796. '               ByVal S_Fact  As Single, _
  1797. '               ByVal NewAng  As Single )
  1798. '  Cos_Ang = Cos(NewAng)*S_Fact
  1799. '  Sin_Ang = Sin(NewAng)*S_Fact
  1800. 'End Sub
  1801. '
  1802. '''  full screen
  1803. 'ScreenInfo scrn_wid, scrn_hgt
  1804. 'screenRes scrn_wid, scrn_hgt, 32,,1
  1805. '
  1806. '''  dim screenpointer (has to be done after screenres)
  1807. 'Dim As ULong Ptr Scrn_Ptr = Screenptr
  1808. '
  1809. '''  place image in center of screen
  1810. 'X_Mid = scrn_wid\2
  1811. 'Y_Mid = scrn_hgt\2
  1812. 'Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1813. '
  1814. '''  find image dimensions
  1815. 'Open Img_Name For Binary As #1
  1816. 'Get #1, 19, Img_Wid
  1817. 'Get #1, 23, Img_Hgt
  1818. 'Close #1
  1819. '
  1820. '''  prepare to dim the array that will hold the image.
  1821. 'Img_Rgt = (Img_Wid-1)\2
  1822. 'Img_Lft = -Img_Rgt
  1823. 'Img_Btm = (Img_Hgt-1)\2
  1824. 'Img_Top = -Img_Btm
  1825. '
  1826. '''  dim array to hold image. Note: pixel (0, 0) is in the center.
  1827. 'Dim As Pixel Pixel(Img_Lft to Img_Rgt, Img_Top to Img_Btm)
  1828. '
  1829. '''  imagecreate sprite and load image to sprite
  1830. 'Img_Buffer = ImageCreate (Img_Wid, Img_Hgt)
  1831. 'Bload (Img_Name, Img_Buffer)
  1832. '
  1833. '''  load image from sprite to array with point command
  1834. 'For Y = Img_Top to Img_Btm
  1835. '  For X = Img_Lft to Img_Rgt
  1836. '    With Pixel(X, Y)
  1837. '      .X = X_Mid+X
  1838. '      .Y = Y_Mid+Y
  1839. '      C = Point (X-Img_Top, Y-Img_Lft, Img_buffer)
  1840. '      If C <> RGB(255, 0, 255) Then
  1841. '        .C = C
  1842. '      Else
  1843. '        .C = RGB(0, 0, 0)
  1844. '      End If
  1845. '    End With
  1846. '  Next X
  1847. 'Next Y
  1848. '
  1849. '''  we don't need the sprite anymore, kill it
  1850. 'ImageDestroy Img_Buffer
  1851. 'Img_Buffer = 0
  1852. '
  1853. '''  main program loop
  1854. 'Do
  1855. '
  1856. '  ''  scale in/out with uparrow/downarrow
  1857. '  If Multikey(80) Then
  1858. '    Scale *= 1.03
  1859. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1860. '  ElseIf Multikey(72) Then
  1861. '    Scale *= 0.97
  1862. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1863. '  End If
  1864. '
  1865. '  ''  rotate left/right with leftarrow/rightarrow
  1866. '  If Multikey(77) Then
  1867. '    Angle -= 0.03
  1868. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1869. '  ElseIf Multikey(75) Then
  1870. '    Angle += 0.03
  1871. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1872. '  End If
  1873. '
  1874. '  ''  lock screen in order to use screen pointers
  1875. '  ScreenLock
  1876. '
  1877. '    ''  draw pixel in center of image
  1878. '    Scrn_Ptr[ X_Mid + Y_Mid * scrn_wid ] = Pixel(0, 0).C
  1879. '    ''  draw all other pixels - 4 at a time
  1880. '    For Y = Img_Top to 0
  1881. '      For X = Img_Lft to -1
  1882. '        ''  find pixel positions
  1883. '        P1 = (X_Mid+X) + (Y_Mid+Y) * scrn_wid
  1884. '        P2 = (X_Mid-X) + (Y_Mid-Y) * scrn_wid
  1885. '        P3 = (X_Mid+Y) + (Y_Mid-X) * scrn_wid
  1886. '        P4 = (X_Mid-Y) + (Y_Mid+X) * scrn_wid
  1887. '        ''  erase old pixels (paint them black)
  1888. '        Scrn_Ptr[P1] = 0
  1889. '        Scrn_Ptr[P2] = 0
  1890. '        Scrn_Ptr[P3] = 0
  1891. '        Scrn_Ptr[P4] = 0
  1892. '        ''  rotate and zoom
  1893. '        Rot_Fac_X = X*Cos_Ang - Y*Sin_Ang
  1894. '        Rot_Fac_Y = X*Sin_Ang + Y*Cos_Ang
  1895. '        If Rot_Fac_X < Img_Lft Or Rot_Fac_X > Img_Rgt Then Continue For
  1896. '        If Rot_Fac_Y < Img_Top Or Rot_Fac_Y > Img_Btm Then Continue For
  1897. '        ''  draw new pixels
  1898. '        Scrn_Ptr[P1] = Pixel(Rot_Fac_X, Rot_Fac_Y).C
  1899. '        Scrn_Ptr[P2] = Pixel(-Rot_Fac_X, -Rot_Fac_Y).C
  1900. '        Scrn_Ptr[P3] = Pixel(Rot_Fac_Y, -Rot_Fac_X).C
  1901. '        Scrn_Ptr[P4] = Pixel(-Rot_Fac_Y, Rot_Fac_X).C
  1902. '      Next X
  1903. '    Next Y
  1904. '
  1905. '  ScreenUnLock
  1906. '
  1907. '  Sleep 10, 1
  1908. 'Loop Until InKey() = Chr(27)
  1909.  
  1910. ' UPDATES:
  1911. ' Fixed bug where values 135, 224, and 314 all resolve to -45 degrees.
  1912. ' Fixed bug where an angle of 46-135 degrees caused the image to be flipped wrong.
  1913.  
  1914. ' TODO:
  1915. ' Fix issue where image looks bad at 30, 60, 120, 150, 210, 240, 300, 330 degrees
  1916.  
  1917. Sub ShearRotate (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  1918.     Const Pi = 4 * Atn(1)
  1919.    
  1920.     Dim angle As Integer
  1921.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  1922.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  1923.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  1924.     Dim x As Integer
  1925.     Dim y As Integer
  1926.     Dim nangle As Integer
  1927.     Dim nx As Integer
  1928.     Dim ny As Integer
  1929.     Dim flipper As Integer
  1930.     Dim rotr As Double
  1931.     Dim shear1 As Double
  1932.     Dim shear2 As Double
  1933.     Dim clr As Integer
  1934.     Dim y1 As _Byte
  1935.     Dim xy1 As _Byte
  1936.     Dim fy As _Byte
  1937.     Dim fx As _Byte
  1938.     Dim in$
  1939.     Dim sLine As String
  1940.    
  1941.     ' initialize new with empty
  1942.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  1943.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1944.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1945.             NewArray(x, y, 0).origx = x
  1946.             NewArray(x, y, 0).origy = y
  1947.             NewArray(x, y, 0).c = iEmpty
  1948.         Next y
  1949.     Next x
  1950.    
  1951.     ' angle is reversed
  1952.     angle = 360 - angle1
  1953.    
  1954.     ' Shearing each element 3 times in one shot
  1955.     nangle = angle
  1956.    
  1957.     ' this pre-processing portion basically rotates by 90 to get
  1958.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  1959.     If angle > 45 And angle < 225 Then
  1960.         If angle < 135 Then
  1961.             nangle = angle - 90
  1962.         Else
  1963.             nangle = angle - 180
  1964.         End If
  1965.     End If
  1966.     If angle > 135 And angle < 315 Then
  1967.         If angle < 225 Then
  1968.             nangle = angle - 180
  1969.         Else
  1970.             nangle = angle - 270
  1971.         End If
  1972.     End If
  1973.     If nangle < 0 Then
  1974.         nangle = nangle + 360
  1975.     End If
  1976.     If nangle > 359 Then
  1977.         nangle = nangle - 360
  1978.     End If
  1979.    
  1980.     rotr = nangle * DtoR
  1981.     shear1 = Tan(rotr / 2) ' correct way
  1982.     shear2 = Sin(rotr)
  1983.    
  1984.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  1985.     ' ***       all resolve to -45 degrees.
  1986.     ' ***       Fixed by changing < to <=
  1987.    
  1988.     'if angle >  45 and angle < 134 then
  1989.     If angle > 45 And angle <= 134 Then
  1990.         flipper = 1
  1991.     ElseIf angle > 134 And angle <= 224 Then
  1992.         flipper = 2
  1993.     ElseIf angle > 224 And angle <= 314 Then
  1994.         ' *** NOTE: this had a bug where this flipper was wrong
  1995.         '           Fixed by adding case 7
  1996.         'flipper = 3
  1997.         flipper = 7
  1998.     Else
  1999.         flipper = 0
  2000.     End If
  2001.    
  2002.     ' Here is where it needs some optimizing possibly... kinda slow...
  2003.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2004.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2005.             Select Case flipper
  2006.                 Case 1:
  2007.                     nx = -y
  2008.                     ny = x
  2009.                 Case 2:
  2010.                     nx = -x
  2011.                     ny = -y
  2012.                 Case 3:
  2013.                     nx = -y
  2014.                     ny = -x
  2015.                 Case 4:
  2016.                     nx = -x
  2017.                     ny = y
  2018.                 Case 5:
  2019.                     nx = x
  2020.                     ny = -y
  2021.                 Case 6:
  2022.                     nx = y
  2023.                     ny = x
  2024.                 Case 7:
  2025.                     nx = y
  2026.                     ny = -x
  2027.                 Case Else:
  2028.                     nx = x
  2029.                     ny = y
  2030.             End Select
  2031.            
  2032.             clr = OldArray(nx, ny, 0).c
  2033.            
  2034.             y1 = y * shear1
  2035.             xy1 = x + y1
  2036.             fy = (y - xy1 * shear2)
  2037.             fx = xy1 + fy * shear1
  2038.            
  2039.             If fx >= -16 And fx <= 16 Then
  2040.                 If fy >= -16 And fy <= 16 Then
  2041.                     NewArray(fx, fy, 0).c = clr
  2042.                     NewArray(fx, fy, 0).origx = fx
  2043.                     NewArray(fx, fy, 0).origy = fy
  2044.                 End If
  2045.             End If
  2046.         Next x
  2047.     Next y
  2048. End Sub ' ShearRotate
  2049.  
  2050. ' /////////////////////////////////////////////////////////////////////////////
  2051. ' Same as ShearRotate, except adds iOverwriteCount parameter,
  2052. ' and counts how many points are overwriting existing points,
  2053. ' and return that value byref in parameter iOverwriteCount.
  2054.  
  2055. Sub ShearRotate1 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iOverwriteCount As Integer)
  2056.     Const Pi = 4 * Atn(1)
  2057.    
  2058.     Dim angle As Integer
  2059.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2060.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2061.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2062.     Dim x As Integer
  2063.     Dim y As Integer
  2064.     Dim nangle As Integer
  2065.     Dim nx As Integer
  2066.     Dim ny As Integer
  2067.     Dim flipper As Integer
  2068.     Dim rotr As Double
  2069.     Dim shear1 As Double
  2070.     Dim shear2 As Double
  2071.     Dim clr As Integer
  2072.     Dim y1 As _Byte
  2073.     Dim xy1 As _Byte
  2074.     Dim fy As _Byte
  2075.     Dim fx As _Byte
  2076.     Dim in$
  2077.     Dim sLine As String
  2078.    
  2079.     ' initialize new with empty
  2080.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2081.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2082.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2083.             NewArray(x, y, 0).origx = x
  2084.             NewArray(x, y, 0).origy = y
  2085.             NewArray(x, y, 0).c = iEmpty
  2086.         Next y
  2087.     Next x
  2088.    
  2089.     ' angle is reversed
  2090.     angle = 360 - angle1
  2091.    
  2092.     ' Shearing each element 3 times in one shot
  2093.     nangle = angle
  2094.    
  2095.     ' this pre-processing portion basically rotates by 90 to get
  2096.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2097.     If angle > 45 And angle < 225 Then
  2098.         If angle < 135 Then
  2099.             nangle = angle - 90
  2100.         Else
  2101.             nangle = angle - 180
  2102.         End If
  2103.     End If
  2104.     If angle > 135 And angle < 315 Then
  2105.         If angle < 225 Then
  2106.             nangle = angle - 180
  2107.         Else
  2108.             nangle = angle - 270
  2109.         End If
  2110.     End If
  2111.     If nangle < 0 Then
  2112.         nangle = nangle + 360
  2113.     End If
  2114.     If nangle > 359 Then
  2115.         nangle = nangle - 360
  2116.     End If
  2117.    
  2118.     rotr = nangle * DtoR
  2119.     shear1 = Tan(rotr / 2) ' correct way
  2120.     shear2 = Sin(rotr)
  2121.    
  2122.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2123.     ' ***       all resolve to -45 degrees.
  2124.     ' ***       Fixed by changing < to <=
  2125.    
  2126.     'if angle >  45 and angle < 134 then
  2127.     If angle > 45 And angle <= 134 Then
  2128.         flipper = 1
  2129.     ElseIf angle > 134 And angle <= 224 Then
  2130.         flipper = 2
  2131.     ElseIf angle > 224 And angle <= 314 Then
  2132.         ' *** NOTE: this had a bug where this flipper was wrong
  2133.         '           Fixed by adding case 7
  2134.         'flipper = 3
  2135.         flipper = 7
  2136.     Else
  2137.         flipper = 0
  2138.     End If
  2139.    
  2140.     ' Here is where it needs some optimizing possibly... kinda slow...
  2141.     iOverwriteCount = 0
  2142.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2143.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2144.             Select Case flipper
  2145.                 Case 1:
  2146.                     nx = -y
  2147.                     ny = x
  2148.                 Case 2:
  2149.                     nx = -x
  2150.                     ny = -y
  2151.                 Case 3:
  2152.                     nx = -y
  2153.                     ny = -x
  2154.                 Case 4:
  2155.                     nx = -x
  2156.                     ny = y
  2157.                 Case 5:
  2158.                     nx = x
  2159.                     ny = -y
  2160.                 Case 6:
  2161.                     nx = y
  2162.                     ny = x
  2163.                 Case 7:
  2164.                     nx = y
  2165.                     ny = -x
  2166.                 Case Else:
  2167.                     nx = x
  2168.                     ny = y
  2169.             End Select
  2170.            
  2171.             clr = OldArray(nx, ny, 0).c
  2172.            
  2173.             y1 = y * shear1
  2174.             xy1 = x + y1
  2175.             fy = (y - xy1 * shear2)
  2176.             fx = xy1 + fy * shear1
  2177.            
  2178.             If fx >= -16 And fx <= 16 Then
  2179.                 If fy >= -16 And fy <= 16 Then
  2180.                    
  2181.                     ' count points that will be overwritten
  2182.                     if NewArray(fx, fy, 0).c <> iEmpty then
  2183.                         iOverwriteCount = iOverwriteCount + 1
  2184.                     end if
  2185.                    
  2186.                     NewArray(fx, fy, 0).c = clr
  2187.                     NewArray(fx, fy, 0).origx = fx
  2188.                     NewArray(fx, fy, 0).origy = fy
  2189.                 End If
  2190.             End If
  2191.         Next x
  2192.     Next y
  2193. End Sub ' ShearRotate1
  2194.  
  2195. ' /////////////////////////////////////////////////////////////////////////////
  2196.  
  2197. Sub ShearRotate1Test1
  2198.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2199.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2200.     Dim sMap As String
  2201.     Dim D As Integer
  2202.     Dim in$
  2203.    
  2204.     ' GET A SHAPE TO BE ROTATED
  2205.     Cls
  2206.     Print "3 shear rotation based on code by leopardpm"
  2207.     Print
  2208.    
  2209.     sMap = TestSprite1$
  2210.    
  2211.     ' CONVERT SHAPE TO ARRAY
  2212.     StringToRotationArray RoArray1(), sMap, "."
  2213.     Print "Initial contents of Rotation Array:"
  2214.     Print RotationArrayToStringTest(RoArray1())
  2215.     Print
  2216.    
  2217.     ' ROTATE THE SHAPE
  2218.     Do
  2219.         Print "Type degrees to rotate (0 TO 360) or non-numeric value to quit."
  2220.         Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2221.  
  2222.         Input "Degrees to rotate (q to quit)? "; in$
  2223.         If IsNum%(in$) Then
  2224.             D = Val(in$)
  2225.             If D >= 0 And D <= 360 Then
  2226.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  2227.                 Print
  2228.                 Print "Rotated by " + cstr$(D) + " degrees:"
  2229.                 Print RotationArrayToStringTest(RoArray2())
  2230.                 Print
  2231.             Else
  2232.                 Exit Do
  2233.             End If
  2234.         Else
  2235.             Exit Do
  2236.         End If
  2237.     Loop
  2238. End Sub ' ShearRotate1Test1
  2239.  
  2240. ' /////////////////////////////////////////////////////////////////////////////
  2241. ' Now receives parameter sMap
  2242. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  2243.  
  2244. ' e.g. ShearRotate1Test2 TestSprite1$
  2245.  
  2246. Sub ShearRotate1Test2(sMap As String)
  2247.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2248.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2249.     'Dim sMap As String
  2250.     Dim D As Integer
  2251.     Dim D1 As Integer
  2252.     Dim in$
  2253.     Dim bFinished As Integer
  2254.     Dim iOverwriteCount As Integer
  2255.    
  2256.     ' GET A SHAPE TO BE ROTATED
  2257.     Cls
  2258.     Print "3 shear rotation based on code by leopardpm"
  2259.     'sMap = TestSprite1$
  2260.    
  2261.     ' CONVERT SHAPE TO ARRAY
  2262.     StringToRotationArray RoArray1(), sMap, "."
  2263.  
  2264.     ' GET START ANGLE
  2265.     D = 0
  2266.     Print
  2267.     Print "Rotated by " + cstr$(D) + " degrees:"
  2268.     Print RotationArrayToStringTest(RoArray1())
  2269.     Print
  2270.     Print "Type an angle (-360 to 360) to rotate to, "
  2271.     Print "or blank to increase by 1 degree, or q to quit."
  2272.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2273.     Print "Hold down <ENTER> to rotate continually."
  2274.     Input "Angle (q to quit)? ", in$
  2275.     If Len(in$) > 0 Then
  2276.         If IsNum%(in$) Then
  2277.             D1 = Val(in$)
  2278.         Else
  2279.             D1 = -500
  2280.         End If
  2281.     Else
  2282.         D1 = 1
  2283.     End If
  2284.  
  2285.     ' ROTATE TO EACH ANGLE
  2286.     If D1 >= -360 And D1 <= 360 Then
  2287.         bFinished = FALSE
  2288.         Do
  2289.             ' ROTATE CLOCKWISE
  2290.             For D = D1 To 360
  2291.                 Cls
  2292.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  2293.                 Print
  2294.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2295.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  2296.                
  2297.                 Print RotationArrayToStringTest(RoArray2())
  2298.                 Print
  2299.  
  2300.                 Print "Type an angle (-360 to 360) to rotate to, "
  2301.                 Print "or blank to increase by 1 degree, or q to quit."
  2302.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2303.                 Print "Hold down <ENTER> to rotate continually."
  2304.                 Input "Angle (q to quit)? ", in$
  2305.                 If Len(in$) > 0 Then
  2306.                     If IsNum%(in$) Then
  2307.                         D = Val(in$)
  2308.                         If D >= 0 And D <= 360 Then
  2309.                             D = D - 1
  2310.                         Else
  2311.                             bFinished = TRUE
  2312.                             Exit For
  2313.                         End If
  2314.                     Else
  2315.                         bFinished = TRUE
  2316.                         Exit For
  2317.                     End If
  2318.                 End If
  2319.             Next D
  2320.             If bFinished = TRUE Then Exit Do
  2321.            
  2322.             ' ROTATE COUNTER-CLOCKWISE
  2323.             For D = 360 To D1 Step -1
  2324.                 Cls
  2325.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  2326.                 Print
  2327.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2328.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  2329.                
  2330.                 Print RotationArrayToStringTest(RoArray2())
  2331.                 Print
  2332.  
  2333.                 Print "Type an angle (0 to 360) to rotate to, "
  2334.                 Print "or blank to increase by 1 degree, or q to quit."
  2335.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2336.                 Print "Hold down <ENTER> to rotate continually."
  2337.                 Input "Angle (q to quit)? ", in$
  2338.                 If Len(in$) > 0 Then
  2339.                     If IsNum%(in$) Then
  2340.                         D = Val(in$)
  2341.                         If D >= 0 And D <= 360 Then
  2342.                             D = D + 1
  2343.                         Else
  2344.                             bFinished = TRUE
  2345.                             Exit For
  2346.                         End If
  2347.                     Else
  2348.                         bFinished = TRUE
  2349.                         Exit For
  2350.                     End If
  2351.                 End If
  2352.             Next D
  2353.             If bFinished = TRUE Then Exit Do
  2354.         Loop
  2355.     End If
  2356. End Sub ' ShearRotate1Test2
  2357.  
  2358. ' /////////////////////////////////////////////////////////////////////////////
  2359. ' ShearRotate v2
  2360. ' Tries to fix the problem of 2 points resolving to the same coordinate
  2361. ' (one overwrites the other, which becomes "lost")
  2362.  
  2363. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  2364.  
  2365. Sub ShearRotate2 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iMissing As Integer)
  2366.     Const Pi = 4 * Atn(1)
  2367.    
  2368.     Dim angle As Integer
  2369.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2370.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2371.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2372.     Dim x As Integer
  2373.     Dim y As Integer
  2374.     Dim nangle As Integer
  2375.     Dim nx As Integer
  2376.     Dim ny As Integer
  2377.     Dim flipper As Integer
  2378.     Dim rotr As Double
  2379.     Dim shear1 As Double
  2380.     Dim shear2 As Double
  2381.     Dim clr As Integer
  2382.     Dim y1 As _Byte
  2383.     Dim xy1 As _Byte
  2384.     Dim fy As _Byte
  2385.     Dim fx As _Byte
  2386.     Dim in$
  2387.     Dim sLine As String
  2388.     ReDim arrLost(-1) As RotationType
  2389.     Dim iLoop As Integer
  2390.     Dim bFound As Integer
  2391.    
  2392.     ' initialize new with empty
  2393.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2394.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2395.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2396.             NewArray(x, y, 0).origx = x
  2397.             NewArray(x, y, 0).origy = y
  2398.             NewArray(x, y, 0).c = iEmpty
  2399.         Next y
  2400.     Next x
  2401.    
  2402.     ' angle is reversed
  2403.     angle = 360 - angle1
  2404.    
  2405.     ' Shearing each element 3 times in one shot
  2406.     nangle = angle
  2407.    
  2408.     ' this pre-processing portion basically rotates by 90 to get
  2409.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2410.     If angle > 45 And angle < 225 Then
  2411.         If angle < 135 Then
  2412.             nangle = angle - 90
  2413.         Else
  2414.             nangle = angle - 180
  2415.         End If
  2416.     End If
  2417.     If angle > 135 And angle < 315 Then
  2418.         If angle < 225 Then
  2419.             nangle = angle - 180
  2420.         Else
  2421.             nangle = angle - 270
  2422.         End If
  2423.     End If
  2424.     If nangle < 0 Then
  2425.         nangle = nangle + 360
  2426.     End If
  2427.     If nangle > 359 Then
  2428.         nangle = nangle - 360
  2429.     End If
  2430.    
  2431.     rotr = nangle * DtoR
  2432.     shear1 = Tan(rotr / 2) ' correct way
  2433.     shear2 = Sin(rotr)
  2434.    
  2435.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2436.     ' ***       all resolve to -45 degrees.
  2437.     ' ***       Fixed by changing < to <=
  2438.    
  2439.     'if angle >  45 and angle < 134 then
  2440.     If angle > 45 And angle <= 134 Then
  2441.         flipper = 1
  2442.     ElseIf angle > 134 And angle <= 224 Then
  2443.         flipper = 2
  2444.     ElseIf angle > 224 And angle <= 314 Then
  2445.         ' *** NOTE: this had a bug where this flipper was wrong
  2446.         '           Fixed by adding case 7
  2447.         'flipper = 3
  2448.         flipper = 7
  2449.     Else
  2450.         flipper = 0
  2451.     End If
  2452.    
  2453.     ' Here is where it needs some optimizing possibly... kinda slow...
  2454.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2455.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2456.             Select Case flipper
  2457.                 Case 1:
  2458.                     nx = -y
  2459.                     ny = x
  2460.                 Case 2:
  2461.                     nx = -x
  2462.                     ny = -y
  2463.                 Case 3:
  2464.                     nx = -y
  2465.                     ny = -x
  2466.                 Case 4:
  2467.                     nx = -x
  2468.                     ny = y
  2469.                 Case 5:
  2470.                     nx = x
  2471.                     ny = -y
  2472.                 Case 6:
  2473.                     nx = y
  2474.                     ny = x
  2475.                 Case 7:
  2476.                     nx = y
  2477.                     ny = -x
  2478.                 Case Else:
  2479.                     nx = x
  2480.                     ny = y
  2481.             End Select
  2482.            
  2483.             clr = OldArray(nx, ny, 0).c
  2484.            
  2485.             y1 = y * shear1
  2486.             xy1 = x + y1
  2487.             fy = (y - xy1 * shear2)
  2488.             fx = xy1 + fy * shear1
  2489.            
  2490.             If fx >= -16 And fx <= 16 Then
  2491.                 If fy >= -16 And fy <= 16 Then
  2492.                     ' only draw here if this spot is empty
  2493.                     if NewArray(fx, fy, 0).c = iEmpty then
  2494.                         NewArray(fx, fy, 0).c = clr
  2495.                         NewArray(fx, fy, 0).origx = fx
  2496.                         NewArray(fx, fy, 0).origy = fy
  2497.                     else
  2498.                         ' don't draw, but save it to a list to handle later
  2499.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  2500.                         arrLost(UBound(arrLost)).c = clr
  2501.                         arrLost(UBound(arrLost)).origx = fx
  2502.                         arrLost(UBound(arrLost)).origy = fy
  2503.                     end if
  2504.                 End If
  2505.             End If
  2506.         Next x
  2507.     Next y
  2508.    
  2509.     ' try to place any points that would have overwritten to a spot nearby
  2510.     ' can nearby be determined by the angle of rotation?
  2511.     ' perhaps if we divide the screen up into 4 zones:
  2512.     '
  2513.     ' --------------------------------------
  2514.     '|                   |                  |
  2515.     '| zone 4            | zone 1           |
  2516.     '| 271-359 degrees)  | (1-89 degrees)   |
  2517.     '|--------------------------------------|
  2518.     '|                   |                  |
  2519.     '| zone 3            | zone 2           |
  2520.     '| (181-269 degrees) | (91-179 degrees) |
  2521.     '|                   |                  |
  2522.     ' --------------------------------------
  2523.    
  2524.     ' in zone   search direction (y,x)
  2525.     ' -------   ----------------------
  2526.     ' 1         up   + right
  2527.     ' 2         down + right
  2528.     ' 3         down + left
  2529.     ' 4         up   + left
  2530.    
  2531.     iMissing = 0
  2532.     For iLoop = 0 To UBound(arrLost)
  2533.         bFound = FindEmptyShearRotationPoint2%(arrLost(iLoop), angle1, iEmpty, x, y, NewArray())
  2534.         if bFound = TRUE then
  2535.             If m_bDebug = TRUE Then
  2536.                 _echo "Plotted  missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  2537.             End If
  2538.         else
  2539.             iMissing = iMissing + 1
  2540.             If m_bDebug = TRUE Then
  2541.                 _echo "Detected missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  2542.             End If
  2543.         end if
  2544.     Next iLoop
  2545.    
  2546. End Sub ' ShearRotate2
  2547.  
  2548. ' /////////////////////////////////////////////////////////////////////////////
  2549. ' Receives
  2550. ' FindMe (RotationType) = contains the starting location (.origx, .origy) to start looking from, and the value (.c) to write
  2551. ' angle1 (Integer) = angle we were rotating to, to determine direction to look in
  2552. ' iEmpty (Integer) = value to test against for empty
  2553. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  2554. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  2555. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  2556.  
  2557. ' Returns
  2558. ' FALSE if no empty spot was found
  2559. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  2560.  
  2561. Function FindEmptyShearRotationPoint2%(FindMe As RotationType, angle1 As Integer, iEmpty as Integer, destX as integer, destY as integer, NewArray() As RotationType)
  2562.     Dim bResult as Integer : bResult = FALSE
  2563.     Dim x As Integer
  2564.     Dim y As Integer
  2565.     Dim dirX As Integer
  2566.     Dim dirY As Integer
  2567.    
  2568.     destX = 0
  2569.     destY = 0
  2570.    
  2571.     ' Choose search direction depending on the angle
  2572.     If angle1 > 0 And angle1 < 90 Then
  2573.         dirX = 1
  2574.         dirY = -1
  2575.     ElseIf angle1 > 90 And angle1 < 180 Then
  2576.         dirX = 1
  2577.         dirY = 1
  2578.     ElseIf angle1 > 180 And angle1 < 270 Then
  2579.         dirX = -1
  2580.         dirY = 1
  2581.     ElseIf angle1 > 270 And angle1 < 360 Then
  2582.         dirX = -1
  2583.         dirY = -1
  2584.     Else
  2585.         dirX = 0
  2586.         dirY = 0
  2587.     End If
  2588.    
  2589.     If dirX <> 0 Then
  2590.         x = FindMe.origx
  2591.         y = FindMe.origy
  2592.         Do
  2593.             ' quit if we're out of bounds
  2594.             if x < LBound(NewArray, 1) then Exit Do
  2595.             if x > UBound(NewArray, 1) then Exit do
  2596.             if y < LBound(NewArray, 2) then Exit Do
  2597.             if y > UBound(NewArray, 2) then Exit do
  2598.            
  2599.             ' =============================================================================
  2600.             ' BEGIN PRIMARY SEARCH
  2601.             ' =============================================================================
  2602.             ' look along y axis for a blank spot
  2603.             destX = x
  2604.             destY = y + dirY
  2605.             if destX >= LBound(NewArray, 1) then
  2606.                 if destX <= UBound(NewArray, 1) then
  2607.                     if destY >= LBound(NewArray, 2) then
  2608.                         if destY <= UBound(NewArray, 2) then
  2609.                             if NewArray(destX, destY, 0).c = iEmpty then
  2610.                                 NewArray(destX, destY, 0).c = FindMe.c
  2611.                                 bResult = TRUE
  2612.                                 Exit Do
  2613.                             end if
  2614.                         end if
  2615.                     end if
  2616.                 end if
  2617.             end if
  2618.            
  2619.             ' look along x axis for a blank spot
  2620.             destX = x + dirX
  2621.             destY = y
  2622.             if destX >= LBound(NewArray, 1) then
  2623.                 if destX <= UBound(NewArray, 1) then
  2624.                     if destY >= LBound(NewArray, 2) then
  2625.                         if destY <= UBound(NewArray, 2) then
  2626.                             if NewArray(x + dirX, y, 0).c = iEmpty then
  2627.                                 NewArray(destX, destY, 0).c = FindMe.c
  2628.                                 bResult = TRUE
  2629.                                 Exit Do
  2630.                             end if
  2631.                         end if
  2632.                     end if
  2633.                 end if
  2634.             end if
  2635.            
  2636.             ' look diagonally for a blank spot
  2637.             destX = x + dirX
  2638.             destY = y + dirY
  2639.             if destX >= LBound(NewArray, 1) then
  2640.                 if destX <= UBound(NewArray, 1) then
  2641.                     if destY >= LBound(NewArray, 2) then
  2642.                         if destY <= UBound(NewArray, 2) then
  2643.                             if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  2644.                                 NewArray(destX, destY, 0).c = FindMe.c
  2645.                                 bResult = TRUE
  2646.                                 Exit Do
  2647.                             end if
  2648.                         end if
  2649.                     end if
  2650.                 end if
  2651.             end if
  2652.             ' =============================================================================
  2653.             ' END PRIMARY SEARCH
  2654.             ' =============================================================================
  2655.            
  2656.             ' =============================================================================
  2657.             ' BEGIN SECONDARY SEARCH
  2658.             ' =============================================================================
  2659. 'yoda
  2660.             ' =============================================================================
  2661.             ' END SECONDARY SEARCH
  2662.             ' =============================================================================
  2663.            
  2664.             ' Keep looking
  2665.             x = x + dirX
  2666.             y = y + dirY
  2667.         Loop
  2668.     End If
  2669.    
  2670.     ' Return result
  2671.     FindEmptyShearRotationPoint2% = bResult
  2672. End Sub ' FindEmptyShearRotationPoint2%
  2673.  
  2674. ' /////////////////////////////////////////////////////////////////////////////
  2675. ' Tries to correct for missing points.
  2676.  
  2677. ' Receives parameter sMap
  2678. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  2679.  
  2680. ' e.g. ShearRotate2Test1 TestSprite1$
  2681.  
  2682. Sub ShearRotate2Test1(sMap As String)
  2683.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2684.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2685.     'Dim sMap As String
  2686.     Dim D As Integer
  2687.     Dim D1 As Integer
  2688.     Dim in$
  2689.     Dim bFinished As Integer
  2690.     Dim iMissing As Integer
  2691.    
  2692.     ' GET A SHAPE TO BE ROTATED
  2693.     Cls
  2694.     Print "3 shear rotation based on code by leopardpm"
  2695.     'sMap = TestSprite1$
  2696.    
  2697.     ' CONVERT SHAPE TO ARRAY
  2698.     StringToRotationArray RoArray1(), sMap, "."
  2699.  
  2700.     ' GET START ANGLE
  2701.     D = 0
  2702.     Print
  2703.     Print "Rotated by " + cstr$(D) + " degrees:"
  2704.     Print RotationArrayToStringTest(RoArray1())
  2705.     Print
  2706.     Print "Type an angle (-360 to 360) to rotate to, "
  2707.     Print "or blank to increase by 1 degree, or q to quit."
  2708.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2709.     Print "Hold down <ENTER> to rotate continually."
  2710.     Input "Angle (q to quit)? ", in$
  2711.     If Len(in$) > 0 Then
  2712.         If IsNum%(in$) Then
  2713.             D1 = Val(in$)
  2714.         Else
  2715.             D1 = -500
  2716.         End If
  2717.     Else
  2718.         D1 = 1
  2719.     End If
  2720.  
  2721.     ' ROTATE TO EACH ANGLE
  2722.     If D1 >= -360 And D1 <= 360 Then
  2723.         bFinished = FALSE
  2724.         Do
  2725.             ' ROTATE CLOCKWISE
  2726.             For D = D1 To 360
  2727.                 Cls
  2728.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  2729.                 Print
  2730.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2731.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  2732.                
  2733.                 Print RotationArrayToStringTest(RoArray2())
  2734.                 Print
  2735.                
  2736.                 Print "Type an angle (-360 to 360) to rotate to, "
  2737.                 Print "or blank to increase by 1 degree, or q to quit."
  2738.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2739.                 Print "Hold down <ENTER> to rotate continually."
  2740.                 Input "Angle (q to quit)? ", in$
  2741.                 If Len(in$) > 0 Then
  2742.                     If IsNum%(in$) Then
  2743.                         D = Val(in$)
  2744.                         If D >= 0 And D <= 360 Then
  2745.                             D = D - 1
  2746.                         Else
  2747.                             bFinished = TRUE
  2748.                             Exit For
  2749.                         End If
  2750.                     Else
  2751.                         bFinished = TRUE
  2752.                         Exit For
  2753.                     End If
  2754.                 End If
  2755.             Next D
  2756.             If bFinished = TRUE Then Exit Do
  2757.            
  2758.             ' ROTATE COUNTER-CLOCKWISE
  2759.             For D = 360 To D1 Step -1
  2760.                 Cls
  2761.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  2762.                 Print
  2763.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2764.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  2765.                
  2766.                 Print RotationArrayToStringTest(RoArray2())
  2767.                 Print
  2768.  
  2769.                 Print "Type an angle (0 to 360) to rotate to, "
  2770.                 Print "or blank to increase by 1 degree, or q to quit."
  2771.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2772.                 Print "Hold down <ENTER> to rotate continually."
  2773.                 Input "Angle (q to quit)? ", in$
  2774.                 If Len(in$) > 0 Then
  2775.                     If IsNum%(in$) Then
  2776.                         D = Val(in$)
  2777.                         If D >= 0 And D <= 360 Then
  2778.                             D = D + 1
  2779.                         Else
  2780.                             bFinished = TRUE
  2781.                             Exit For
  2782.                         End If
  2783.                     Else
  2784.                         bFinished = TRUE
  2785.                         Exit For
  2786.                     End If
  2787.                 End If
  2788.             Next D
  2789.             If bFinished = TRUE Then Exit Do
  2790.         Loop
  2791.     End If
  2792. End Sub ' ShearRotate2Test1
  2793.  
  2794. ' /////////////////////////////////////////////////////////////////////////////
  2795. ' ShearRotate v3
  2796.  
  2797. ' Tries to fix the problem of 2 points resolving to the same coordinate
  2798. ' (one overwrites the other, which becomes "lost")
  2799. ' a little more accurately, using iDirection parameter
  2800. ' (which can be cClockwise or cCounterClockwise)
  2801. ' together with which quarter of the screen the point is in,
  2802.  
  2803. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  2804.  
  2805. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  2806.  
  2807. Sub ShearRotate3 ( _
  2808.         OldArray() As RotationType, _
  2809.         NewArray() As RotationType, _
  2810.         angle1 As Integer, _
  2811.         iDirection As Integer, _
  2812.         iEmpty As Integer, _
  2813.         iMissing As Integer)
  2814.        
  2815.     Const Pi = 4 * Atn(1)
  2816.    
  2817.     Dim angle As Integer
  2818.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2819.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2820.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2821.     Dim x As Integer
  2822.     Dim y As Integer
  2823.     Dim nangle As Integer
  2824.     Dim nx As Integer
  2825.     Dim ny As Integer
  2826.     Dim flipper As Integer
  2827.     Dim rotr As Double
  2828.     Dim shear1 As Double
  2829.     Dim shear2 As Double
  2830.     Dim clr As Integer
  2831.     Dim y1 As _Byte
  2832.     Dim xy1 As _Byte
  2833.     Dim fy As _Byte
  2834.     Dim fx As _Byte
  2835.     Dim in$
  2836.     Dim sLine As String
  2837.     ReDim arrLost(-1) As RotationType
  2838.     Dim iLoop As Integer
  2839.     Dim bFound As Integer
  2840.     Dim iScreenZone As Integer
  2841.         Dim iMidX As Integer
  2842.         Dim iMidY As Integer
  2843.        
  2844.     ' initialize new with empty
  2845.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2846.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2847.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2848.             NewArray(x, y, 0).origx = x
  2849.             NewArray(x, y, 0).origy = y
  2850.             NewArray(x, y, 0).c = iEmpty
  2851.         Next y
  2852.     Next x
  2853.    
  2854.         ' find midpoints
  2855.         iMidX = (UBound(OldArray, 1) - LBound(OldArray, 1)) / 2
  2856.         iMidY = (UBound(OldArray, 2) - LBound(OldArray, 2)) / 2
  2857.        
  2858.     ' angle is reversed
  2859.     angle = 360 - angle1
  2860.    
  2861.     ' Shearing each element 3 times in one shot
  2862.     nangle = angle
  2863.    
  2864.     ' this pre-processing portion basically rotates by 90 to get
  2865.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2866.     If angle > 45 And angle < 225 Then
  2867.         If angle < 135 Then
  2868.             nangle = angle - 90
  2869.         Else
  2870.             nangle = angle - 180
  2871.         End If
  2872.     End If
  2873.     If angle > 135 And angle < 315 Then
  2874.         If angle < 225 Then
  2875.             nangle = angle - 180
  2876.         Else
  2877.             nangle = angle - 270
  2878.         End If
  2879.     End If
  2880.     If nangle < 0 Then
  2881.         nangle = nangle + 360
  2882.     End If
  2883.     If nangle > 359 Then
  2884.         nangle = nangle - 360
  2885.     End If
  2886.    
  2887.     rotr = nangle * DtoR
  2888.     shear1 = Tan(rotr / 2) ' correct way
  2889.     shear2 = Sin(rotr)
  2890.    
  2891.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2892.     ' ***       all resolve to -45 degrees.
  2893.     ' ***       Fixed by changing < to <=
  2894.    
  2895.     'if angle >  45 and angle < 134 then
  2896.     If angle > 45 And angle <= 134 Then
  2897.         flipper = 1
  2898.     ElseIf angle > 134 And angle <= 224 Then
  2899.         flipper = 2
  2900.     ElseIf angle > 224 And angle <= 314 Then
  2901.         ' *** NOTE: this had a bug where this flipper was wrong
  2902.         '           Fixed by adding case 7
  2903.         'flipper = 3
  2904.         flipper = 7
  2905.     Else
  2906.         flipper = 0
  2907.     End If
  2908.    
  2909.     ' Here is where it needs some optimizing possibly... kinda slow...
  2910.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2911.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2912.            
  2913.                         ' find which part of screen the current point is in
  2914.                         if y > iMidY then
  2915.                                 ' bottom half of screen
  2916.                                 if x > iMidX then
  2917.                                         ' right half of screen
  2918.                                         iScreenZone = 2
  2919.                                 else
  2920.                                         ' left half of screen
  2921.                                         iScreenZone = 3
  2922.                                 end if
  2923.                         else
  2924.                                 ' top half of screen
  2925.                                 if x > iMidX then
  2926.                                         ' right half of screen
  2927.                                         iScreenZone = 1
  2928.                                 else
  2929.                                         ' left half of screen
  2930.                                         iScreenZone = 4
  2931.                                 end if
  2932.                         end if
  2933.                        
  2934.                         ' calculate directions
  2935.                         Select Case flipper
  2936.                 Case 1:
  2937.                     nx = -y
  2938.                     ny = x
  2939.                 Case 2:
  2940.                     nx = -x
  2941.                     ny = -y
  2942.                 Case 3:
  2943.                     nx = -y
  2944.                     ny = -x
  2945.                 Case 4:
  2946.                     nx = -x
  2947.                     ny = y
  2948.                 Case 5:
  2949.                     nx = x
  2950.                     ny = -y
  2951.                 Case 6:
  2952.                     nx = y
  2953.                     ny = x
  2954.                 Case 7:
  2955.                     nx = y
  2956.                     ny = -x
  2957.                 Case Else:
  2958.                     nx = x
  2959.                     ny = y
  2960.             End Select
  2961.            
  2962.             clr = OldArray(nx, ny, 0).c
  2963.            
  2964.             y1 = y * shear1
  2965.             xy1 = x + y1
  2966.             fy = (y - xy1 * shear2)
  2967.             fx = xy1 + fy * shear1
  2968.            
  2969.             If fx >= -16 And fx <= 16 Then
  2970.                 If fy >= -16 And fy <= 16 Then
  2971.                     ' only draw here if this spot is empty
  2972.                     if NewArray(fx, fy, 0).c = iEmpty then
  2973.                         NewArray(fx, fy, 0).c = clr
  2974.                         NewArray(fx, fy, 0).origx = fx
  2975.                         NewArray(fx, fy, 0).origy = fy
  2976.                     else
  2977.                         ' don't draw, but save it to a list to handle later
  2978.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  2979.                         arrLost(UBound(arrLost)).c = clr
  2980.                         arrLost(UBound(arrLost)).origx = fx
  2981.                         arrLost(UBound(arrLost)).origy = fy
  2982.                                                
  2983.                                                 ' preserve which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  2984.                                                 arrLost(UBound(arrLost)).z = iScreenZone
  2985.                     end if
  2986.                 End If
  2987.             End If
  2988.         Next x
  2989.     Next y
  2990.    
  2991.     ' try to place any points that would have overwritten to a spot nearby
  2992.     ' can nearby be determined by the direction of rotation  (iDirection)
  2993.         ' together with which quarter of the screen the point is in (iScreenZone)
  2994.     ' where we divide the screen up into 4 zones:
  2995.    
  2996.     ' --------------------------------------
  2997.     '|                   |                  |
  2998.     '| zone 4            | zone 1           |
  2999.     '|                   |                  |
  3000.     '|--------------------------------------|
  3001.     '|                   |                  |
  3002.     '| zone 3            | zone 2           |
  3003.     '|                   |                  |
  3004.     '|                   |                  |
  3005.     ' --------------------------------------
  3006.    
  3007.     ' in zone   rotation direction   search direction (y,x)
  3008.     ' -------   ------------------   ----------------------
  3009.     ' 1         clockwise            down + right
  3010.         ' 1         counter-clockwise    up   + left
  3011.     ' 2         clockwise            down + left
  3012.     ' 2         counter-clockwise    up   + right
  3013.     ' 3         clockwise            up   + left
  3014.     ' 3         counter-clockwise    down + right
  3015.     ' 4         clockwise            up   + right
  3016.     ' 4         counter-clockwise    down + left
  3017.    
  3018.     iMissing = 0
  3019.     For iLoop = 0 To UBound(arrLost)
  3020.         bFound = FindEmptyShearRotationPoint3%(arrLost(iLoop), iDirection, iEmpty, x, y, NewArray())
  3021.         if bFound = TRUE then
  3022.             If m_bDebug = TRUE Then
  3023.                 _echo "Plotted  missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3024.             End If
  3025.         else
  3026.             iMissing = iMissing + 1
  3027.             If m_bDebug = TRUE Then
  3028.                 _echo "Detected missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3029.             End If
  3030.         end if
  3031.     Next iLoop
  3032.    
  3033. End Sub ' ShearRotate3
  3034.  
  3035. ' /////////////////////////////////////////////////////////////////////////////
  3036. ' Looks for a new point
  3037. ' a little more accurately, using iDirection parameter
  3038. ' which can be cClockwise or cCounterClockwise.
  3039.  
  3040. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3041.  
  3042. ' Receives
  3043. ' FindMe (RotationType) = contains
  3044. '                         .origx, .origy = the starting location to start looking from,
  3045. '                         .z = which area of the screen the point is in
  3046. '                              (1=top right, 2=bottom right, 3=bottom left, 4=top left)
  3047. '                              to determine direction to look in
  3048. '                         .c = the value to write
  3049. ' iDirection (Integer) = direction of rotation, can be cClockwise or cCounterClockwise (constants must be declared globally)
  3050. ' iEmpty (Integer) = value to test against for empty
  3051. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  3052. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  3053. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  3054.  
  3055. ' Returns
  3056. ' FALSE if no empty spot was found
  3057. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  3058.  
  3059. Function FindEmptyShearRotationPoint3%(FindMe As RotationType, iDirection As Integer, iEmpty as Integer, destX as integer, destY as integer, NewArray() As RotationType)
  3060.     Dim bResult as Integer : bResult = FALSE
  3061.     Dim x As Integer
  3062.     Dim y As Integer
  3063.     Dim dirX As Integer
  3064.     Dim dirY As Integer
  3065.     Dim bContinue As Integer
  3066.        
  3067.         ' Initialize
  3068.     destX = 0
  3069.     destY = 0
  3070.     bContinue = TRUE
  3071.        
  3072.     ' Choose search direction based on the quadrant of the screen
  3073.         ' and the direction of rotation:
  3074.        
  3075.         ' iScreenZone   iDirection           search direction (y,x)
  3076.     ' -----------   ------------------   ----------------------
  3077.     ' 1             cClockwise           down + right ( 1, 1)
  3078.         ' 1             cCounterClockwise    up   + left  (-1,-1)
  3079.     ' 2             cClockwise           down + left  ( 1,-1)
  3080.     ' 2             cCounterClockwise    up   + right (-1, 1)
  3081.     ' 3             cClockwise           up   + left  (-1,-1)
  3082.     ' 3             cCounterClockwise    down + right ( 1, 1)
  3083.     ' 4             cClockwise           up   + right (-1, 1)
  3084.     ' 4             cCounterClockwise    down + left  ( 1,-1)
  3085.        
  3086.     If     FindMe.z = 1 And iDirection = cClockwise Then
  3087.         dirY = 1
  3088.         dirX = 1
  3089.     ElseIf FindMe.z = 1 And iDirection = cCounterClockwise Then
  3090.         dirY = -1
  3091.         dirX = -1
  3092.     ElseIf FindMe.z = 2 And iDirection = cClockwise Then
  3093.         dirY = 1
  3094.         dirX = -1
  3095.     ElseIf FindMe.z = 2 And iDirection = cCounterClockwise Then
  3096.         dirY = -1
  3097.         dirX = 1
  3098.     ElseIf FindMe.z = 3 And iDirection = cClockwise Then
  3099.         dirY = -1
  3100.         dirX = -1
  3101.     ElseIf FindMe.z = 3 And iDirection = cCounterClockwise Then
  3102.         dirY = 1
  3103.         dirX = 1
  3104.     ElseIf FindMe.z = 4 And iDirection = cClockwise Then
  3105.         dirY = -1
  3106.         dirX = 1
  3107.     ElseIf FindMe.z = 4 And iDirection = cCounterClockwise Then
  3108.         dirY = 1
  3109.         dirX = -1
  3110.     Else
  3111.         bContinue = FALSE
  3112.     End If
  3113.    
  3114.         ' Quit if we're out of bounds
  3115.     If bContinue = TRUE Then
  3116.                 bContinue = FALSE
  3117.         x = FindMe.origx
  3118.         y = FindMe.origy
  3119.                 if x >= LBound(NewArray, 1) then
  3120.                         if x <= UBound(NewArray, 1) then
  3121.                                 if y >= LBound(NewArray, 2) then
  3122.                                         if y <= UBound(NewArray, 2) then
  3123.                                                 bContinue = TRUE
  3124.                                         end if
  3125.                                 end if
  3126.                         end if
  3127.                 end if
  3128.         End If
  3129.        
  3130.         ' look along y axis for an available adjacent point
  3131.         If bContinue = TRUE Then
  3132.                 destX = x
  3133.                 destY = y + dirY
  3134.                 if destX >= LBound(NewArray, 1) then
  3135.                         if destX <= UBound(NewArray, 1) then
  3136.                                 if destY >= LBound(NewArray, 2) then
  3137.                                         if destY <= UBound(NewArray, 2) then
  3138.                                                 if NewArray(destX, destY, 0).c = iEmpty then
  3139.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3140.                                                         bResult = TRUE
  3141.                                                         bContinue = FALSE
  3142.                                                 end if
  3143.                                         end if
  3144.                                 end if
  3145.                         end if
  3146.                 end if
  3147.         end if
  3148.        
  3149.         ' look along x axis for an available adjacent point
  3150.         If bContinue = TRUE Then
  3151.                 destX = x + dirX
  3152.                 destY = y
  3153.                 if destX >= LBound(NewArray, 1) then
  3154.                         if destX <= UBound(NewArray, 1) then
  3155.                                 if destY >= LBound(NewArray, 2) then
  3156.                                         if destY <= UBound(NewArray, 2) then
  3157.                                                 if NewArray(x + dirX, y, 0).c = iEmpty then
  3158.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3159.                                                         bResult = TRUE
  3160.                                                         bContinue = FALSE
  3161.                                                 end if
  3162.                                         end if
  3163.                                 end if
  3164.                         end if
  3165.                 end if
  3166.         end if
  3167.        
  3168.         ' look diagonally for an available adjacent point
  3169.         If bContinue = TRUE Then
  3170.                 destX = x + dirX
  3171.                 destY = y + dirY
  3172.                 if destX >= LBound(NewArray, 1) then
  3173.                         if destX <= UBound(NewArray, 1) then
  3174.                                 if destY >= LBound(NewArray, 2) then
  3175.                                         if destY <= UBound(NewArray, 2) then
  3176.                                                 if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  3177.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3178.                                                         bResult = TRUE
  3179.                                                         bContinue = FALSE
  3180.                                                 end if
  3181.                                         end if
  3182.                                 end if
  3183.                         end if
  3184.                 end if
  3185.     End If
  3186.        
  3187.     ' Return result
  3188.     FindEmptyShearRotationPoint3% = bResult
  3189. End Sub ' FindEmptyShearRotationPoint3%
  3190.  
  3191. ' /////////////////////////////////////////////////////////////////////////////
  3192. ' Receives parameter sMap
  3193. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3194.  
  3195. ' e.g. ShearRotate3Test1 TestSprite1$
  3196.  
  3197. Sub ShearRotate3Test1(sMap As String)
  3198.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3199.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3200.     'Dim sMap As String
  3201.     Dim D As Integer
  3202.     Dim D1 As Integer
  3203.     Dim in$
  3204.     Dim bFinished As Integer
  3205.     Dim iMissing As Integer
  3206.    
  3207.     ' GET A SHAPE TO BE ROTATED
  3208.     Cls
  3209.     Print "3 shear rotation based on code by leopardpm"
  3210.     'sMap = TestSprite1$
  3211.    
  3212.     ' CONVERT SHAPE TO ARRAY
  3213.     StringToRotationArray RoArray1(), sMap, "."
  3214.  
  3215.     ' GET START ANGLE
  3216.     D = 0
  3217.     Print
  3218.     Print "Rotated by " + cstr$(D) + " degrees:"
  3219.     Print RotationArrayToStringTest(RoArray1())
  3220.     Print
  3221.     Print "Type an angle (-360 to 360) to rotate to, "
  3222.     Print "or blank to increase by 1 degree, or q to quit."
  3223.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3224.     Print "Hold down <ENTER> to rotate continually."
  3225.     Input "Angle (q to quit)? ", in$
  3226.     If Len(in$) > 0 Then
  3227.         If IsNum%(in$) Then
  3228.             D1 = Val(in$)
  3229.         Else
  3230.             D1 = -500
  3231.         End If
  3232.     Else
  3233.         D1 = 1
  3234.     End If
  3235.  
  3236.     ' ROTATE TO EACH ANGLE
  3237.     If D1 >= -360 And D1 <= 360 Then
  3238.         bFinished = FALSE
  3239.         Do
  3240.             ' ROTATE CLOCKWISE
  3241.             For D = D1 To 360
  3242.                 Cls
  3243.                                
  3244.                 ShearRotate3 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  3245.                 Print
  3246.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3247.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3248.                
  3249.                 Print RotationArrayToStringTest(RoArray2())
  3250.                 Print
  3251.                
  3252.                 Print "Type an angle (-360 to 360) to rotate to, "
  3253.                 Print "or blank to increase by 1 degree, or q to quit."
  3254.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3255.                 Print "Hold down <ENTER> to rotate continually."
  3256.                 Input "Angle (q to quit)? ", in$
  3257.                 If Len(in$) > 0 Then
  3258.                     If IsNum%(in$) Then
  3259.                         D = Val(in$)
  3260.                         If D >= 0 And D <= 360 Then
  3261.                             D = D - 1
  3262.                         Else
  3263.                             bFinished = TRUE
  3264.                             Exit For
  3265.                         End If
  3266.                     Else
  3267.                         bFinished = TRUE
  3268.                         Exit For
  3269.                     End If
  3270.                 End If
  3271.             Next D
  3272.             If bFinished = TRUE Then Exit Do
  3273.            
  3274.             ' ROTATE COUNTER-CLOCKWISE
  3275.             For D = 360 To D1 Step -1
  3276.                 Cls
  3277.                 ShearRotate3 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  3278.                 Print
  3279.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3280.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3281.                
  3282.                 Print RotationArrayToStringTest(RoArray2())
  3283.                 Print
  3284.  
  3285.                 Print "Type an angle (0 to 360) to rotate to, "
  3286.                 Print "or blank to increase by 1 degree, or q to quit."
  3287.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3288.                 Print "Hold down <ENTER> to rotate continually."
  3289.                 Input "Angle (q to quit)? ", in$
  3290.                 If Len(in$) > 0 Then
  3291.                     If IsNum%(in$) Then
  3292.                         D = Val(in$)
  3293.                         If D >= 0 And D <= 360 Then
  3294.                             D = D + 1
  3295.                         Else
  3296.                             bFinished = TRUE
  3297.                             Exit For
  3298.                         End If
  3299.                     Else
  3300.                         bFinished = TRUE
  3301.                         Exit For
  3302.                     End If
  3303.                 End If
  3304.             Next D
  3305.             If bFinished = TRUE Then Exit Do
  3306.         Loop
  3307.     End If
  3308. End Sub ' ShearRotate3Test1
  3309.  
  3310. ' /////////////////////////////////////////////////////////////////////////////
  3311. ' ShearRotate v4
  3312.  
  3313. ' Tries to fix the problem of 2 points resolving to the same coordinate
  3314. ' (one overwrites the other, which becomes "lost")
  3315. ' using a different approach, by just looking at the problem angles:
  3316. ' 30, 60, 120, 150, 210, 240, 300, 330 degrees
  3317.  
  3318. ' (which can be cClockwise or cCounterClockwise)
  3319. ' together with which quarter of the screen the point is in,
  3320.  
  3321. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3322.  
  3323. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  3324.  
  3325. Sub ShearRotate4 ( _
  3326.         OldArray() As RotationType, _
  3327.         NewArray() As RotationType, _
  3328.         angle1 As Integer, _
  3329.         iDirection As Integer, _
  3330.         iEmpty As Integer, _
  3331.         iMissing As Integer)
  3332.        
  3333.     Const Pi = 4 * Atn(1)
  3334.    
  3335.     Dim angle As Integer
  3336.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  3337.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  3338.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  3339.     Dim x As Integer
  3340.     Dim y As Integer
  3341.     Dim nangle As Integer
  3342.     Dim nx As Integer
  3343.     Dim ny As Integer
  3344.     Dim flipper As Integer
  3345.     Dim rotr As Double
  3346.     Dim shear1 As Double
  3347.     Dim shear2 As Double
  3348.     Dim clr As Integer
  3349.     Dim y1 As _Byte
  3350.     Dim xy1 As _Byte
  3351.     Dim fy As _Byte
  3352.     Dim fx As _Byte
  3353.     Dim in$
  3354.     Dim sLine As String
  3355.     ReDim arrLost(-1) As RotationType
  3356.     Dim iLoop As Integer
  3357.     Dim bFound As Integer
  3358.     Dim iScreenZone As Integer
  3359.         Dim iMidX As Integer
  3360.         Dim iMidY As Integer
  3361.        
  3362.     ' initialize new with empty
  3363.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3364.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3365.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3366.             NewArray(x, y, 0).origx = x
  3367.             NewArray(x, y, 0).origy = y
  3368.             NewArray(x, y, 0).c = iEmpty
  3369.         Next y
  3370.     Next x
  3371.    
  3372.         ' find midpoints
  3373.         iMidX = (UBound(OldArray, 1) - LBound(OldArray, 1)) / 2
  3374.         iMidY = (UBound(OldArray, 2) - LBound(OldArray, 2)) / 2
  3375.        
  3376.     ' angle is reversed
  3377.     angle = 360 - angle1
  3378.    
  3379.     ' Shearing each element 3 times in one shot
  3380.     nangle = angle
  3381.    
  3382.     ' this pre-processing portion basically rotates by 90 to get
  3383.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  3384.     If angle > 45 And angle < 225 Then
  3385.         If angle < 135 Then
  3386.             nangle = angle - 90
  3387.         Else
  3388.             nangle = angle - 180
  3389.         End If
  3390.     End If
  3391.     If angle > 135 And angle < 315 Then
  3392.         If angle < 225 Then
  3393.             nangle = angle - 180
  3394.         Else
  3395.             nangle = angle - 270
  3396.         End If
  3397.     End If
  3398.     If nangle < 0 Then
  3399.         nangle = nangle + 360
  3400.     End If
  3401.     If nangle > 359 Then
  3402.         nangle = nangle - 360
  3403.     End If
  3404.    
  3405.     rotr = nangle * DtoR
  3406.     shear1 = Tan(rotr / 2) ' correct way
  3407.     shear2 = Sin(rotr)
  3408.    
  3409.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  3410.     ' ***       all resolve to -45 degrees.
  3411.     ' ***       Fixed by changing < to <=
  3412.    
  3413.     'if angle >  45 and angle < 134 then
  3414.     If angle > 45 And angle <= 134 Then
  3415.         flipper = 1
  3416.     ElseIf angle > 134 And angle <= 224 Then
  3417.         flipper = 2
  3418.     ElseIf angle > 224 And angle <= 314 Then
  3419.         ' *** NOTE: this had a bug where this flipper was wrong
  3420.         '           Fixed by adding case 7
  3421.         'flipper = 3
  3422.         flipper = 7
  3423.     Else
  3424.         flipper = 0
  3425.     End If
  3426.    
  3427.     ' Here is where it needs some optimizing possibly... kinda slow...
  3428.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3429.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3430.            
  3431.                         ' find which part of screen the current point is in
  3432.                         if y > iMidY then
  3433.                                 ' bottom half of screen
  3434.                                 if x > iMidX then
  3435.                                         ' right half of screen
  3436.                                         iScreenZone = 2
  3437.                                 else
  3438.                                         ' left half of screen
  3439.                                         iScreenZone = 3
  3440.                                 end if
  3441.                         else
  3442.                                 ' top half of screen
  3443.                                 if x > iMidX then
  3444.                                         ' right half of screen
  3445.                                         iScreenZone = 1
  3446.                                 else
  3447.                                         ' left half of screen
  3448.                                         iScreenZone = 4
  3449.                                 end if
  3450.                         end if
  3451.                        
  3452.                         ' calculate directions
  3453.                         Select Case flipper
  3454.                 Case 1:
  3455.                     nx = -y
  3456.                     ny = x
  3457.                 Case 2:
  3458.                     nx = -x
  3459.                     ny = -y
  3460.                 Case 3:
  3461.                     nx = -y
  3462.                     ny = -x
  3463.                 Case 4:
  3464.                     nx = -x
  3465.                     ny = y
  3466.                 Case 5:
  3467.                     nx = x
  3468.                     ny = -y
  3469.                 Case 6:
  3470.                     nx = y
  3471.                     ny = x
  3472.                 Case 7:
  3473.                     nx = y
  3474.                     ny = -x
  3475.                 Case Else:
  3476.                     nx = x
  3477.                     ny = y
  3478.             End Select
  3479.            
  3480.             clr = OldArray(nx, ny, 0).c
  3481.            
  3482.             y1 = y * shear1
  3483.             xy1 = x + y1
  3484.             fy = (y - xy1 * shear2)
  3485.             fx = xy1 + fy * shear1
  3486.            
  3487.             If fx >= -16 And fx <= 16 Then
  3488.                 If fy >= -16 And fy <= 16 Then
  3489.                     ' only draw here if this spot is empty
  3490.                     if NewArray(fx, fy, 0).c = iEmpty then
  3491.                         NewArray(fx, fy, 0).c = clr
  3492.                         NewArray(fx, fy, 0).origx = fx
  3493.                         NewArray(fx, fy, 0).origy = fy
  3494.                     else
  3495.                         ' don't draw, but save it to a list to handle later
  3496.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  3497.                         arrLost(UBound(arrLost)).c = clr
  3498.                         arrLost(UBound(arrLost)).origx = fx
  3499.                         arrLost(UBound(arrLost)).origy = fy
  3500.                                                
  3501.                                                 ' preserve which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  3502.                                                 arrLost(UBound(arrLost)).z = iScreenZone
  3503.                     end if
  3504.                 End If
  3505.             End If
  3506.         Next x
  3507.     Next y
  3508.    
  3509.     ' try to place any points that would have overwritten to a spot nearby
  3510.     ' can nearby be determined by the direction of rotation  (iDirection)
  3511.         ' together with which quarter of the screen the point is in (iScreenZone)
  3512.     ' where we divide the screen up into 4 zones:
  3513.    
  3514.     ' --------------------------------------
  3515.     '|                   |                  |
  3516.     '| zone 4            | zone 1           |
  3517.     '|                   |                  |
  3518.     '|--------------------------------------|
  3519.     '|                   |                  |
  3520.     '| zone 3            | zone 2           |
  3521.     '|                   |                  |
  3522.     '|                   |                  |
  3523.     ' --------------------------------------
  3524.    
  3525.     ' in zone   rotation direction   search direction (y,x)
  3526.     ' -------   ------------------   ----------------------
  3527.     ' 1         clockwise            down + right
  3528.         ' 1         counter-clockwise    up   + left
  3529.     ' 2         clockwise            down + left
  3530.     ' 2         counter-clockwise    up   + right
  3531.     ' 3         clockwise            up   + left
  3532.     ' 3         counter-clockwise    down + right
  3533.     ' 4         clockwise            up   + right
  3534.     ' 4         counter-clockwise    down + left
  3535.    
  3536.         if IsProblemAngle%(angle1) then
  3537.                 iMissing = 0
  3538.                 For iLoop = 0 To UBound(arrLost)
  3539.                         bFound = FindEmptyShearRotationPoint4%(arrLost(iLoop), iDirection, iEmpty, x, y, NewArray())
  3540.                         if bFound = TRUE then
  3541.                                 If m_bDebug = TRUE Then
  3542.                                         _echo "Plotted  missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3543.                                 End If
  3544.                         else
  3545.                                 iMissing = iMissing + 1
  3546.                                 If m_bDebug = TRUE Then
  3547.                                         _echo "Detected missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3548.                                 End If
  3549.                         end if
  3550.                 Next iLoop
  3551.     end if
  3552. End Sub ' ShearRotate4
  3553.  
  3554. ' div: int1% = num1% \ den1%
  3555. ' mod: rem1% = num1% MOD den1%
  3556. function IsProblemAngle%(angle as integer)
  3557.         dim bResult as integer : bResult = FALSE
  3558.         Dim i%
  3559.         For i% = 0 To 360 Step 30
  3560.                 If i% Mod 90 <> 0 Then
  3561.                         if angle = i% then
  3562.                                 bResult = TRUE
  3563.                                 exit for
  3564.                         end if
  3565.                 End If
  3566.         Next i%
  3567.         IsProblemAngle% = bResult
  3568. end function ' IsProblemAngle%
  3569.  
  3570. ' /////////////////////////////////////////////////////////////////////////////
  3571. ' Looks for a new point
  3572. ' a little more accurately, using iDirection parameter
  3573. ' which can be cClockwise or cCounterClockwise.
  3574.  
  3575. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3576.  
  3577. ' Receives
  3578. ' FindMe (RotationType) = contains
  3579. '                         .origx, .origy = the starting location to start looking from,
  3580. '                         .z = which area of the screen the point is in
  3581. '                              (1=top right, 2=bottom right, 3=bottom left, 4=top left)
  3582. '                              to determine direction to look in
  3583. '                         .c = the value to write
  3584. ' iDirection (Integer) = direction of rotation, can be cClockwise or cCounterClockwise (constants must be declared globally)
  3585. ' iEmpty (Integer) = value to test against for empty
  3586. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  3587. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  3588. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  3589.  
  3590. ' Returns
  3591. ' FALSE if no empty spot was found
  3592. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  3593.  
  3594. Function FindEmptyShearRotationPoint4%(FindMe As RotationType, iDirection As Integer, iEmpty as Integer, destX as integer, destY as integer, NewArray() As RotationType)
  3595.     Dim bResult as Integer : bResult = FALSE
  3596.     Dim x As Integer
  3597.     Dim y As Integer
  3598.     Dim dirX As Integer
  3599.     Dim dirY As Integer
  3600.     Dim bContinue As Integer
  3601.        
  3602.         ' Initialize
  3603.     destX = 0
  3604.     destY = 0
  3605.     bContinue = TRUE
  3606.        
  3607.     ' Choose search direction based on the quadrant of the screen
  3608.         ' and the direction of rotation:
  3609.        
  3610.         ' iScreenZone   iDirection           search direction (y,x)
  3611.     ' -----------   ------------------   ----------------------
  3612.     ' 1             cClockwise           down + right ( 1, 1)
  3613.         ' 1             cCounterClockwise    up   + left  (-1,-1)
  3614.     ' 2             cClockwise           down + left  ( 1,-1)
  3615.     ' 2             cCounterClockwise    up   + right (-1, 1)
  3616.     ' 3             cClockwise           up   + left  (-1,-1)
  3617.     ' 3             cCounterClockwise    down + right ( 1, 1)
  3618.     ' 4             cClockwise           up   + right (-1, 1)
  3619.     ' 4             cCounterClockwise    down + left  ( 1,-1)
  3620.        
  3621.     If     FindMe.z = 1 And iDirection = cClockwise Then
  3622.         dirY = 1
  3623.         dirX = 1
  3624.     ElseIf FindMe.z = 1 And iDirection = cCounterClockwise Then
  3625.         dirY = -1
  3626.         dirX = -1
  3627.     ElseIf FindMe.z = 2 And iDirection = cClockwise Then
  3628.         dirY = 1
  3629.         dirX = -1
  3630.     ElseIf FindMe.z = 2 And iDirection = cCounterClockwise Then
  3631.         dirY = -1
  3632.         dirX = 1
  3633.     ElseIf FindMe.z = 3 And iDirection = cClockwise Then
  3634.         dirY = -1
  3635.         dirX = -1
  3636.     ElseIf FindMe.z = 3 And iDirection = cCounterClockwise Then
  3637.         dirY = 1
  3638.         dirX = 1
  3639.     ElseIf FindMe.z = 4 And iDirection = cClockwise Then
  3640.         dirY = -1
  3641.         dirX = 1
  3642.     ElseIf FindMe.z = 4 And iDirection = cCounterClockwise Then
  3643.         dirY = 1
  3644.         dirX = -1
  3645.     Else
  3646.         bContinue = FALSE
  3647.     End If
  3648.    
  3649.         ' Quit if we're out of bounds
  3650.     If bContinue = TRUE Then
  3651.                 bContinue = FALSE
  3652.         x = FindMe.origx
  3653.         y = FindMe.origy
  3654.                 if x >= LBound(NewArray, 1) then
  3655.                         if x <= UBound(NewArray, 1) then
  3656.                                 if y >= LBound(NewArray, 2) then
  3657.                                         if y <= UBound(NewArray, 2) then
  3658.                                                 bContinue = TRUE
  3659.                                         end if
  3660.                                 end if
  3661.                         end if
  3662.                 end if
  3663.         End If
  3664.        
  3665.         ' look along y axis for an available adjacent point
  3666.         If bContinue = TRUE Then
  3667.                 destX = x
  3668.                 destY = y + dirY
  3669.                 if destX >= LBound(NewArray, 1) then
  3670.                         if destX <= UBound(NewArray, 1) then
  3671.                                 if destY >= LBound(NewArray, 2) then
  3672.                                         if destY <= UBound(NewArray, 2) then
  3673.                                                 if NewArray(destX, destY, 0).c = iEmpty then
  3674.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3675.                                                         bResult = TRUE
  3676.                                                         bContinue = FALSE
  3677.                                                 end if
  3678.                                         end if
  3679.                                 end if
  3680.                         end if
  3681.                 end if
  3682.         end if
  3683.        
  3684.         ' look along x axis for an available adjacent point
  3685.         If bContinue = TRUE Then
  3686.                 destX = x + dirX
  3687.                 destY = y
  3688.                 if destX >= LBound(NewArray, 1) then
  3689.                         if destX <= UBound(NewArray, 1) then
  3690.                                 if destY >= LBound(NewArray, 2) then
  3691.                                         if destY <= UBound(NewArray, 2) then
  3692.                                                 if NewArray(x + dirX, y, 0).c = iEmpty then
  3693.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3694.                                                         bResult = TRUE
  3695.                                                         bContinue = FALSE
  3696.                                                 end if
  3697.                                         end if
  3698.                                 end if
  3699.                         end if
  3700.                 end if
  3701.         end if
  3702.        
  3703.         ' look diagonally for an available adjacent point
  3704.         If bContinue = TRUE Then
  3705.                 destX = x + dirX
  3706.                 destY = y + dirY
  3707.                 if destX >= LBound(NewArray, 1) then
  3708.                         if destX <= UBound(NewArray, 1) then
  3709.                                 if destY >= LBound(NewArray, 2) then
  3710.                                         if destY <= UBound(NewArray, 2) then
  3711.                                                 if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  3712.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3713.                                                         bResult = TRUE
  3714.                                                         bContinue = FALSE
  3715.                                                 end if
  3716.                                         end if
  3717.                                 end if
  3718.                         end if
  3719.                 end if
  3720.     End If
  3721.        
  3722. '       ' look (in the opposite direction) along y axis for an available adjacent point
  3723. '       If bContinue = TRUE Then
  3724. '               destX = x
  3725. '               destY = y - dirY
  3726. '               if destX >= LBound(NewArray, 1) then
  3727. '                       if destX <= UBound(NewArray, 1) then
  3728. '                               if destY >= LBound(NewArray, 2) then
  3729. '                                       if destY <= UBound(NewArray, 2) then
  3730. '                                               if NewArray(destX, destY, 0).c = iEmpty then
  3731. '                                                       NewArray(destX, destY, 0).c = FindMe.c
  3732. '                                                       bResult = TRUE
  3733. '                                                       bContinue = FALSE
  3734. '                                               end if
  3735. '                                       end if
  3736. '                               end if
  3737. '                       end if
  3738. '               end if
  3739. '       end if
  3740. '      
  3741. '       ' look (in the opposite direction) along x axis for an available adjacent point
  3742. '       If bContinue = TRUE Then
  3743. '               destX = x - dirX
  3744. '               destY = y
  3745. '               if destX >= LBound(NewArray, 1) then
  3746. '                       if destX <= UBound(NewArray, 1) then
  3747. '                               if destY >= LBound(NewArray, 2) then
  3748. '                                       if destY <= UBound(NewArray, 2) then
  3749. '                                               if NewArray(x + dirX, y, 0).c = iEmpty then
  3750. '                                                       NewArray(destX, destY, 0).c = FindMe.c
  3751. '                                                       bResult = TRUE
  3752. '                                                       bContinue = FALSE
  3753. '                                               end if
  3754. '                                       end if
  3755. '                               end if
  3756. '                       end if
  3757. '               end if
  3758. '       end if
  3759. '      
  3760. '       ' look (in the opposite direction) diagonally for an available adjacent point
  3761. '       If bContinue = TRUE Then
  3762. '               destX = x - dirX
  3763. '               destY = y - dirY
  3764. '               if destX >= LBound(NewArray, 1) then
  3765. '                       if destX <= UBound(NewArray, 1) then
  3766. '                               if destY >= LBound(NewArray, 2) then
  3767. '                                       if destY <= UBound(NewArray, 2) then
  3768. '                                               if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  3769. '                                                       NewArray(destX, destY, 0).c = FindMe.c
  3770. '                                                       bResult = TRUE
  3771. '                                                       bContinue = FALSE
  3772. '                                               end if
  3773. '                                       end if
  3774. '                               end if
  3775. '                       end if
  3776. '               end if
  3777. '    End If
  3778.        
  3779.     ' Return result
  3780.     FindEmptyShearRotationPoint4% = bResult
  3781. End Sub ' FindEmptyShearRotationPoint4%
  3782.  
  3783. ' /////////////////////////////////////////////////////////////////////////////
  3784. ' Tries to correct for missing points with improved logic v3
  3785.  
  3786. ' Receives parameter sMap
  3787. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3788.  
  3789. ' e.g. ShearRotate4Test1 TestSprite1$
  3790.  
  3791. Sub ShearRotate4Test1(sMap As String)
  3792.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3793.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3794.     'Dim sMap As String
  3795.     Dim D As Integer
  3796.     Dim D1 As Integer
  3797.     Dim in$
  3798.     Dim bFinished As Integer
  3799.     Dim iMissing As Integer
  3800.    
  3801.     ' GET A SHAPE TO BE ROTATED
  3802.     Cls
  3803.     Print "3 shear rotation based on code by leopardpm"
  3804.     'sMap = TestSprite1$
  3805.    
  3806.     ' CONVERT SHAPE TO ARRAY
  3807.     StringToRotationArray RoArray1(), sMap, "."
  3808.  
  3809.     ' GET START ANGLE
  3810.     D = 0
  3811.     Print
  3812.     Print "Rotated by " + cstr$(D) + " degrees:"
  3813.     Print RotationArrayToStringTest(RoArray1())
  3814.     Print
  3815.     Print "Type an angle (-360 to 360) to rotate to, "
  3816.     Print "or blank to increase by 1 degree, or q to quit."
  3817.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3818.     Print "Hold down <ENTER> to rotate continually."
  3819.     Input "Angle (q to quit)? ", in$
  3820.     If Len(in$) > 0 Then
  3821.         If IsNum%(in$) Then
  3822.             D1 = Val(in$)
  3823.         Else
  3824.             D1 = -500
  3825.         End If
  3826.     Else
  3827.         D1 = 1
  3828.     End If
  3829.  
  3830.     ' ROTATE TO EACH ANGLE
  3831.     If D1 >= -360 And D1 <= 360 Then
  3832.         bFinished = FALSE
  3833.         Do
  3834.             ' ROTATE CLOCKWISE
  3835.             For D = D1 To 360
  3836.                 Cls
  3837.                                
  3838.                 ShearRotate4 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  3839.                 Print
  3840.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3841.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3842.                
  3843.                 Print RotationArrayToStringTest(RoArray2())
  3844.                 Print
  3845.                
  3846.                 Print "Type an angle (-360 to 360) to rotate to, "
  3847.                 Print "or blank to increase by 1 degree, or q to quit."
  3848.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3849.                 Print "Hold down <ENTER> to rotate continually."
  3850.                 Input "Angle (q to quit)? ", in$
  3851.                 If Len(in$) > 0 Then
  3852.                     If IsNum%(in$) Then
  3853.                         D = Val(in$)
  3854.                         If D >= 0 And D <= 360 Then
  3855.                             D = D - 1
  3856.                         Else
  3857.                             bFinished = TRUE
  3858.                             Exit For
  3859.                         End If
  3860.                     Else
  3861.                         bFinished = TRUE
  3862.                         Exit For
  3863.                     End If
  3864.                 End If
  3865.             Next D
  3866.             If bFinished = TRUE Then Exit Do
  3867.            
  3868.             ' ROTATE COUNTER-CLOCKWISE
  3869.             For D = 360 To D1 Step -1
  3870.                 Cls
  3871.                 ShearRotate4 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  3872.                 Print
  3873.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3874.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3875.                
  3876.                 Print RotationArrayToStringTest(RoArray2())
  3877.                 Print
  3878.  
  3879.                 Print "Type an angle (0 to 360) to rotate to, "
  3880.                 Print "or blank to increase by 1 degree, or q to quit."
  3881.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3882.                 Print "Hold down <ENTER> to rotate continually."
  3883.                 Input "Angle (q to quit)? ", in$
  3884.                 If Len(in$) > 0 Then
  3885.                     If IsNum%(in$) Then
  3886.                         D = Val(in$)
  3887.                         If D >= 0 And D <= 360 Then
  3888.                             D = D + 1
  3889.                         Else
  3890.                             bFinished = TRUE
  3891.                             Exit For
  3892.                         End If
  3893.                     Else
  3894.                         bFinished = TRUE
  3895.                         Exit For
  3896.                     End If
  3897.                 End If
  3898.             Next D
  3899.             If bFinished = TRUE Then Exit Do
  3900.         Loop
  3901.     End If
  3902. End Sub ' ShearRotate4Test1
  3903.  
  3904. ' /////////////////////////////////////////////////////////////////////////////
  3905.  
  3906. Function TestSprite1$
  3907.     Dim m$
  3908.     m$ = ""
  3909.     '                   11111111112222222222333
  3910.     '          12345678901234567890123456789012
  3911.     m$ = m$ + "11111111111111111111111111111111" + Chr$(13) ' 1
  3912.     m$ = m$ + "4..............................2" + Chr$(13) ' 2
  3913.     m$ = m$ + "4....##.....#######.....####...2" + Chr$(13) ' 3
  3914.     m$ = m$ + "4...####....##...###...######..2" + Chr$(13) ' 4
  3915.     m$ = m$ + "4..##..##...##...###..##....##.2" + Chr$(13) ' 5
  3916.     m$ = m$ + "4.##....##..#######...##.......2" + Chr$(13) ' 6
  3917.     m$ = m$ + "4.########..#######...##.......2" + Chr$(13) ' 7
  3918.     m$ = m$ + "4.########..##...###..##....##.2" + Chr$(13) ' 8
  3919.     m$ = m$ + "4.##....##..##...###...######..2" + Chr$(13) ' 9
  3920.     m$ = m$ + "4.##....##..#######.....####...2" + Chr$(13) ' 10
  3921.     m$ = m$ + "4..............................2" + Chr$(13) ' 11
  3922.     m$ = m$ + "4..............................2" + Chr$(13) ' 12
  3923.     m$ = m$ + "4..ABBBBBBBBBBBBBBBBBBBBBBBBC..2" + Chr$(13) ' 13
  3924.     m$ = m$ + "4..A...........EE...........C..2" + Chr$(13) ' 14
  3925.     m$ = m$ + "4..A..........FFFF..........C..2" + Chr$(13) ' 15
  3926.     m$ = m$ + "4..A.........GGGGGG.........C..2" + Chr$(13) ' 16
  3927.     m$ = m$ + "4..A........HHHHHHHH........C..2" + Chr$(13) ' 17
  3928.     m$ = m$ + "4..A.......IIIIIIIIII.......C..2" + Chr$(13) ' 18
  3929.     m$ = m$ + "4..A......JJJJJJJJJJJJ......C..2" + Chr$(13) ' 19
  3930.     m$ = m$ + "4..DDDDDDDDDDDDDDDDDDDDDDDDDC..2" + Chr$(13) ' 20
  3931.     m$ = m$ + "4..............................2" + Chr$(13) ' 21
  3932.     m$ = m$ + "4..............................2" + Chr$(13) ' 22
  3933.     m$ = m$ + "4.######....########..########.2" + Chr$(13) ' 23
  3934.     m$ = m$ + "4.#######...########..########.2" + Chr$(13) ' 24
  3935.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 25
  3936.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 26
  3937.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 27
  3938.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 28
  3939.     m$ = m$ + "4.#######...##........##.......2" + Chr$(13) ' 29
  3940.     m$ = m$ + "4.######....########..##.......2" + Chr$(13) ' 30
  3941.     m$ = m$ + "4..............................2" + Chr$(13) ' 31
  3942.     m$ = m$ + "33333333333333333333333333333332" + Chr$(13) ' 32
  3943.     TestSprite1$ = m$
  3944. End Function ' TestSprite1$
  3945.  
  3946. ' /////////////////////////////////////////////////////////////////////////////
  3947.  
  3948. Function TestSprite2$
  3949.     Dim m$
  3950.     m$ = ""
  3951.     '                   11111111112222222222333
  3952.     '          12345678901234567890123456789012
  3953.     m$ = m$ + "...............AA..............." + Chr$(13) ' 1
  3954.     m$ = m$ + "..............//BB.............." + Chr$(13) ' 2
  3955.     m$ = m$ + ".............??..CC............." + Chr$(13) ' 3
  3956.     m$ = m$ + "............==....DD............" + Chr$(13) ' 4
  3957.     m$ = m$ + "...........++......EE..........." + Chr$(13) ' 5
  3958.     m$ = m$ + "..........&&........FF.........." + Chr$(13) ' 6
  3959.     m$ = m$ + ".........zz..........GG........." + Chr$(13) ' 7
  3960.     m$ = m$ + "........yy............HH........" + Chr$(13) ' 8
  3961.     m$ = m$ + ".......xx..............II......." + Chr$(13) ' 9
  3962.     m$ = m$ + "......ww................JJ......" + Chr$(13) ' 10
  3963.     m$ = m$ + ".....vv..................KK....." + Chr$(13) ' 11
  3964.     m$ = m$ + "....uu....................LL...." + Chr$(13) ' 12
  3965.     m$ = m$ + "...tt......DDAAAAAAA.......MM..." + Chr$(13) ' 13
  3966.     m$ = m$ + "..ss.......DDAAAAAAA........NN.." + Chr$(13) ' 14
  3967.     m$ = m$ + ".rr........DD.....BB.........OO." + Chr$(13) ' 15
  3968.     m$ = m$ + "qq.........DD.....BB..........PP" + Chr$(13) ' 16
  3969.     m$ = m$ + "pp.........DD.....BB..........QQ" + Chr$(13) ' 17
  3970.     m$ = m$ + ".oo........DD.....BB.........RR." + Chr$(13) ' 18
  3971.     m$ = m$ + "..nn.......CCCCCCCBB........SS.." + Chr$(13) ' 19
  3972.     m$ = m$ + "...mm......CCCCCCCBB.......TT..." + Chr$(13) ' 20
  3973.     m$ = m$ + "....ll....................UU...." + Chr$(13) ' 21
  3974.     m$ = m$ + ".....kk..................VV....." + Chr$(13) ' 22
  3975.     m$ = m$ + "......jj................WW......" + Chr$(13) ' 23
  3976.     m$ = m$ + ".......ii..............XX......." + Chr$(13) ' 24
  3977.     m$ = m$ + "........hh............YY........" + Chr$(13) ' 25
  3978.     m$ = m$ + ".........gg..........ZZ........." + Chr$(13) ' 26
  3979.     m$ = m$ + "..........ff........@@.........." + Chr$(13) ' 27
  3980.     m$ = m$ + "...........ee......##..........." + Chr$(13) ' 28
  3981.     m$ = m$ + "............dd....$$............" + Chr$(13) ' 29
  3982.     m$ = m$ + ".............cc..%%............." + Chr$(13) ' 30
  3983.     m$ = m$ + "..............bb\\.............." + Chr$(13) ' 31
  3984.     m$ = m$ + "...............aa..............." + Chr$(13) ' 32
  3985.     TestSprite2$ = m$
  3986. End Function ' TestSprite2$
  3987.  
  3988. ' /////////////////////////////////////////////////////////////////////////////
  3989.  
  3990. Function PetrText1$
  3991.     Dim m$
  3992.     m$ = ""
  3993.     '                   11111111112222222222333
  3994.     '          12345678901234567890123456789012
  3995.     m$ = m$ + "................................" + Chr$(13) ' 1
  3996.     m$ = m$ + "................................" + Chr$(13) ' 2
  3997.     m$ = m$ + "................................" + Chr$(13) ' 3
  3998.     m$ = m$ + "................................" + Chr$(13) ' 4
  3999.     m$ = m$ + "................................" + Chr$(13) ' 5
  4000.     m$ = m$ + "................................" + Chr$(13) ' 6
  4001.     m$ = m$ + "................................" + Chr$(13) ' 7
  4002.     m$ = m$ + "................................" + Chr$(13) ' 8
  4003.     m$ = m$ + "................................" + Chr$(13) ' 9
  4004.     m$ = m$ + "................................" + Chr$(13) ' 10
  4005.     m$ = m$ + "................................" + Chr$(13) ' 11
  4006.     m$ = m$ + "................................" + Chr$(13) ' 12
  4007.     m$ = m$ + "................................" + Chr$(13) ' 13
  4008.     m$ = m$ + "................................" + Chr$(13) ' 14
  4009.     m$ = m$ + "....It's a SCREEN resolution?..." + Chr$(13) ' 15
  4010.     m$ = m$ + "................................" + Chr$(13) ' 16
  4011.     m$ = m$ + "................................" + Chr$(13) ' 17
  4012.     m$ = m$ + "................................" + Chr$(13) ' 18
  4013.     m$ = m$ + "................................" + Chr$(13) ' 19
  4014.     m$ = m$ + "................................" + Chr$(13) ' 20
  4015.     m$ = m$ + "................................" + Chr$(13) ' 21
  4016.     m$ = m$ + "................................" + Chr$(13) ' 22
  4017.     m$ = m$ + "................................" + Chr$(13) ' 23
  4018.     m$ = m$ + "................................" + Chr$(13) ' 24
  4019.     m$ = m$ + "................................" + Chr$(13) ' 25
  4020.     m$ = m$ + "................................" + Chr$(13) ' 26
  4021.     m$ = m$ + "................................" + Chr$(13) ' 27
  4022.     m$ = m$ + "................................" + Chr$(13) ' 28
  4023.     m$ = m$ + "................................" + Chr$(13) ' 29
  4024.     m$ = m$ + "................................" + Chr$(13) ' 30
  4025.     m$ = m$ + "................................" + Chr$(13) ' 31
  4026.     m$ = m$ + "................................" + Chr$(13) ' 32
  4027.     PetrText1$ = m$
  4028. End Function ' PetrText1$
  4029.  
  4030. ' /////////////////////////////////////////////////////////////////////////////
  4031.  
  4032. Function ArrayToString$ (MyArray( 1 To 32 , 1 To 32) As String)
  4033.     Dim MyString As String
  4034.     Dim iY As Integer
  4035.     Dim iX As Integer
  4036.     Dim sLine As String
  4037.     MyString = ""
  4038.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  4039.         sLine = ""
  4040.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  4041.             sLine = sLine + MyArray(iY, iX)
  4042.         Next iX
  4043.         MyString = MyString + sLine + Chr$(13)
  4044.     Next iY
  4045.     ArrayToString$ = MyString
  4046. End Function ' ArrayToString$
  4047.  
  4048. ' /////////////////////////////////////////////////////////////////////////////
  4049.  
  4050. Function ArrayToStringTest$ (MyArray() As String)
  4051.     Dim MyString As String
  4052.     Dim iY As Integer
  4053.     Dim iX As Integer
  4054.     Dim sLine As String
  4055.     MyString = ""
  4056.  
  4057.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  4058.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  4059.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  4060.         sLine = ""
  4061.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  4062.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  4063.             sLine = sLine + MyArray(iY, iX)
  4064.         Next iX
  4065.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  4066.         MyString = MyString + sLine + Chr$(13)
  4067.     Next iY
  4068.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  4069.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  4070.     ArrayToStringTest$ = MyString
  4071. End Function ' ArrayToStringTest$
  4072.  
  4073. ' /////////////////////////////////////////////////////////////////////////////
  4074.  
  4075. Function RotationArrayToStringTest$ (RoArray() As RotationType)
  4076.     Dim MyString As String
  4077.     Dim iY As Integer
  4078.     Dim iX As Integer
  4079.     Dim sLine As String
  4080.     MyString = ""
  4081.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  4082.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  4083.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  4084.     For iY = LBound(RoArray, 1) To UBound(RoArray, 1)
  4085.         sLine = ""
  4086.         sLine = sLine + Right$("    " + cstr$(iY), 3)
  4087.         For iX = LBound(RoArray, 2) To UBound(RoArray, 2)
  4088.             sLine = sLine + Chr$(RoArray(iX, iY, 0).c)
  4089.         Next iX
  4090.         sLine = sLine + Right$("   " + cstr$(iY), 3)
  4091.         MyString = MyString + sLine + Chr$(13)
  4092.     Next iY
  4093.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  4094.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  4095.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  4096.     RotationArrayToStringTest$ = MyString
  4097. End Function ' RotationArrayToStringTest$
  4098.  
  4099. ' /////////////////////////////////////////////////////////////////////////////
  4100. ' 1. split string by line breaks CHR$(13)
  4101. ' 2. split lines up to 1 column per char
  4102. ' 3. count rows, columns
  4103. ' 4. DIM array, making sure array has
  4104. '    a) an _ODD_ number of rows/columns, with a center point
  4105. '    b) index is in cartesian format, where center is (0,0)
  4106. ' 5. populate array with contents of string
  4107.  
  4108. ' dimension #1 = columns
  4109. ' dimension #2 = rows
  4110.  
  4111. Sub StringToRotationArray (RoArray() As RotationType, MyString As String, EmptyChar As String)
  4112.     Dim RoutineName As String: RoutineName = "StringToRotationArray"
  4113.     ReDim arrLines$(0)
  4114.     Dim delim$
  4115.     Dim iRow%
  4116.     Dim iCol%
  4117.     Dim sChar$
  4118.     Dim iColCount As Integer
  4119.     Dim iRowCount As Integer
  4120.     Dim iCount As Integer
  4121.     Dim bAddedRow As Integer: bAddedRow = FALSE
  4122.     Dim bAddedColumn As Integer: bAddedColumn = FALSE
  4123.     Dim iHalf1 As Integer
  4124.     Dim iHalf2 As Integer
  4125.     Dim iFrom1 As Integer
  4126.     Dim iFrom2 As Integer
  4127.     Dim iTo1 As Integer
  4128.     Dim iTo2 As Integer
  4129.     Dim iEmpty As Integer
  4130.     Dim iX As Integer
  4131.     Dim iY As Integer
  4132.  
  4133.     delim$ = Chr$(13)
  4134.     split MyString, delim$, arrLines$()
  4135.  
  4136.     iRowCount = UBound(arrLines$) + 1
  4137.  
  4138.     ' look at all the rows and find the max # of columns used
  4139.     iColCount = 0
  4140.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4141.  
  4142.         ' count the columns for this row
  4143.         iCount = 0
  4144.         For iCol% = 1 To Len(arrLines$(iRow%))
  4145.             iCount = iCount + 1
  4146.         Next iCol%
  4147.  
  4148.         ' if this row has the most so far, then set that to the max
  4149.         If iCount > iColCount Then
  4150.             iColCount = iCount
  4151.         End If
  4152.     Next iRow%
  4153.  
  4154.     ' adjust columns to be odd
  4155.     If IsEven%(iColCount) Then
  4156.         iColCount = iColCount + 1
  4157.         bAddedColumn = TRUE
  4158.     End If
  4159.  
  4160.     ' calculate array bounds for columns
  4161.     iHalf1 = (iColCount - 1) / 2
  4162.     iFrom1 = 0 - iHalf1
  4163.     iTo1 = iHalf1
  4164.  
  4165.     ' adjust rows to be odd
  4166.     If IsEven%(iRowCount) Then
  4167.         iRowCount = iRowCount + 1
  4168.         bAddedRow = TRUE
  4169.     End If
  4170.  
  4171.     ' calculate array bounds for rows
  4172.     iHalf2 = (iRowCount - 1) / 2
  4173.     iFrom2 = 0 - iHalf2
  4174.     iTo2 = iHalf2
  4175.  
  4176.     ' size array to new bounds
  4177.     ReDim RoArray(iFrom1 To iTo1, iFrom2 To iTo2, 127) As RotationType
  4178.  
  4179.     ' get value for empty
  4180.     If Len(EmptyChar) > 0 Then
  4181.         iEmpty = Asc(EmptyChar)
  4182.     Else
  4183.         iEmpty = 32 ' (use space as default)
  4184.     End If
  4185.  
  4186.     ' clear array
  4187.     For iY = LBound(RoArray, 2) To UBound(RoArray, 2)
  4188.         For iX = LBound(RoArray, 1) To UBound(RoArray, 1)
  4189.             RoArray(iX, iY, 0).c = iEmpty
  4190.             RoArray(iX, iY, 0).origx = iX
  4191.             RoArray(iX, iY, 0).origy = iY
  4192.         Next iX
  4193.     Next iY
  4194.  
  4195.     ' fill array
  4196.     iY = LBound(RoArray, 2) - 1
  4197.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4198.         iY = iY + 1
  4199.         iX = LBound(RoArray, 1) - 1
  4200.         For iCol% = 1 To Len(arrLines$(iRow%))
  4201.             iX = iX + 1
  4202.             sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  4203.             RoArray(iX, iY, 0).c = Asc(sChar$)
  4204.         Next iCol%
  4205.     Next iRow%
  4206.  
  4207. End Sub ' StringToRotationArray
  4208.  
  4209. ' /////////////////////////////////////////////////////////////////////////////
  4210.  
  4211. Sub StringToArray (MyArray() As String, MyString As String)
  4212.     Dim delim$
  4213.     ReDim arrLines$(0)
  4214.     Dim iRow%
  4215.     Dim iCol%
  4216.     Dim sChar$
  4217.     Dim iDim1 As Integer
  4218.     Dim iDim2 As Integer
  4219.     iDim1 = LBound(MyArray, 1)
  4220.     iDim2 = LBound(MyArray, 2)
  4221.     delim$ = Chr$(13)
  4222.     split MyString, delim$, arrLines$()
  4223.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4224.         If iRow% <= UBound(MyArray, 2) Then
  4225.             For iCol% = 1 To Len(arrLines$(iRow%))
  4226.                 If iCol% <= UBound(MyArray, 1) Then
  4227.                     sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  4228.  
  4229.                     If Len(sChar$) > 1 Then
  4230.                         sChar$ = Left$(sChar$, 1)
  4231.                     Else
  4232.                         If Len(sChar$) = 0 Then
  4233.                             sChar$ = "."
  4234.                         End If
  4235.                     End If
  4236.                     MyArray(iRow% + iDim1, (iCol% - 1) + iDim2) = sChar$
  4237.                 Else
  4238.                     ' Exit if out of bounds
  4239.                     Exit For
  4240.                 End If
  4241.             Next iCol%
  4242.         Else
  4243.             ' Exit if out of bounds
  4244.             Exit For
  4245.         End If
  4246.     Next iRow%
  4247. End Sub ' StringToArray
  4248.  
  4249. ' /////////////////////////////////////////////////////////////////////////////
  4250.  
  4251. 'SUB ClearArray (MyArray(1 To 32, 1 To 32) AS STRING, MyString As String)
  4252. Sub ClearArray (MyArray() As String, MyString As String)
  4253.     Dim iRow As Integer
  4254.     Dim iCol As Integer
  4255.     Dim sChar$
  4256.     If Len(MyString) = 1 Then
  4257.         sChar$ = MyString
  4258.     Else
  4259.         If Len(MyString) = 0 Then
  4260.             sChar$ = " "
  4261.         Else
  4262.             sChar$ = Left$(MyString, 1)
  4263.         End If
  4264.     End If
  4265.     For iRow = LBound(MyArray, 1) To UBound(MyArray, 1)
  4266.         For iCol = LBound(MyArray, 2) To UBound(MyArray, 2)
  4267.             MyArray(iRow, iCol) = sChar$
  4268.         Next iCol
  4269.     Next iRow
  4270. End Sub ' ClearArray
  4271.  
  4272. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4273. ' BEGIN GENERAL PURPOSE ROUTINES
  4274. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4275.  
  4276. ' /////////////////////////////////////////////////////////////////////////////
  4277.  
  4278. Function cstr$ (myValue)
  4279.     'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
  4280.     cstr$ = _Trim$(Str$(myValue))
  4281. End Function ' cstr$
  4282.  
  4283. Function cstrl$ (myValue As Long)
  4284.     cstrl$ = _Trim$(Str$(myValue))
  4285. End Function ' cstrl$
  4286.  
  4287. ' /////////////////////////////////////////////////////////////////////////////
  4288.  
  4289. Function IIF (Condition, IfTrue, IfFalse)
  4290.     If Condition Then IIF = IfTrue Else IIF = IfFalse
  4291.  
  4292. ' /////////////////////////////////////////////////////////////////////////////
  4293.  
  4294. Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
  4295.     If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
  4296.  
  4297. ' /////////////////////////////////////////////////////////////////////////////
  4298. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  4299.  
  4300. Function IsEven% (n)
  4301.     If n Mod 2 = 0 Then
  4302.         IsEven% = TRUE
  4303.     Else
  4304.         IsEven% = FALSE
  4305.     End If
  4306. End Function ' IsEven%
  4307.  
  4308. ' /////////////////////////////////////////////////////////////////////////////
  4309. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  4310.  
  4311. Function IsOdd% (n)
  4312.     If n Mod 2 = 1 Then
  4313.         IsOdd% = TRUE
  4314.     Else
  4315.         IsOdd% = FALSE
  4316.     End If
  4317. End Function ' IsOdd%
  4318.  
  4319. ' /////////////////////////////////////////////////////////////////////////////
  4320. ' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0
  4321.  
  4322. Function IsNum% (text$)
  4323.     Dim a$
  4324.     Dim b$
  4325.     a$ = _Trim$(text$)
  4326.     b$ = _Trim$(Str$(Val(text$)))
  4327.     If a$ = b$ Then
  4328.         IsNum% = TRUE
  4329.     Else
  4330.         IsNum% = FALSE
  4331.     End If
  4332. End Function ' IsNum%
  4333.  
  4334. ' /////////////////////////////////////////////////////////////////////////////
  4335. ' Split and join strings
  4336. ' https://www.qb64.org/forum/index.php?topic=1073.0
  4337.  
  4338. 'Combine all elements of in$() into a single string with delimiter$ separating the elements.
  4339.  
  4340. Function join$ (in$(), delimiter$)
  4341.     result$ = in$(LBound(in$))
  4342.     For i = LBound(in$) + 1 To UBound(in$)
  4343.         result$ = result$ + delimiter$ + in$(i)
  4344.     Next i
  4345.     join$ = result$
  4346. End Function ' join$
  4347.  
  4348. ' /////////////////////////////////////////////////////////////////////////////
  4349. ' FROM: String Manipulation
  4350. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index_topic_5964-0/
  4351. '
  4352. 'SUMMARY:
  4353. '   Purpose:  A library of custom functions that transform strings.
  4354. '   Author:   Dustinian Camburides (dustinian@gmail.com)
  4355. '   Platform: QB64 (www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there])
  4356. '   Revision: 1.6
  4357. '   Updated:  5/28/2012
  4358.  
  4359. 'SUMMARY:
  4360. '[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
  4361. 'INPUT:
  4362. 'Text: The input string; the text that's being manipulated.
  4363. 'Find: The specified sub-string; the string sought within the [Text] string.
  4364. 'Add: The sub-string that's being added to the [Text] string.
  4365.  
  4366. Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
  4367.     ' VARIABLES:
  4368.     Dim Text2 As String
  4369.     Dim Find2 As String
  4370.     Dim Add2 As String
  4371.     Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
  4372.     Dim strBefore As String ' The characters before the string to be replaced.
  4373.     Dim strAfter As String ' The characters after the string to be replaced.
  4374.  
  4375.     ' INITIALIZE:
  4376.     ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
  4377.     Text2 = Text1
  4378.     Find2 = Find1
  4379.     Add2 = Add1
  4380.  
  4381.     lngLocation = InStr(1, Text2, Find2)
  4382.  
  4383.     ' PROCESSING:
  4384.     ' While [Find2] appears in [Text2]...
  4385.     While lngLocation
  4386.         ' Extract all Text2 before the [Find2] substring:
  4387.         strBefore = Left$(Text2, lngLocation - 1)
  4388.  
  4389.         ' Extract all text after the [Find2] substring:
  4390.         strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
  4391.  
  4392.         ' Return the substring:
  4393.         Text2 = strBefore + Add2 + strAfter
  4394.  
  4395.         ' Locate the next instance of [Find2]:
  4396.         lngLocation = InStr(1, Text2, Find2)
  4397.  
  4398.         ' Next instance of [Find2]...
  4399.     Wend
  4400.  
  4401.     ' OUTPUT:
  4402.     Replace$ = Text2
  4403. End Function ' Replace$
  4404.  
  4405. ' /////////////////////////////////////////////////////////////////////////////
  4406. ' Split and join strings
  4407. ' https://www.qb64.org/forum/index.php?topic=1073.0
  4408. '
  4409. ' FROM luke, QB64 Developer
  4410. ' Date: February 15, 2019, 04:11:07 AM
  4411. '
  4412. ' Given a string of words separated by spaces (or any other character),
  4413. ' splits it into an array of the words. I've no doubt many people have
  4414. ' written a version of this over the years and no doubt there's a million
  4415. ' ways to do it, but I thought I'd put mine here so we have at least one
  4416. ' version. There's also a join function that does the opposite
  4417. ' array -> single string.
  4418. '
  4419. ' Code is hopefully reasonably self explanatory with comments and a little demo.
  4420. ' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.
  4421.  
  4422. 'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
  4423. 'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
  4424. '
  4425. 'delimiter$ must be one character long.
  4426. 'result$() must have been REDIMmed previously.
  4427.  
  4428. Sub split (in$, delimiter$, result$())
  4429.     ReDim result$(-1)
  4430.     start = 1
  4431.     Do
  4432.         While Mid$(in$, start, 1) = delimiter$
  4433.             start = start + 1
  4434.             If start > Len(in$) Then Exit Sub
  4435.         Wend
  4436.         finish = InStr(start, in$, delimiter$)
  4437.         If finish = 0 Then finish = Len(in$) + 1
  4438.         ReDim _Preserve result$(0 To UBound(result$) + 1)
  4439.         result$(UBOUND(result$)) = MID$(in$, start, finish - start)
  4440.         start = finish + 1
  4441.     LOOP WHILE start <= LEN(in$)
  4442. END SUB ' split
  4443.  
  4444. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4445. ' END GENERAL PURPOSE ROUTINES
  4446. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4447.  
  4448. ' #END
  4449. ' ################################################################################################################################################################
  4450.  

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
So I have to do a bunch of reading to catch up to where the discussion is, but I never mentioned how a certain experiment went the other day so I recreated it just now. This is quick and dirty, not a solution, but maybe it'll inspire.

1) Take a screenshot at 29 degrees, save.
2) Take a screenshot at 31 degrees, save.
3) Invert colors on each image (for paint.exe's convenience)
4) With transparent selection enabled, paste one picture over the other as shown.

The result is basically what you want, but in bold. This is the pictorial version of binary ANDing the two images. All you would need to do is de-bold the final image, which could come from using the original skeleton that is angle 30's image, with perhaps an OR instead - or something. Alright, just wanted to share that before too much time goes by.

  [ You are not allowed to view this attachment ]  



EDIT:

Here's a scheme. Three definitions:
[29] = image at 29 degrees
[30] = image at 30 degrees
[31] = image at 31 degrees

If rotating the positive direction, use [29] AND [30]
If rotating in the negative direction, use [31] AND [30]
If not moving at all, use [29] AND [31].
« Last Edit: December 29, 2021, 10:38:00 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
So I have to do a bunch of reading to catch up to where the discussion is, but I never mentioned how a certain experiment went the other day so I recreated it just now. This is quick and dirty, not a solution, but maybe it'll inspire.

1) Take a screenshot at 29 degrees, save.
2) Take a screenshot at 31 degrees, save.
3) Invert colors on each image (for paint.exe's convenience)
4) With transparent selection enabled, paste one picture over the other as shown.

The result is basically what you want, but in bold. This is the pictorial version of binary ANDing the two images. All you would need to do is de-bold the final image, which could come from using the original skeleton that is angle 30's image, with perhaps an OR instead - or something. Alright, just wanted to share that before too much time goes by.

EDIT:

Here's a scheme. Three definitions:
[29] = image at 29 degrees
[30] = image at 30 degrees
[31] = image at 31 degrees

If rotating the positive direction, use [29] AND [30]
If rotating in the negative direction, use [31] AND [30]
If not moving at all, use [29] AND [31].

Thanks for sharing this idea - I just gave it a try.

Here's what we get at 29 degrees:
  [ You are not allowed to view this attachment ]  

Here is 31 degrees:
  [ You are not allowed to view this attachment ]  

And here is what we get when we try merging:
  [ You are not allowed to view this attachment ]  

I think the problem is how to determine if a point has been duplicated.
If we duplicate a point, the result is a sort of "blur".
With text characters like in the above example, it's easy to see the problem.

We can check to see if a point gets overwritten (like ShearRotate4 does)
but if it does, how do we identify which is the equivalent point from the previous/next angle?

I suppose we could substitute a "mask" array, which uses unique values for each point,
and it can then locate the given point in its new position:
  • Copy the unrotated array OriginalArray to MaskArray, where each point gets a unique value
  • Rotate MaskArray to the desired angle, result is RotatedMaskArray, checking for overwritten points.
  • Rotate MaskArray counter-clockwise to angle-1, result is CCWMaskArray. Locate overwritten points.
  • Plot any overwritten points found in CCWMaskArray to RotatedMaskArray _if_ not occupied.
  • If any overwritten points remain to be found, rotate MaskArray clockwise to angle+1, result is CWMaskArray. Locate overwritten points.
  • Plot any overwritten points found in CWMaskArray to RotatedMaskArray _if_ not occupied.
  • Finally, use RotatedMaskArray as a guide to construct RotatedArray from the actual values in OriginalArray
^^ or something like that?

That would probably work actually, although it's costly -
we would have to copy our array 2 or more times, and iterate over it.
But if what we want is accuracy, that might do it?

Here is the code, use option 22 from the menu:
Code: QB64: [Select]
  1. ' ################################################################################################################################################################
  2. ' #TOP
  3.  
  4. ' Basic 2D plotting functions
  5. ' Version 1.00 by madscijr
  6. ' with help from various (sources cited below).
  7. ' ################################################################################################################################################################
  8.  
  9. ' =============================================================================
  10. ' GLOBAL DECLARATIONS
  11. ' =============================================================================
  12.  
  13. ' boolean constants
  14. Const FALSE = 0
  15. Const TRUE = Not FALSE
  16.  
  17. ' rotational constants
  18. Const cCounterClockwise = -1
  19. Const cClockwise = 1
  20.  
  21. ' -----------------------------------------------------------------------------
  22. ' USER DEFINED TYPES
  23. ' -----------------------------------------------------------------------------
  24. Type RotationType
  25.     origx As Integer
  26.     origy As Integer
  27.     c As Integer
  28.     z as integer ' which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  29. End Type ' RotationType
  30.  
  31. ' -----------------------------------------------------------------------------
  32. ' GLOBAL VARIABLES
  33. ' -----------------------------------------------------------------------------
  34. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  35. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  36. Dim Shared m_bDebug: m_bDebug = TRUE
  37.  
  38. ' =============================================================================
  39. ' BEGIN MAIN PROGRAM
  40. ' =============================================================================
  41. Dim in$
  42.  
  43. ' ****************************************************************************************************************************************************************
  44. ' ACTIVATE DEBUGGING WINDOW
  45. If m_bDebug = TRUE Then
  46.     $Console
  47.     _Delay 4
  48.     _Console On
  49.     _Echo "Started " + m_ProgramName$
  50.     _Echo "Debugging on..."
  51. ' ****************************************************************************************************************************************************************
  52.  
  53. ' -----------------------------------------------------------------------------
  54. ' START THE MENU
  55. main
  56.  
  57. ' -----------------------------------------------------------------------------
  58. ' DONE
  59. Print m_ProgramName$ + " finished."
  60. 'Screen 0
  61. Input "Press <ENTER> to continue", in$
  62.  
  63. ' ****************************************************************************************************************************************************************
  64. ' DEACTIVATE DEBUGGING WINDOW
  65. If m_bDebug = TRUE Then
  66. ' ****************************************************************************************************************************************************************
  67.  
  68. ' -----------------------------------------------------------------------------
  69. ' EXIT
  70. System ' return control to the operating system
  71.  
  72. ' =============================================================================
  73. ' END MAIN PROGRAM
  74. ' =============================================================================
  75.  
  76. ' /////////////////////////////////////////////////////////////////////////////
  77. ' MAIN MENU
  78.  
  79. Sub main
  80.     Dim RoutineName As String: RoutineName = "main"
  81.     Dim in$
  82.  
  83.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  84.     Do
  85.         Cls
  86.         Print m_ProgramName$
  87.         Print
  88.         Print "Some basic 2D plotting"
  89.         Print
  90.         Print " 1. PlotPointTest"
  91.         Print " 2. PlotSquareTest"
  92.         Print " 3. PlotCircleTest"
  93.                 Print " 4. PlotCircleTopLeftTest"
  94.         Print " 5. PlotSemicircleTest"
  95.         Print " 6. CircleFillTest"
  96.         Print " 7. CircleFillTopLeftTest"
  97.                 Print " 8. SemiCircleFillTest"
  98.                 Print " 9. EllipseTest"
  99.         Print "10. EllipseFillTest"
  100.         Print "11. PlotLineTest"
  101.         Print "12. ShearRotate1Test1"
  102.         Print "13. ShearRotate1Test2 (auto advances 0-360 degrees)"
  103.         Print "14. ShearRotate1Test2 (auto advances 0-360 degrees) (uses Petr's text)"
  104.         Print "15. ShearRotate2Test1 (correct for missing points logic v1)"
  105.         Print "16. ShearRotate2Test1 (correct for missing points logic v1) (uses Petr's text)"
  106.         Print "17. ShearRotate3Test1 (correct for missing points logic v2)"
  107.         Print "18. ShearRotate3Test1 (correct for missing points logic v2) (uses Petr's text)"
  108.         Print "19. ShearRotate4Test1 (correct for missing points logic v3)"
  109.         Print "20. ShearRotate4Test1 (correct for missing points logic v3) (uses Petr's text)"
  110.         Print "21. ShearRotate5Test1 (correct for missing points, STxAxTIC logic)"
  111.         Print "22. ShearRotate5Test1 (correct for missing points, STxAxTIC logic) (uses Petr's text)"
  112.         Print
  113.         Print "What to do? ('q' to exit)"
  114.  
  115.         Input in$: in$ = LCase$(_Trim$(in$))
  116.        
  117.         If in$ = "1" Then
  118.             PlotPointTest
  119.         ElseIf in$ = "2" Then
  120.             PlotSquareTest
  121.         ElseIf in$ = "3" Then
  122.             PlotCircleTest
  123.         ElseIf in$ = "4" Then
  124.             PlotCircleTopLeftTest
  125.         ElseIf in$ = "5" Then
  126.             PlotSemicircleTest
  127.                 ElseIf in$ = "6" Then
  128.             CircleFillTest
  129.         ElseIf in$ = "7" Then
  130.             CircleFillTopLeftTest
  131.                 Elseif in$ = "8" then
  132.                         SemiCircleFillTest
  133.         ElseIf in$ = "9" Then
  134.             EllipseTest
  135.         ElseIf in$ = "10" Then
  136.             EllipseFillTest
  137.         ElseIf in$ = "11" Then
  138.             PlotLineTest
  139.         ElseIf in$ = "12" Then
  140.             ShearRotate1Test1
  141.         ElseIf in$ = "13" Then
  142.             ShearRotate1Test2 TestSprite1$
  143.         ElseIf in$ = "14" Then
  144.             ShearRotate1Test2 PetrText1$
  145.         ElseIf in$ = "15" Then
  146.             ShearRotate2Test1 TestSprite1$
  147.         ElseIf in$ = "16" Then
  148.             ShearRotate2Test1 PetrText1$
  149.         ElseIf in$ = "17" Then
  150.             ShearRotate3Test1 TestSprite1$
  151.         ElseIf in$ = "18" Then
  152.             ShearRotate3Test1 PetrText1$
  153.         ElseIf in$ = "19" Then
  154.             ShearRotate4Test1 TestSprite1$
  155.         ElseIf in$ = "20" Then
  156.             ShearRotate4Test1 PetrText1$
  157.         ElseIf in$ = "21" Then
  158.             ShearRotate5Test1 TestSprite1$
  159.         ElseIf in$ = "22" Then
  160.             ShearRotate5Test1 PetrText1$
  161.         End If
  162.     Loop Until in$ = "q"
  163. End Sub ' main
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175. ' /////////////////////////////////////////////////////////////////////////////
  176. ' MyArray(1 To 32, 1 To 32) AS STRING
  177. ' where index is MyArray(Y, X)
  178.  
  179. Sub PlotPoint (X As Integer, Y As Integer, S As String, MyArray() As String)
  180. _echo "PlotPoint X=" + cstr$(X) + ", Y=" + cstr$(Y) + ", S=" + chr$(34) + S + chr$(34) + ", MyArray()"
  181.     If (X >= LBound(MyArray, 2)) Then
  182.         If (X <= UBound(MyArray, 2)) Then
  183.             If (Y >= LBound(MyArray, 1)) Then
  184.                 If (Y <= UBound(MyArray, 1)) Then
  185.                     If Len(S) = 1 Then
  186.                         MyArray(Y, X) = S
  187.                     Else
  188.                         If Len(S) > 1 Then
  189.                             MyArray(Y, X) = Left$(S, 1)
  190.                         End If
  191.                     End If
  192.                 End If
  193.             End If
  194.         End If
  195.     End If
  196. End Sub ' PlotPoint
  197.  
  198. ' /////////////////////////////////////////////////////////////////////////////
  199.  
  200. Sub PlotPointTest
  201.     Dim MyArray(1 To 32, 1 To 32) As String
  202.     Dim iX As Integer
  203.     Dim iY As Integer
  204.     Dim in$
  205.     Dim X As Integer
  206.     Dim Y As Integer
  207.     Dim L As Integer
  208.     Dim iChar As Integer
  209.    
  210.     ClearArray MyArray(), "."
  211.     iChar = 64
  212.    
  213.     Cls
  214.     Print "Plot a point."
  215.     Print ArrayToStringTest(MyArray())
  216.     Print
  217.    
  218.     Do
  219.         Print "Type x,y (1-32, 1-32) coordinate to plot point at."
  220.         Input "X,Y OR 0 TO QUIT? "; X, Y
  221.         If X > 0 And Y > 0 Then
  222.             iChar = iChar + 1
  223.             If iChar > 90 Then iChar = 65
  224.            
  225.             Print "X=" + cstr$(X) + ", Y=" + cstr$(Y)
  226.             PlotPoint X, Y, chr$(iChar), MyArray()
  227.  
  228.             Print "Current point plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  229.             Print ArrayToStringTest(MyArray())
  230.             Print
  231.            
  232.         Else
  233.             Exit Do
  234.         End If
  235.     Loop
  236. End Sub ' PlotPointTest
  237.  
  238. ' /////////////////////////////////////////////////////////////////////////////
  239.  
  240. Sub PlotSquare (X1 As Integer, Y1 As Integer, L As Integer, S As String, MyArray() As String)
  241.     Dim X As Integer
  242.     Dim X2 As Integer
  243.     Dim Y As Integer
  244.     Dim Y2 As Integer
  245.     Dim sChar$
  246.  
  247.     If Len(S) = 1 Then
  248.         sChar$ = S
  249.     Else
  250.         If Len(S) = 0 Then
  251.             sChar$ = " "
  252.         Else
  253.             sChar$ = Left$(S, 1)
  254.         End If
  255.     End If
  256.  
  257.     X2 = (X1 + L) - 1
  258.     Y2 = (Y1 + L) - 1
  259.     For X = X1 To X2
  260.         For Y = Y1 To Y2
  261.             PlotPoint X, Y, sChar$, MyArray()
  262.         Next Y
  263.     Next X
  264. End Sub ' PlotSquare
  265.  
  266. ' /////////////////////////////////////////////////////////////////////////////
  267.  
  268. Sub PlotSquareTest
  269.     Dim MyArray(1 To 32, 1 To 32) As String
  270.     Dim iX As Integer
  271.     Dim iY As Integer
  272.     Dim in$
  273.     Dim X As Integer
  274.     Dim Y As Integer
  275.     Dim L As Integer
  276.     Dim iChar As Integer
  277.    
  278.     ClearArray MyArray(), "."
  279.     iChar = 64
  280.    
  281.     Cls
  282.     Print "Enter parameters to draw a square."
  283.     Print ArrayToStringTest(MyArray())
  284.     Print
  285.     Do
  286.         Print "Type top left x,y (1-32, 1-32) coordinate to plot square,"
  287.         Print "and size (1-32) of square."
  288.         Input "X,Y,L OR 0 TO QUIT? "; X, Y, L
  289.         If X>0 AND Y>0 AND L > 0 Then
  290.             iChar = iChar + 1
  291.             If iChar > 90 Then iChar = 65
  292.            
  293.             Print
  294.             Print "X=" + cstr$(X)
  295.             Print "Y=" + cstr$(Y)
  296.             Print "L=" + cstr$(L)
  297.             Print
  298.             PlotSquare X, Y, L, chr$(iChar), MyArray()
  299.            
  300.             Print "Square plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  301.             Print ArrayToStringTest(MyArray())
  302.             Print
  303.         Else
  304.             Exit Do
  305.         End If
  306.     Loop
  307. End Sub ' PlotSquareTest
  308.  
  309. ' /////////////////////////////////////////////////////////////////////////////
  310. ' Fast circle drawing in pure Atari BASIC#
  311. ' https://atariwiki.org/wiki/Wiki.jsp?page=Super%20fast%20circle%20routine
  312.  
  313. ' * Magazine: Moj Mikro, 1989/3
  314. ' * Author : Zlatko Bleha
  315. ' * Page : 27 - 31
  316. ' * Atari BASIC listing on disk (tokenized): M8903282.BAS
  317. ' * Atari BASIC listing (listed): M8903282.LST
  318.  
  319. ' Next example is demonstration of implementing mentioned circle algorithm
  320. ' in pure Atari BASIC. This program shows how much faster it is compared to
  321. ' classic program using sine and cosine functions from Atari BASIC
  322. ' (shown in last example).
  323.  
  324. ' Basic Listing M8903282.LST#
  325. '1 REM *******************************
  326. '2 REM PROGRAM  : FAST CIRCLE DRAWING
  327. '3 REM AUTHOR   : ZLATKO BLEHA
  328. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  329. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  330. '6 REM *******************************
  331. '7 REM
  332. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  333. '20 PRINT "ENTER X, Y AND R"
  334. '30 INPUT X,Y,R
  335. '40 IF R=0 THEN PLOT X,Y:END
  336. '50 B=R:C=0:A=R-1
  337. '60 PLOT X+C,Y+B
  338. '70 PLOT X+C,Y-B
  339. '80 PLOT X-C,Y-B
  340. '90 PLOT X-C,Y+B
  341. '100 PLOT X+B,Y+C
  342. '110 PLOT X+B,Y-C
  343. '120 PLOT X-B,Y-C
  344. '130 PLOT X-B,Y+C
  345. '140 C=C+1
  346. '150 A=A+1-C-C
  347. '160 IF A>=0 THEN 190
  348. '170 B=B-1
  349. '180 A=A+B+B
  350. '190 IF B>=C THEN 60
  351.  
  352. ' Use some valid values for coordinates and radius, for example:
  353. ' X=40, Y=40, R=30
  354. ' X=130, Y=90, R=60
  355. ' Slow circle drawing in Atari BASIC#
  356. ' * Magazine: Moj Mikro, 1989/3
  357. ' * Author : Zlatko Bleha
  358. ' * Page : 27 - 31
  359. ' * Atari BASIC listing on disk (tokenized): M8903281.BAS
  360. ' * Atari BASIC listing (listed): M8903281.LST
  361.  
  362. ' This is classic example for drawing circles from Atari BASIC
  363. ' using sine and cosine functions. Unfortunatelly, this is very slow
  364. ' way of doing it and not recommended.
  365. ' Just use routine shown above and everybody will be happy
  366.  
  367. ' Basic Listing M8903281.LST#
  368. '1 REM *******************************
  369. '2 REM PROGRAM  : SLOW CIRCLE DRAWING
  370. '3 REM AUTHOR   : ZLATKO BLEHA
  371. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  372. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  373. '6 REM *******************************
  374. '7 REM
  375. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  376. '20 FOR A=0 TO 6.28 STEP 0.02
  377. '30 X=SIN(A)*50+150
  378. '40 Y=COS(A)*50+80
  379. '50 PLOT X,Y
  380. '60 NEXT A
  381.  
  382. ' Conclusion#
  383. ' Returning back to first program with the fastest way of drawing circles...
  384. ' There is one more thing to note. In case you want to use PLOT subroutine,
  385. ' which is part of the main circle routine, then read following explanation.
  386. ' PLOT routine is written so it can be used easily from Atari BASIC program
  387. ' independently from main circle routine, by using like this:
  388. ' A=USR(30179,POK,X,Y)
  389. '
  390. ' POK   1 (drawing a pixel), 0 (erasing a pixel)
  391. ' X     X coordinate of the pixel
  392. ' Y     Y coordinate of the pixel
  393. '
  394. ' The routine alone is not any faster than normal PLOT command
  395. ' from Atari BASIC, because USR command takes approximately 75%
  396. ' of whole execution. But, used as part of the main circle routine
  397. ' it does not matter anymore, because it is integrated in one larger
  398. ' entity. There the execution is very fast, with no overhead.
  399. ' PLOT routine is here for you to examine anyway.
  400. ' You never know if you will maybe need it in the future.
  401.  
  402. ' More on plotting circles:
  403. '     Drawing a circle in BASIC - fast
  404. '     https://www.cpcwiki.eu/forum/programming/drawing-a-circle-in-basic-fast/
  405.  
  406. ' X,Y     = center point of circle
  407. ' R       = radius
  408. ' S       = char to draw
  409. ' MyArray = 2D string array to plot circle in
  410.  
  411. Sub PlotCircle (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  412.     Dim A As Integer
  413.     Dim B As Integer
  414.     Dim C As Integer
  415.     Dim S2 As String
  416.  
  417.     If Len(S) = 1 Then
  418.         S2 = S
  419.     Else
  420.         If Len(S) = 0 Then
  421.             S2 = " "
  422.         Else
  423.             S2 = Left$(S, 1)
  424.         End If
  425.     End If
  426.  
  427.     If R > 0 Then
  428.         B = R
  429.         C = 0
  430.         A = R - 1
  431.         Do
  432.             PlotPoint X + C, Y + B, S2, MyArray()
  433.             PlotPoint X + C, Y - B, S2, MyArray()
  434.             PlotPoint X - C, Y - B, S2, MyArray()
  435.             PlotPoint X - C, Y + B, S2, MyArray()
  436.             PlotPoint X + B, Y + C, S2, MyArray()
  437.             PlotPoint X + B, Y - C, S2, MyArray()
  438.             PlotPoint X - B, Y - C, S2, MyArray()
  439.             PlotPoint X - B, Y + C, S2, MyArray()
  440.             C = C + 1
  441.             A = A + 1 - C - C
  442.             If A < 0 Then ' IF A>=0 THEN 190
  443.                 B = B - 1
  444.                 A = A + B + B
  445.             End If
  446.             If B < C Then Exit Do ' 190 IF B>=C THEN 60
  447.         Loop
  448.     End If
  449. End Sub ' PlotCircle
  450.  
  451. ' /////////////////////////////////////////////////////////////////////////////
  452.  
  453. Sub PlotCircleTest
  454.     Dim MyArray(1 To 32, 1 To 32) As String
  455.     Dim iX As Integer
  456.     Dim iY As Integer
  457.     Dim in$
  458.     Dim X As Integer
  459.     Dim Y As Integer
  460.     Dim R As Integer
  461.     Dim iChar As Integer
  462.    
  463.     ClearArray MyArray(), "."
  464.     iChar = 64
  465.    
  466.     Cls
  467.     Print "Plot a raster circle"
  468.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  469.     Print
  470.     Print "Enter parameters to draw a circle."
  471.     Print ArrayToStringTest(MyArray())
  472.     Print
  473.    
  474.     Do
  475.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  476.         Print "and radius (1-32) of circle."
  477.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  478.         If X > 0 AND Y > 0 AND R > 0 Then
  479.             iChar = iChar + 1
  480.             If iChar > 90 Then iChar = 65
  481.            
  482.             Print "X=" + cstr$(X)
  483.             Print "Y=" + cstr$(Y)
  484.             Print "R=" + cstr$(R)
  485.            
  486.             PlotCircle X, Y, R, Chr$(iChar), MyArray()
  487.            
  488.             Print "Circle plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  489.             Print ArrayToStringTest(MyArray())
  490.             Print
  491.         Else
  492.             Exit Do
  493.         End If
  494.     Loop
  495.    
  496. End Sub ' PlotCircleTest
  497.  
  498. ' /////////////////////////////////////////////////////////////////////////////
  499. ' X,Y     = top left point of circle
  500. ' R       = radius
  501. ' S       = char to draw
  502. ' MyArray = 2D string array to plot circle in
  503.  
  504. Sub PlotCircleTopLeft (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  505.     Dim RoutineName As String : RoutineName = "PlotCircleTopLeft"
  506.     Dim A As Integer
  507.     Dim B As Integer
  508.     Dim C As Integer
  509.     Dim S2 As String
  510.     Dim W As Integer
  511.     ReDim arrTemp(0, 0) As String
  512.     Dim DY As Integer
  513.     Dim DX As Integer
  514.         DIM TX As Integer
  515.         DIM TY As Integer
  516.         Dim MinY As Integer
  517.         Dim MaxY As Integer
  518.         Dim MinX As Integer
  519.         Dim MaxX As Integer
  520.    
  521.     ' Get total width
  522.     W = (R * 2) + 1
  523.    
  524.     ' Define a temp array
  525.     ReDim arrTemp(0 To W, 0 To W) As String
  526.    
  527.         ' Get minimum X, Y of target array
  528.         MinY = lbound(MyArray, 1)
  529.         MaxY = ubound(MyArray, 1)
  530.         MinX = lbound(MyArray, 2)
  531.         MaxX = ubound(MyArray, 2)
  532.        
  533.     If Len(S) = 1 Then
  534.         S2 = S
  535.     Else
  536.         If Len(S) = 0 Then
  537.             S2 = " "
  538.         Else
  539.             S2 = Left$(S, 1)
  540.         End If
  541.     End If
  542.    
  543.     If R > 0 Then
  544.         ' Draw circle to temporary array
  545.         B = R
  546.         C = 0
  547.         A = R - 1
  548.         Do
  549.             ' PORTIONS OF CIRCLE:
  550.             ' .......3333222.......
  551.             ' .....33.......22.....
  552.             ' ....3...........2....
  553.             ' ...7.............6...
  554.             ' ..7...............6..
  555.             ' .7.................6.
  556.             ' .7.................6.
  557.             ' 7...................6
  558.             ' 7...................6
  559.             ' 7...................6
  560.             ' 8...................6
  561.             ' 8...................5
  562.             ' 8...................5
  563.             ' 8...................5
  564.             ' .8.................5.
  565.             ' .8.................5.
  566.             ' ..8...............5..
  567.             ' ...8.............5...
  568.             ' ....4...........1....
  569.             ' .....44.......11.....
  570.             ' .......4444111.......
  571.             PlotPoint R + C, R + B, S2, arrTemp() ' 1
  572.             PlotPoint R + C, R - B, S2, arrTemp() ' 2
  573.             PlotPoint R - C, R - B, S2, arrTemp() ' 3
  574.             PlotPoint R - C, R + B, S2, arrTemp() ' 4
  575.             PlotPoint R + B, R + C, S2, arrTemp() ' 5
  576.             PlotPoint R + B, R - C, S2, arrTemp() ' 6
  577.             PlotPoint R - B, R - C, S2, arrTemp() ' 7
  578.             PlotPoint R - B, R + C, S2, arrTemp() ' 8
  579.             C = C + 1
  580.             A = A + 1 - C - C
  581.             If A < 0 Then
  582.                 B = B - 1
  583.                 A = A + B + B
  584.             End If
  585.             If B < C Then Exit Do
  586.         Loop
  587.        
  588.         ' Copy circle to destination Y,X
  589.         For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  590.             For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  591.                 IF LEN(arrTemp(DY, DX)) > 0 THEN
  592.                                         TY = Y + DY
  593.                                         If TY >= MinY Then
  594.                                                 If TY <= MaxY Then
  595.                                                         TX = X + DX
  596.                                                         If TX >= MinX Then
  597.                                                                 If TX <= MaxX Then
  598.                                                                         MyArray(TY, TX) = arrTemp(DY, DX)
  599.                                                                 End If
  600.                                                         End If
  601.                                                 End If
  602.                                         End If
  603.                                        
  604.                 END IF
  605.             Next DX
  606.         Next DY
  607.     End If
  608. End Sub ' PlotCircleTopLeft
  609.  
  610. ' /////////////////////////////////////////////////////////////////////////////
  611.  
  612. Sub PlotCircleTopLeftTest
  613.     Dim MyArray(1 To 32, 1 To 32) As String
  614.     Dim iX As Integer
  615.     Dim iY As Integer
  616.     Dim in$
  617.     Dim X As Integer
  618.     Dim Y As Integer
  619.     Dim R As Integer
  620.     Dim iChar As Integer
  621.    
  622.     ClearArray MyArray(), "."
  623.     iChar = 64
  624.    
  625.     Cls
  626.     Print "Plot a raster circle, specifying top left x,y position"
  627.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  628.     Print
  629.     Print "Enter parameters to draw a circle."
  630.     Print ArrayToStringTest(MyArray())
  631.     Print
  632.    
  633.     Do
  634.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot circle,"
  635.         Print "and radius (1-32) of circle."
  636.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  637.         If X > 0 AND Y > 0 AND R > 0 Then
  638.             iChar = iChar + 1
  639.             If iChar > 90 Then iChar = 65
  640.            
  641.             Print "X=" + cstr$(X)
  642.             Print "Y=" + cstr$(Y)
  643.             Print "R=" + cstr$(R)
  644.            
  645.             PlotCircleTopLeft X, Y, R, Chr$(iChar), MyArray()
  646.            
  647.             Print "Circle plotted (from top left), drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  648.             Print ArrayToStringTest(MyArray())
  649.             Print
  650.         Else
  651.             Exit Do
  652.         End If
  653.     Loop
  654.    
  655. End Sub ' PlotCircleTopLeftTest
  656.  
  657. ' /////////////////////////////////////////////////////////////////////////////
  658. ' Based on PlotCircleTopLeft.
  659.  
  660. ' X,Y     = top left point of circle
  661. ' R       = radius
  662. ' Q       = which quarter of the circle to return
  663. '           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
  664. '           like this:
  665.             ' .......4444111.......
  666.             ' .....44.......11.....
  667.             ' ....4...........1....
  668.             ' ...4.............1...
  669.             ' ..4...............1..
  670.             ' .4.................1.
  671.             ' .4.................1.
  672.             ' 4...................1
  673.             ' 4...................1
  674.             ' 4...................1
  675.             ' 3...................1
  676.             ' 3...................2
  677.             ' 3...................2
  678.             ' 3...................2
  679.             ' .3.................2.
  680.             ' .3.................2.
  681.             ' ..3...............2..
  682.             ' ...3.............2...
  683.             ' ....3...........2....
  684.             ' .....33.......22.....
  685.             ' .......3333222.......
  686. ' S       = char to draw
  687. ' MyArray = 2D string array to plot circle in
  688.  
  689. Sub PlotSemicircle (X As Integer, Y As Integer, R As Integer, Q As Integer, S As String, MyArray() As String)
  690.     Dim RoutineName As String : RoutineName = "PlotCircleTopLeft"
  691.     Dim A As Integer
  692.     Dim B As Integer
  693.     Dim C As Integer
  694.     Dim S2 As String
  695.     Dim W As Integer
  696.     ReDim arrTemp(0, 0) As String
  697.     Dim DY As Integer
  698.     Dim DX As Integer
  699.         DIM TX As Integer
  700.         DIM TY As Integer
  701.         Dim MinY As Integer
  702.         Dim MaxY As Integer
  703.         Dim MinX As Integer
  704.         Dim MaxX As Integer
  705.    
  706.     ' Get total width
  707.     W = (R * 2) + 1
  708.    
  709.     ' Define a temp array
  710.     ReDim arrTemp(0 To W, 0 To W) As String
  711.    
  712.         ' Get minimum X, Y of target array
  713.         MinY = lbound(MyArray, 1)
  714.         MaxY = ubound(MyArray, 1)
  715.         MinX = lbound(MyArray, 2)
  716.         MaxX = ubound(MyArray, 2)
  717.        
  718.     If Len(S) = 1 Then
  719.         S2 = S
  720.     Else
  721.         If Len(S) = 0 Then
  722.             S2 = " "
  723.         Else
  724.             S2 = Left$(S, 1)
  725.         End If
  726.     End If
  727.    
  728.     If R > 0 Then
  729.         ' Draw circle to temporary array
  730.         B = R
  731.         C = 0
  732.         A = R - 1
  733.         Do
  734.             ' PORTIONS OF CIRCLE:
  735.             ' .......3333222.......
  736.             ' .....33.......22.....
  737.             ' ....3...........2....
  738.             ' ...7.............6...
  739.             ' ..7...............6..
  740.             ' .7.................6.
  741.             ' .7.................6.
  742.             ' 7...................6
  743.             ' 7...................6
  744.             ' 7...................6
  745.             ' 8...................6
  746.             ' 8...................5
  747.             ' 8...................5
  748.             ' 8...................5
  749.             ' .8.................5.
  750.             ' .8.................5.
  751.             ' ..8...............5..
  752.             ' ...8.............5...
  753.             ' ....4...........1....
  754.             ' .....44.......11.....
  755.             ' .......4444111.......
  756.            
  757.             ' JUST PLOT SELECTED QUADRANT:
  758.             Select Case Q
  759.                 Case 1:
  760.                     ' quadrant #1
  761.                     PlotPoint C, R - B, S2, arrTemp() ' 2
  762.                     PlotPoint B, R - C, S2, arrTemp() ' 6
  763.                 Case 2:
  764.                     ' quadrant #2
  765.                     PlotPoint B, C, S2, arrTemp() ' 5
  766.                     PlotPoint C, B, S2, arrTemp() ' 1
  767.                 Case 3:
  768.                     ' quadrant #3
  769.                     PlotPoint R - C, B, S2, arrTemp() ' 4
  770.                     PlotPoint R - B, C, S2, arrTemp() ' 8
  771.                 Case 4:
  772.                     ' quadrant #4
  773.                     PlotPoint R - B, R - C, S2, arrTemp() ' 7
  774.                     PlotPoint R - C, R - B, S2, arrTemp() ' 3
  775.                 Case Else:
  776.                     ' (DO NOTHING)
  777.             End Select
  778.            
  779.             '' PLOT CIRCLE:
  780.             '' quadrant #1
  781.             'PlotPoint R + C, R - B, S2, arrTemp() ' 2
  782.             'PlotPoint R + B, R - C, S2, arrTemp() ' 6
  783.             '
  784.             '' quadrant #2
  785.             'PlotPoint R + B, R + C, S2, arrTemp() ' 5
  786.             'PlotPoint R + C, R + B, S2, arrTemp() ' 1
  787.             '
  788.             '' quadrant #3
  789.             'PlotPoint R - C, R + B, S2, arrTemp() ' 4
  790.             'PlotPoint R - B, R + C, S2, arrTemp() ' 8
  791.             '
  792.             '' quadrant #4
  793.             'PlotPoint R - B, R - C, S2, arrTemp() ' 7
  794.             'PlotPoint R - C, R - B, S2, arrTemp() ' 3
  795.            
  796.             C = C + 1
  797.             A = A + 1 - C - C
  798.             If A < 0 Then
  799.                 B = B - 1
  800.                 A = A + B + B
  801.             End If
  802.             If B < C Then Exit Do
  803.         Loop
  804.        
  805.         ' Copy semicircle to destination Y,X
  806.         For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  807.             For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  808.                 IF LEN(arrTemp(DY, DX)) > 0 THEN
  809.                                         TY = Y + DY
  810.                                         If TY >= MinY Then
  811.                                                 If TY <= MaxY Then
  812.                                                         TX = X + DX
  813.                                                         If TX >= MinX Then
  814.                                                                 If TX <= MaxX Then
  815.                                                                         MyArray(TY, TX) = arrTemp(DY, DX)
  816.                                                                 End If
  817.                                                         End If
  818.                                                 End If
  819.                                         End If
  820.                 END IF
  821.             Next DX
  822.         Next DY
  823.     End If
  824. End Sub ' PlotSemicircle
  825.  
  826. ' /////////////////////////////////////////////////////////////////////////////
  827.  
  828. Sub PlotSemicircleTest
  829.     Dim MyArray(1 To 32, 1 To 32) As String
  830.     Dim iX As Integer
  831.     Dim iY As Integer
  832.     Dim in$
  833.     Dim X As Integer
  834.     Dim Y As Integer
  835.     Dim R As Integer
  836.     Dim Q As Integer
  837.     Dim iChar As Integer
  838.    
  839.     ClearArray MyArray(), "."
  840.     iChar = 64
  841.    
  842.     Cls
  843.     Print "Plot a semicircle"
  844.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  845.     Print
  846.     Print "Enter parameters to draw a semicircle."
  847.     Print ArrayToStringTest(MyArray())
  848.     Print
  849.    
  850.     Do
  851.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot semicircle,"
  852.         Print "radius (1-32) of semicircle, and quadrant of circle to use:"
  853.         Print "41"
  854.         Print "32"
  855.         Input "X,Y,R,Q OR 0 TO QUIT: "; X, Y, R, Q
  856.         If X > 0 AND Y > 0 AND R > 0 Then
  857.             iChar = iChar + 1
  858.             If iChar > 90 Then iChar = 65
  859.            
  860.             Print "X=" + cstr$(X)
  861.             Print "Y=" + cstr$(Y)
  862.             Print "R=" + cstr$(R)
  863.            
  864.             PlotSemicircle X, Y, R, Q, Chr$(iChar), MyArray()
  865.            
  866.             Print "Semicircle plotted (from top left), drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  867.             Print ArrayToStringTest(MyArray())
  868.             Print
  869.         Else
  870.             Exit Do
  871.         End If
  872.     Loop
  873.    
  874. End Sub ' PlotSemicircleTest
  875.  
  876. ' /////////////////////////////////////////////////////////////////////////////
  877. ' Re: Is this fast enough as general circle fill?
  878. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg1913#msg1913
  879.  
  880. ' From: SMcNeill
  881. ' Date: « Reply #30 on: June 26, 2018, 03:34:18 pm »
  882. '
  883. ' Sometimes, computers do things that are completely counter-intuitive to us, and
  884. ' we find ourselves having to step back as programmers and simply say, "WOW!!"  
  885. ' Here's a perfect example of that:
  886. ' Here we look at two different circle fill routines -- one, which I'd assume to
  887. ' be faster, which precalculates the offset needed to find the endpoints for each
  888. ' line which composes a circle, and another, which is the same old CircleFill
  889. ' program which I've shared countless times over the years with people on various
  890. ' QB64 forums.
  891. '
  892. ' When all is said and done though, CircleFill is STILL even faster than
  893. ' CircleFillFast, which pregenerates those end-points for us!
  894.  
  895. ' CX,CY     = center point of circle
  896. ' R         = radius
  897. ' S         = char to draw
  898. ' MyArray = 2D string array to plot circle in
  899.  
  900. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, S As String, MyArray() As String)
  901.     DIM Radius AS INTEGER
  902.     Dim RadiusError AS INTEGER
  903.     DIM X AS INTEGER
  904.     Dim Y AS INTEGER
  905.     Dim iLoopX as INTEGER
  906.     Dim iLoopY as INTEGER
  907.    
  908.     Radius = ABS(R)
  909.     RadiusError = -Radius
  910.     X = Radius
  911.     Y = 0
  912.    
  913.     IF Radius = 0 THEN
  914.         'PSET (CX, CY), C
  915.         'PlotPoint CX, CY, S, MyArray()
  916.         EXIT SUB
  917.     END IF
  918.    
  919.     ' Draw the middle span here so we don't draw it twice in the main loop,
  920.     ' which would be a problem with blending turned on.
  921.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  922.     FOR iLoopX = CX - X TO CX + X
  923.         PlotPoint iLoopX, CY, S, MyArray()
  924.     NEXT iLoopX
  925.    
  926.     WHILE X > Y
  927.         RadiusError = RadiusError + Y * 2 + 1
  928.         IF RadiusError >= 0 THEN
  929.             IF X <> Y + 1 THEN
  930.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  931.                 iLoopY = CY - X
  932.                 FOR iLoopX = CX - Y TO CX + Y
  933.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  934.                 NEXT iLoopX
  935.                
  936.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  937.                 iLoopY = CY + X
  938.                 FOR iLoopX = CX - Y TO CX + Y
  939.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  940.                 NEXT iLoopX
  941.             END IF
  942.             X = X - 1
  943.             RadiusError = RadiusError - X * 2
  944.         END IF
  945.         Y = Y + 1
  946.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  947.         iLoopY = CY - Y
  948.         FOR iLoopX = CX - X TO CX + X
  949.             PlotPoint iLoopX, iLoopY, S, MyArray()
  950.         NEXT iLoopX
  951.        
  952.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  953.         iLoopY = CY + Y
  954.         FOR iLoopX = CX - X TO CX + X
  955.             PlotPoint iLoopX, iLoopY, S, MyArray()
  956.         NEXT iLoopX
  957.     WEND
  958. END SUB ' CircleFill
  959.  
  960. ' /////////////////////////////////////////////////////////////////////////////
  961.  
  962. Sub CircleFillTest
  963.     Dim MyArray(1 To 32, 1 To 32) As String
  964.     Dim iX As Integer
  965.     Dim iY As Integer
  966.     Dim in$
  967.     Dim X As Integer
  968.     Dim Y As Integer
  969.     Dim R As Integer
  970.     Dim iChar As Integer
  971.    
  972.     ClearArray MyArray(), "."
  973.     iChar = 64
  974.    
  975.     Cls
  976.     Print "Plot a filled circle"
  977.     Print "Based on CircleFill by SMcNeill."
  978.     Print
  979.     Print "Enter parameters to draw a circle."
  980.     Print ArrayToStringTest(MyArray())
  981.     Print
  982.    
  983.     Do
  984.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  985.         Print "and radius (1-32) of circle."
  986.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  987.         If X > 0 AND Y > 0 AND R > 0 Then
  988.             iChar = iChar + 1
  989.             If iChar > 90 Then iChar = 65
  990.            
  991.             Print "X=" + cstr$(X)
  992.             Print "Y=" + cstr$(Y)
  993.             Print "R=" + cstr$(R)
  994.            
  995.             'PlotCircle X, Y, R, Chr$(iChar), MyArray()
  996.             CircleFill X, Y, R, Chr$(iChar), MyArray()
  997.            
  998.             Print "Circle plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  999.             Print ArrayToStringTest(MyArray())
  1000.             Print
  1001.         Else
  1002.             Exit Do
  1003.         End If
  1004.     Loop
  1005.    
  1006. End Sub ' CircleFillTest
  1007.  
  1008. ' /////////////////////////////////////////////////////////////////////////////
  1009. ' Based on CircleFill and PlotCircleTopLeft.
  1010. ' CX,CY     = top left point of circle
  1011. ' R         = radius
  1012. ' S         = char to draw
  1013. ' MyArray = 2D string array to plot circle in
  1014.  
  1015. SUB CircleFillTopLeft (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, S As String, MyArray() As String)
  1016.     DIM Radius AS INTEGER
  1017.     Dim RadiusError AS INTEGER
  1018.     DIM X AS INTEGER
  1019.     Dim Y AS INTEGER
  1020.     Dim iLoopX as INTEGER
  1021.     Dim iLoopY as INTEGER
  1022.     ReDim arrTemp(0, 0) As String
  1023.     Dim DY As Integer
  1024.     Dim DX As Integer
  1025.     DIM W As Integer
  1026.         DIM TX As Integer
  1027.         DIM TY As Integer
  1028.         Dim MinY As Integer
  1029.         Dim MaxY As Integer
  1030.         Dim MinX As Integer
  1031.         Dim MaxX As Integer
  1032.    
  1033.     Radius = ABS(R)
  1034.     RadiusError = -Radius
  1035.     X = Radius
  1036.     Y = 0
  1037.    
  1038.     IF Radius = 0 THEN
  1039.         'PSET (CX, CY), C
  1040.         'PlotPoint CX, CY, S, MyArray()
  1041.         EXIT SUB
  1042.     END IF
  1043.    
  1044.     ' Get total width
  1045.     W = (Radius * 2) + 1
  1046.    
  1047.     ' Define a temp array
  1048.     ReDim arrTemp(0 To W, 0 To W) As String
  1049.    
  1050.         ' Get minimum X, Y of target array
  1051.         MinY = lbound(MyArray, 1)
  1052.         MaxY = ubound(MyArray, 1)
  1053.         MinX = lbound(MyArray, 2)
  1054.         MaxX = ubound(MyArray, 2)
  1055.        
  1056.     ' Draw the middle span here so we don't draw it twice in the main loop,
  1057.     ' which would be a problem with blending turned on.
  1058.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  1059.     'FOR iLoopX = CX - X TO CX + X
  1060.     FOR iLoopX = R - X TO R + X
  1061.         'PlotPoint iLoopX, CY, S, MyArray()
  1062.         'PlotPoint iLoopX, CY, S, arrTemp()
  1063.         PlotPoint iLoopX, R, S, arrTemp()
  1064.     NEXT iLoopX
  1065.    
  1066.     WHILE X > Y
  1067.         RadiusError = RadiusError + Y * 2 + 1
  1068.         IF RadiusError >= 0 THEN
  1069.             IF X <> Y + 1 THEN
  1070.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1071.                 'iLoopY = CY - X
  1072.                 iLoopY = R - X
  1073.                 'FOR iLoopX = CX - Y TO CX + Y
  1074.                 FOR iLoopX = R - Y TO R + Y
  1075.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1076.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1077.                 NEXT iLoopX
  1078.                
  1079.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1080.                 'iLoopY = CY + X
  1081.                 iLoopY = R + X
  1082.                 'FOR iLoopX = CX - Y TO CX + Y
  1083.                 FOR iLoopX = R - Y TO R + Y
  1084.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1085.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1086.                 NEXT iLoopX
  1087.             END IF
  1088.             X = X - 1
  1089.             RadiusError = RadiusError - X * 2
  1090.         END IF
  1091.         Y = Y + 1
  1092.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1093.         'iLoopY = CY - Y
  1094.         iLoopY = R - Y
  1095.         'FOR iLoopX = CX - X TO CX + X
  1096.         FOR iLoopX = R - X TO R + X
  1097.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1098.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1099.         NEXT iLoopX
  1100.        
  1101.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1102.         'iLoopY = CY + Y
  1103.         iLoopY = R + Y
  1104.         'FOR iLoopX = CX - X TO CX + X
  1105.         FOR iLoopX = R - X TO R + X
  1106.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1107.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1108.         NEXT iLoopX
  1109.     WEND
  1110.    
  1111.     ' Copy circle to destination Y,X
  1112.     For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  1113.         For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  1114.             IF LEN(arrTemp(DY, DX)) > 0 THEN
  1115.                 TY = DY + CY
  1116.                                 If TY >= MinY Then
  1117.                                         If TY <= MaxY Then
  1118.                                                 TX = DX + CX
  1119.                                                 If TX >= MinX Then
  1120.                                                         If TX <= MaxX Then
  1121.                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1122.                                                         End If
  1123.                                                 End If
  1124.                                         End If
  1125.                                 End If
  1126.             END IF
  1127.         Next DX
  1128.     Next DY
  1129.    
  1130. END SUB ' CircleFillTopLeft
  1131.  
  1132. ' /////////////////////////////////////////////////////////////////////////////
  1133.  
  1134. Sub CircleFillTopLeftTest
  1135.     Dim MyArray(1 To 32, 1 To 32) As String
  1136.     Dim iX As Integer
  1137.     Dim iY As Integer
  1138.     Dim in$
  1139.     Dim X As Integer
  1140.     Dim Y As Integer
  1141.     Dim R As Integer
  1142.     Dim iChar As Integer
  1143.    
  1144.     ClearArray MyArray(), "."
  1145.     iChar = 64
  1146.    
  1147.     Cls
  1148.     Print "Plot a solid circle, specifying top left x,y position"
  1149.     Print "Based on CircleFill by SMcNeill."
  1150.     Print
  1151.     Print "Enter parameters to draw a circle."
  1152.     Print ArrayToStringTest(MyArray())
  1153.     Print
  1154.    
  1155.     Do
  1156.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot circle,"
  1157.         Print "and radius (1-32) of circle."
  1158.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  1159.         If X > 0 AND Y > 0 AND R > 0 Then
  1160.             iChar = iChar + 1
  1161.             If iChar > 90 Then iChar = 65
  1162.            
  1163.             Print "X=" + cstr$(X)
  1164.             Print "Y=" + cstr$(Y)
  1165.             Print "R=" + cstr$(R)
  1166.            
  1167.             CircleFillTopLeft X, Y, R, Chr$(iChar), MyArray()
  1168.            
  1169.             Print "Circle plotted (from top left), drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1170.             Print ArrayToStringTest(MyArray())
  1171.             Print
  1172.         Else
  1173.             Exit Do
  1174.         End If
  1175.     Loop
  1176.    
  1177. End Sub ' CircleFillTopLeftTest
  1178.  
  1179. ' /////////////////////////////////////////////////////////////////////////////
  1180. ' Based on CircleFill and PlotSemiCircle
  1181.  
  1182. ' CX,CY   = top left point of circle
  1183. ' R       = radius
  1184. ' Q       = which quarter of the circle to return semicircle from
  1185. '           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
  1186. '           like this:
  1187.             ' .......4444111.......
  1188.             ' .....44444411111.....
  1189.             ' ....4444444111111....
  1190.             ' ...444444441111111...
  1191.             ' ..44444444411111111..
  1192.             ' .4444444444111111111.
  1193.             ' .4444444444111111111.
  1194.             ' 444444444441111111111
  1195.             ' 444444444441111111111
  1196.             ' 444444444441111111111
  1197.             ' 333333333331111111111
  1198.             ' 333333333332222222222
  1199.             ' 333333333332222222222
  1200.             ' 333333333332222222222
  1201.             ' .3333333333222222222.
  1202.             ' .3333333333222222222.
  1203.             ' ..33333333322222222..
  1204.             ' ...333333332222222...
  1205.             ' ....3333333222222....
  1206.             ' .....33333322222.....
  1207.             ' .......3333222.......
  1208. ' S       = char to draw
  1209. ' MyArray = 2D string array to plot semicircle in
  1210.  
  1211. SUB SemiCircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, Q AS INTEGER, S As String, MyArray() As String)
  1212.     DIM Radius AS INTEGER
  1213.     Dim RadiusError AS INTEGER
  1214.     DIM X AS INTEGER
  1215.     Dim Y AS INTEGER
  1216.     Dim iLoopX as INTEGER
  1217.     Dim iLoopY as INTEGER
  1218.     ReDim arrTemp(0, 0) As String
  1219.     Dim DY As Integer
  1220.     Dim DX As Integer
  1221.     DIM W As Integer
  1222.     DIM AX As Integer
  1223.         DIM AY As Integer
  1224.         DIM TX As Integer
  1225.         DIM TY As Integer
  1226.         Dim MinY As Integer
  1227.         Dim MaxY As Integer
  1228.         Dim MinX As Integer
  1229.         Dim MaxX As Integer
  1230.        
  1231.     Radius = ABS(R)
  1232.     RadiusError = -Radius
  1233.     X = Radius
  1234.     Y = 0
  1235.    
  1236.     IF Radius = 0 THEN
  1237.         'PSET (CX, CY), C
  1238.         'PlotPoint CX, CY, S, MyArray()
  1239.         EXIT SUB
  1240.     END IF
  1241.    
  1242.     ' Get total width
  1243.     W = (Radius * 2) + 1
  1244.    
  1245.     ' Define a temp array
  1246.     ReDim arrTemp(0 To W, 0 To W) As String
  1247.    
  1248.         ' Get minimum X, Y of target array
  1249.         MinY = lbound(MyArray, 1)
  1250.         MaxY = ubound(MyArray, 1)
  1251.         MinX = lbound(MyArray, 2)
  1252.         MaxX = ubound(MyArray, 2)
  1253.        
  1254.         ' Temp array's lbound is 0
  1255.         ' Calculate difference from MyArray the indices of arrTemp are
  1256.         AY = 0 - MinY
  1257.         AX = 0 - MinX
  1258.        
  1259.     ' Draw the middle span here so we don't draw it twice in the main loop,
  1260.     ' which would be a problem with blending turned on.
  1261.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  1262.     'FOR iLoopX = CX - X TO CX + X
  1263.     FOR iLoopX = R - X TO R + X
  1264.         'PlotPoint iLoopX, CY, S, MyArray()
  1265.         'PlotPoint iLoopX, CY, S, arrTemp()
  1266.         PlotPoint iLoopX, R, S, arrTemp()
  1267.     NEXT iLoopX
  1268.    
  1269.     WHILE X > Y
  1270.         RadiusError = RadiusError + Y * 2 + 1
  1271.         IF RadiusError >= 0 THEN
  1272.             IF X <> Y + 1 THEN
  1273.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1274.                 'iLoopY = CY - X
  1275.                 iLoopY = R - X
  1276.                 'FOR iLoopX = CX - Y TO CX + Y
  1277.                 FOR iLoopX = R - Y TO R + Y
  1278.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1279.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1280.                 NEXT iLoopX
  1281.                
  1282.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1283.                 'iLoopY = CY + X
  1284.                 iLoopY = R + X
  1285.                 'FOR iLoopX = CX - Y TO CX + Y
  1286.                 FOR iLoopX = R - Y TO R + Y
  1287.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1288.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1289.                 NEXT iLoopX
  1290.             END IF
  1291.             X = X - 1
  1292.             RadiusError = RadiusError - X * 2
  1293.         END IF
  1294.         Y = Y + 1
  1295.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1296.         'iLoopY = CY - Y
  1297.         iLoopY = R - Y
  1298.         'FOR iLoopX = CX - X TO CX + X
  1299.         FOR iLoopX = R - X TO R + X
  1300.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1301.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1302.         NEXT iLoopX
  1303.        
  1304.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1305.         'iLoopY = CY + Y
  1306.         iLoopY = R + Y
  1307.         'FOR iLoopX = CX - X TO CX + X
  1308.         FOR iLoopX = R - X TO R + X
  1309.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1310.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1311.         NEXT iLoopX
  1312.     WEND
  1313.        
  1314.         '_echo "MyArray(" + _Trim$(Str$(lbound(MyArray,1))) + " To " + _Trim$(Str$(ubound(MyArray,1))) + ", " + _Trim$(Str$(lbound(MyArray,2))) + " To " + _Trim$(Str$(ubound(MyArray,2))) + ")"
  1315.        
  1316.     ' Copy semicircle to destination Y,X
  1317.         ' JUST COPY SELECTED QUADRANT:
  1318.         Select Case Q
  1319.                 Case 1:
  1320.                         ' quadrant #1
  1321.                         For DY = 0 to Radius
  1322.                                 For DX = Radius to W
  1323.                                         '_echo "DY=" + cstr$(DY) + ", DX=" + cstr$(DX)
  1324.                                         IF LEN(arrTemp(DY, DX)) > 0 THEN
  1325.                                                 TY = (DY + CY) - (AY+1)
  1326.                                                 If TY >= MinY Then
  1327.                                                         If TY <= MaxY Then
  1328.                                                                 TX = (DX - Radius) - AX
  1329.                                                                 If TX >= MinX Then
  1330.                                                                         If TX <= MaxX Then
  1331.                                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1332.                                                                         End If
  1333.                                                                 End If
  1334.                                                         End If
  1335.                                                 End If
  1336.                                         END IF
  1337.                                 Next DX
  1338.                         Next DY
  1339.                 Case 2:
  1340.                         ' quadrant #2
  1341.                         For DY = Radius to W
  1342.                                 For DX = Radius to W
  1343.                                         IF LEN(arrTemp(DY, DX)) > 0 THEN
  1344.                                                 TY = (DY - Radius) - AY
  1345.                                                 If TY >= MinY Then
  1346.                                                         If TY <= MaxY Then
  1347.                                                                 TX = (DX - Radius) - AX
  1348.                                                                 If TX >= MinX Then
  1349.                                                                         If TX <= MaxX Then
  1350.                                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1351.                                                                         End If
  1352.                                                                 End If
  1353.                                                         End If
  1354.                                                 End If
  1355.                                         END IF
  1356.                                 Next DX
  1357.                         Next DY
  1358.                 Case 3:
  1359.                         ' quadrant #3
  1360.                         For DY = Radius to W
  1361.                                 For DX = 0 to Radius
  1362.                                         IF LEN(arrTemp(DY, DX)) > 0 THEN
  1363.                                                 TY = (DY - Radius) - AY
  1364.                                                 If TY >= MinY Then
  1365.                                                         If TY <= MaxY Then
  1366.                                                                 TX = (DX + CX) - (AX+1)
  1367.                                                                 If TX >= MinX Then
  1368.                                                                         If TX <= MaxX Then
  1369.                                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1370.                                                                         End If
  1371.                                                                 End If
  1372.                                                         End If
  1373.                                                 End If
  1374.                                         END IF
  1375.                                 Next DX
  1376.                         Next DY
  1377.                 Case 4:
  1378.                         ' quadrant #4
  1379.                         For DY = 0 to Radius
  1380.                                 For DX = 0 to Radius
  1381.                                         IF LEN(arrTemp(DY, DX)) > 0 THEN
  1382.                                                 TY = (DY + CY) - (AY+1)
  1383.                                                 If TY >= MinY Then
  1384.                                                         If TY <= MaxY Then
  1385.                                                                 TX = (DX + CX) - (AX+1)
  1386.                                                                 If TX >= MinX Then
  1387.                                                                         If TX <= MaxX Then
  1388.                                                                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1389.                                                                         End If
  1390.                                                                 End If
  1391.                                                         End If
  1392.                                                 End If
  1393.                                         END IF
  1394.                                 Next DX
  1395.                         Next DY
  1396.                 Case Else:
  1397.                         ' (DO NOTHING)
  1398.         End Select
  1399.    
  1400.         '' Copy circle to destination:
  1401.         'For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  1402.     '    For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  1403.     '        IF LEN(arrTemp(DY, DX)) > 0 THEN
  1404.     '            MyArray(DY + CY, DX + CX) = arrTemp(DY, DX)
  1405.     '        END IF
  1406.     '    Next DX
  1407.     'Next DY
  1408.    
  1409. END SUB ' SemiCircleFill
  1410.  
  1411. ' /////////////////////////////////////////////////////////////////////////////
  1412.  
  1413. Sub SemiCircleFillTest
  1414.     Dim MyArray(1 To 32, 1 To 32) As String
  1415.     Dim iX As Integer
  1416.     Dim iY As Integer
  1417.     Dim in$
  1418.     Dim X As Integer
  1419.     Dim Y As Integer
  1420.     Dim R As Integer
  1421.     Dim Q As Integer
  1422.     Dim iChar As Integer
  1423.    
  1424.     ClearArray MyArray(), "."
  1425.     iChar = 64
  1426.    
  1427.     Cls
  1428.     Print "Plot a solid semicircle"
  1429.     Print "Based on CircleFill by SMcNeill."
  1430.     Print
  1431.     Print "Enter parameters to draw a semicircle."
  1432.     Print ArrayToStringTest(MyArray())
  1433.     Print
  1434.    
  1435.     Do
  1436.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot semicircle,"
  1437.         Print "radius (1-32) of semicircle, and quadrant of circle to use:"
  1438.         Print "41"
  1439.         Print "32"
  1440.         Input "X,Y,R,Q OR 0 TO QUIT: "; X, Y, R, Q
  1441.         If X > 0 AND Y > 0 AND R > 0 Then
  1442.             iChar = iChar + 1
  1443.             If iChar > 90 Then iChar = 65
  1444.            
  1445.             Print "X=" + cstr$(X)
  1446.             Print "Y=" + cstr$(Y)
  1447.             Print "R=" + cstr$(R)
  1448.            
  1449.             SemiCircleFill X, Y, R, Q, Chr$(iChar), MyArray()
  1450.            
  1451.             Print "Semicircle plotted (from top left), drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1452.             Print ArrayToStringTest(MyArray())
  1453.             Print
  1454.         Else
  1455.             Exit Do
  1456.         End If
  1457.     Loop
  1458.    
  1459. End Sub ' SemiCircleFillTest
  1460.  
  1461. ' /////////////////////////////////////////////////////////////////////////////
  1462. ' Re: Is this fast enough as general circle fill?
  1463. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  1464.  
  1465. ' From: bplus
  1466. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  1467.  
  1468. SUB Ellipse (CX AS INTEGER, CY AS INTEGER, xRadius AS INTEGER, yRadius AS INTEGER, S As String, MyArray() As String)
  1469.     DIM scale AS SINGLE
  1470.     DIM xs AS INTEGER
  1471.     DIM x AS INTEGER
  1472.     DIM y AS INTEGER
  1473.     DIM lastx AS INTEGER
  1474.     DIM lasty AS INTEGER
  1475.     Dim iLoopX as INTEGER
  1476.     Dim iLoopY as INTEGER
  1477.    
  1478.     scale = yRadius / xRadius
  1479.     xs = xRadius * xRadius
  1480.    
  1481.     'PSET (CX, CY - yRadius)
  1482.     PlotPoint CX, CY - yRadius, S, MyArray()
  1483.    
  1484.     'PSET (CX, CY + yRadius)
  1485.     PlotPoint CX, CY + yRadius, S, MyArray()
  1486.    
  1487.     lastx = 0: lasty = yRadius
  1488.     FOR x = 1 TO xRadius
  1489.         y = scale * SQR(xs - x * x)
  1490.         'LINE (CX + lastx, CY - lasty)-(CX + x, CY - y)
  1491.         PlotLine CX + lastx, CY - lasty, CX + x, CY - y, S, MyArray()
  1492.        
  1493.         'LINE (CX + lastx, CY + lasty)-(CX + x, CY + y)
  1494.         PlotLine CX + lastx, CY + lasty, CX + x, CY + y, S, MyArray()
  1495.        
  1496.         'LINE (CX - lastx, CY - lasty)-(CX - x, CY - y)
  1497.         PlotLine CX - lastx, CY - lasty, CX - x, CY - y, S, MyArray()
  1498.        
  1499.         'LINE (CX - lastx, CY + lasty)-(CX - x, CY + y)
  1500.         PlotLine CX - lastx, CY + lasty, CX - x, CY + y, S, MyArray()
  1501.        
  1502.         lastx = x
  1503.         lasty = y
  1504.     NEXT x
  1505. END SUB ' Ellipse
  1506.  
  1507. ' /////////////////////////////////////////////////////////////////////////////
  1508.  
  1509. Sub EllipseTest
  1510.     Dim MyArray(1 To 32, 1 To 32) As String
  1511.     Dim iX As Integer
  1512.     Dim iY As Integer
  1513.     Dim in$
  1514.     Dim X As Integer
  1515.     Dim Y As Integer
  1516.     Dim RX As Integer
  1517.     Dim RY As Integer
  1518.     Dim iChar As Integer
  1519.    
  1520.     ClearArray MyArray(), "."
  1521.     iChar = 64
  1522.    
  1523.     Cls
  1524.     Print "Plot an ellipse"
  1525.     Print "Based on ellipse by bplus."
  1526.     Print
  1527.     Print "Enter parameters to draw an ellipse."
  1528.     Print ArrayToStringTest(MyArray())
  1529.     Print
  1530.    
  1531.     Do
  1532.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  1533.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  1534.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  1535.         If X > 0 AND Y > 0 AND RX > 0 AND RY > 0 Then
  1536.             iChar = iChar + 1
  1537.             If iChar > 90 Then iChar = 65
  1538.            
  1539.             Print "X =" + cstr$(X)
  1540.             Print "Y =" + cstr$(Y)
  1541.             Print "RX=" + cstr$(RX)
  1542.             Print "RY=" + cstr$(RY)
  1543.            
  1544.             Ellipse X, Y, RX, RY, Chr$(iChar), MyArray()
  1545.            
  1546.             Print "Ellipse plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1547.             Print ArrayToStringTest(MyArray())
  1548.             Print
  1549.         Else
  1550.             Exit Do
  1551.         End If
  1552.     Loop
  1553.    
  1554. End Sub ' EllipseTest
  1555.  
  1556. ' /////////////////////////////////////////////////////////////////////////////
  1557. ' Re: Is this fast enough as general circle fill?
  1558. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  1559.  
  1560. ' From: bplus
  1561. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  1562. '
  1563. ' Here is my ellipse and filled ellipse routines, no where near
  1564. ' Steve's level of performance. The speed is cut in half at
  1565. ' least because you probably have to do a whole quadrants worth
  1566. ' of calculations (ellipse not as symmetric as circle).
  1567. '
  1568. ' But I am sure this code can be optimized more than it is:
  1569.  
  1570. SUB EllipseFill (CX AS INTEGER, CY AS INTEGER, xRadius AS INTEGER, yRadius AS INTEGER, S As String, MyArray() As String)
  1571.     DIM scale AS SINGLE
  1572.     DIM x AS INTEGER
  1573.     DIM y AS INTEGER
  1574.     Dim iLoopX as INTEGER
  1575.     Dim iLoopY as INTEGER
  1576.    
  1577.     scale = yRadius / xRadius
  1578.    
  1579.     'LINE (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  1580.     FOR iLoopY = CY - yRadius TO CY + yRadius
  1581.         PlotPoint CX, iLoopY, S, MyArray()
  1582.     NEXT iLoopY
  1583.    
  1584.     FOR x = 1 TO xRadius
  1585.         y = scale * SQR(xRadius * xRadius - x * x)
  1586.        
  1587.         'LINE (CX + x, CY - y)-(CX + x, CY + y), , BF
  1588.         iLoopX = CX + x
  1589.         FOR iLoopY = CY - y TO  CY + y
  1590.             PlotPoint iLoopX, iLoopY, S, MyArray()
  1591.         NEXT iLoopY
  1592.        
  1593.         'LINE (CX - x, CY - y)-(CX - x, CY + y), , BF
  1594.         iLoopX = CX - x
  1595.         FOR iLoopY = CY - y TO CY + y
  1596.             PlotPoint iLoopX, iLoopY, S, MyArray()
  1597.         NEXT iLoopY
  1598.     NEXT x
  1599. END SUB ' EllipseFill
  1600.  
  1601. ' /////////////////////////////////////////////////////////////////////////////
  1602.  
  1603. Sub EllipseFillTest
  1604.     Dim MyArray(1 To 32, 1 To 32) As String
  1605.     Dim iX As Integer
  1606.     Dim iY As Integer
  1607.     Dim in$
  1608.     Dim X As Integer
  1609.     Dim Y As Integer
  1610.     Dim RX As Integer
  1611.     Dim RY As Integer
  1612.     Dim iChar As Integer
  1613.    
  1614.     ClearArray MyArray(), "."
  1615.     iChar = 64
  1616.    
  1617.     Cls
  1618.     Print "Plot a filled ellipse"
  1619.     Print "Based on fellipse by bplus."
  1620.     Print
  1621.     Print "Enter parameters to draw an ellipse."
  1622.     Print ArrayToStringTest(MyArray())
  1623.     Print
  1624.    
  1625.     Do
  1626.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  1627.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  1628.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  1629.         If X > 0 AND Y > 0 AND RX > 0 AND RY > 0 Then
  1630.             iChar = iChar + 1
  1631.             If iChar > 90 Then iChar = 65
  1632.            
  1633.             Print "X =" + cstr$(X)
  1634.             Print "Y =" + cstr$(Y)
  1635.             Print "RX=" + cstr$(RX)
  1636.             Print "RY=" + cstr$(RY)
  1637.            
  1638.             EllipseFill X, Y, RX, RY, Chr$(iChar), MyArray()
  1639.            
  1640.             Print "Ellipse plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1641.             Print ArrayToStringTest(MyArray())
  1642.             Print
  1643.         Else
  1644.             Exit Do
  1645.         End If
  1646.     Loop
  1647.    
  1648. End Sub ' EllipseFillTest
  1649.  
  1650. ' /////////////////////////////////////////////////////////////////////////////
  1651. ' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
  1652. ' From: http://www.thedubber.altervista.org/qbsrc.htm
  1653.  
  1654. Sub PlotLine (x1%, y1%, x2%, y2%, c$, MyArray() As String)
  1655.     Dim iLoop%
  1656.     Dim steep%: steep% = 0
  1657.     Dim ev%: ev% = 0
  1658.     Dim sx%
  1659.     Dim sy%
  1660.     Dim dx%
  1661.     Dim dy%
  1662.    
  1663.     If (x2% - x1%) > 0 Then
  1664.         sx% = 1
  1665.     Else
  1666.         sx% = -1
  1667.     End If
  1668.  
  1669.     dx% = Abs(x2% - x1%)
  1670.     If (y2% - y1%) > 0 Then
  1671.         sy% = 1
  1672.     Else
  1673.         sy% = -1
  1674.     End If
  1675.  
  1676.     dy% = Abs(y2% - y1%)
  1677.     If (dy% > dx%) Then
  1678.         steep% = 1
  1679.         Swap x1%, y1%
  1680.         Swap dx%, dy%
  1681.         Swap sx%, sy%
  1682.     End If
  1683.  
  1684.     ev% = 2 * dy% - dx%
  1685.     For iLoop% = 0 To dx% - 1
  1686.         If steep% = 1 Then
  1687.             ''PSET (y1%, x1%), c%:
  1688.             'LOCATE y1%, x1%
  1689.             'PRINT c$;
  1690.             PlotPoint y1%, x1%, c$, MyArray()
  1691.         Else
  1692.             ''PSET (x1%, y1%), c%
  1693.             'LOCATE x1%, y1%
  1694.             'PRINT c$;
  1695.             PlotPoint x1%, y1%, c$, MyArray()
  1696.         End If
  1697.  
  1698.         While ev% >= 0
  1699.             y1% = y1% + sy%
  1700.             ev% = ev% - 2 * dx%
  1701.         Wend
  1702.         x1% = x1% + sx%
  1703.         ev% = ev% + 2 * dy%
  1704.     Next iLoop%
  1705.     ''PSET (x2%, y2%), c%
  1706.     'LOCATE x2%, y2%
  1707.     'PRINT c$;
  1708.     PlotPoint x2%, y2%, c$, MyArray()
  1709. End Sub ' PlotLine
  1710.  
  1711. ' /////////////////////////////////////////////////////////////////////////////
  1712.  
  1713. Sub PlotLineTest
  1714.     Dim MyArray(1 To 32, 1 To 32) As String
  1715.     Dim in$
  1716.     Dim X1 As Integer
  1717.     Dim Y1 As Integer
  1718.     Dim X2 As Integer
  1719.     Dim Y2 As Integer
  1720.     Dim iChar As Integer
  1721.    
  1722.     ClearArray MyArray(), "."
  1723.     iChar = 64
  1724.    
  1725.     Cls
  1726.     Print "Plot line with Bresenham Algorithm"
  1727.     Print "based on BRESNHAM.BAS by Kurt Kuzba (4/16/96)."
  1728.     Print
  1729.     Print ArrayToStringTest(MyArray())
  1730.     Do
  1731.         Print "Enter coordinate values for "
  1732.         Print "line start point x1, y1 (1-32, 1-32)"
  1733.         Print "line end   point x2, y2 (1-32, 1-32)"
  1734.         Input "ENTER X1,Y1,X2,Y2 OR 0 TO QUIT: "; X1, Y1, X2, Y2
  1735.         If X1 > 0 And Y1 > 0 And X2 > 0 And Y2 > 0 Then
  1736.             iChar = iChar + 1
  1737.             If iChar > 90 Then iChar = 65
  1738.            
  1739.             Print "X1=" + cstr$(X1)
  1740.             Print "Y1=" + cstr$(Y1)
  1741.             Print "X2=" + cstr$(X2)
  1742.             Print "Y2=" + cstr$(Y2)
  1743.            
  1744.             PlotLine X1, Y1, X2, Y2, Chr$(iChar), MyArray()
  1745.            
  1746.             Print "Line plotted, drawn with " + chr$(34) + chr$(iChar) + chr$(34) + ":"
  1747.             Print ArrayToStringTest(MyArray())
  1748.            
  1749.         Else
  1750.             Exit Do
  1751.         End If
  1752.     Loop
  1753. End Sub ' PlotLineTest
  1754.  
  1755. ' /////////////////////////////////////////////////////////////////////////////
  1756. ' 3 shear method testing
  1757.  
  1758. ' _PUT Rotation Help
  1759. ' https://www.qb64.org/forum/index.php?topic=1959.0
  1760.  
  1761. ' 3 Shear Rotation - rotates without any aliasing(holes)
  1762. ' https://www.freebasic.net/forum/viewtopic.php?t=24557
  1763.  
  1764. ' From: leopardpm
  1765. ' Date: Apr 02, 2016 1:21
  1766. ' Last edited by leopardpm on Apr 02, 2016 17:18, edited 1 time in total.
  1767. '
  1768. ' This is just a little 3-shear rotation routine
  1769. ' (I am using 3-shear because it leaves no gaps/aliasing)
  1770. ' that I was wondering if anyone sees how to make it faster.
  1771. ' Obviously, I am just thinking about inside the double loop.
  1772.  
  1773. ' Thanks again to BasicCoder2 for linking me to this little routine, it is wonderful so far!
  1774.  
  1775. '''                      roto-zooming algorithm
  1776. '''                    coded by Michael S. Nissen
  1777. '''                        jernmager@yahoo.dk
  1778. '
  1779. ''' ===============================================================
  1780. ''' Recoded to run on FBC 32/64 bit WIN, Version 1.05.0, 2016, by MrSwiss
  1781. ''' Heavy flickering before going Full-Screen on 64 Bit !!!
  1782. ''' This seems NOT to be the Case on 32 Bit ...
  1783. ''' ===============================================================
  1784. '
  1785. 'Type Pixel
  1786. '  As Single   X, Y
  1787. '  As ULong    C
  1788. 'End Type
  1789. '
  1790. '''  dim vars
  1791. 'Dim shared as Any Ptr Img_Buffer
  1792. '''  write the name of the .bmp image you want to rotozoom here:
  1793. '''  (it has to be sqare ie. 100x100 pixels, 760x760 pixels or whatever)
  1794. 'Dim As String Img_Name = "phobos.bmp"
  1795. 'Dim shared as Integer X_Mid, Y_Mid, scrn_wid, scrn_hgt, P1, P2, P3, P4, C
  1796. 'Dim shared as Short Img_Hgt, Img_Wid, Img_Lft, Img_Rgt, Img_Top, Img_Btm, X, Y
  1797. 'Dim Shared As Single Cos_Ang, Sin_Ang, Rot_Fac_X, Rot_Fac_Y, Angle = 0, Scale = 1
  1798. '
  1799. ''' changed Function to Sub (+ recoded arguments list)
  1800. 'Sub Calc_rotozoom ( ByRef Cos_Ang As Single, _
  1801. '               ByRef Sin_Ang As Single, _
  1802. '               ByVal S_Fact  As Single, _
  1803. '               ByVal NewAng  As Single )
  1804. '  Cos_Ang = Cos(NewAng)*S_Fact
  1805. '  Sin_Ang = Sin(NewAng)*S_Fact
  1806. 'End Sub
  1807. '
  1808. '''  full screen
  1809. 'ScreenInfo scrn_wid, scrn_hgt
  1810. 'screenRes scrn_wid, scrn_hgt, 32,,1
  1811. '
  1812. '''  dim screenpointer (has to be done after screenres)
  1813. 'Dim As ULong Ptr Scrn_Ptr = Screenptr
  1814. '
  1815. '''  place image in center of screen
  1816. 'X_Mid = scrn_wid\2
  1817. 'Y_Mid = scrn_hgt\2
  1818. 'Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1819. '
  1820. '''  find image dimensions
  1821. 'Open Img_Name For Binary As #1
  1822. 'Get #1, 19, Img_Wid
  1823. 'Get #1, 23, Img_Hgt
  1824. 'Close #1
  1825. '
  1826. '''  prepare to dim the array that will hold the image.
  1827. 'Img_Rgt = (Img_Wid-1)\2
  1828. 'Img_Lft = -Img_Rgt
  1829. 'Img_Btm = (Img_Hgt-1)\2
  1830. 'Img_Top = -Img_Btm
  1831. '
  1832. '''  dim array to hold image. Note: pixel (0, 0) is in the center.
  1833. 'Dim As Pixel Pixel(Img_Lft to Img_Rgt, Img_Top to Img_Btm)
  1834. '
  1835. '''  imagecreate sprite and load image to sprite
  1836. 'Img_Buffer = ImageCreate (Img_Wid, Img_Hgt)
  1837. 'Bload (Img_Name, Img_Buffer)
  1838. '
  1839. '''  load image from sprite to array with point command
  1840. 'For Y = Img_Top to Img_Btm
  1841. '  For X = Img_Lft to Img_Rgt
  1842. '    With Pixel(X, Y)
  1843. '      .X = X_Mid+X
  1844. '      .Y = Y_Mid+Y
  1845. '      C = Point (X-Img_Top, Y-Img_Lft, Img_buffer)
  1846. '      If C <> RGB(255, 0, 255) Then
  1847. '        .C = C
  1848. '      Else
  1849. '        .C = RGB(0, 0, 0)
  1850. '      End If
  1851. '    End With
  1852. '  Next X
  1853. 'Next Y
  1854. '
  1855. '''  we don't need the sprite anymore, kill it
  1856. 'ImageDestroy Img_Buffer
  1857. 'Img_Buffer = 0
  1858. '
  1859. '''  main program loop
  1860. 'Do
  1861. '
  1862. '  ''  scale in/out with uparrow/downarrow
  1863. '  If Multikey(80) Then
  1864. '    Scale *= 1.03
  1865. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1866. '  ElseIf Multikey(72) Then
  1867. '    Scale *= 0.97
  1868. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1869. '  End If
  1870. '
  1871. '  ''  rotate left/right with leftarrow/rightarrow
  1872. '  If Multikey(77) Then
  1873. '    Angle -= 0.03
  1874. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1875. '  ElseIf Multikey(75) Then
  1876. '    Angle += 0.03
  1877. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1878. '  End If
  1879. '
  1880. '  ''  lock screen in order to use screen pointers
  1881. '  ScreenLock
  1882. '
  1883. '    ''  draw pixel in center of image
  1884. '    Scrn_Ptr[ X_Mid + Y_Mid * scrn_wid ] = Pixel(0, 0).C
  1885. '    ''  draw all other pixels - 4 at a time
  1886. '    For Y = Img_Top to 0
  1887. '      For X = Img_Lft to -1
  1888. '        ''  find pixel positions
  1889. '        P1 = (X_Mid+X) + (Y_Mid+Y) * scrn_wid
  1890. '        P2 = (X_Mid-X) + (Y_Mid-Y) * scrn_wid
  1891. '        P3 = (X_Mid+Y) + (Y_Mid-X) * scrn_wid
  1892. '        P4 = (X_Mid-Y) + (Y_Mid+X) * scrn_wid
  1893. '        ''  erase old pixels (paint them black)
  1894. '        Scrn_Ptr[P1] = 0
  1895. '        Scrn_Ptr[P2] = 0
  1896. '        Scrn_Ptr[P3] = 0
  1897. '        Scrn_Ptr[P4] = 0
  1898. '        ''  rotate and zoom
  1899. '        Rot_Fac_X = X*Cos_Ang - Y*Sin_Ang
  1900. '        Rot_Fac_Y = X*Sin_Ang + Y*Cos_Ang
  1901. '        If Rot_Fac_X < Img_Lft Or Rot_Fac_X > Img_Rgt Then Continue For
  1902. '        If Rot_Fac_Y < Img_Top Or Rot_Fac_Y > Img_Btm Then Continue For
  1903. '        ''  draw new pixels
  1904. '        Scrn_Ptr[P1] = Pixel(Rot_Fac_X, Rot_Fac_Y).C
  1905. '        Scrn_Ptr[P2] = Pixel(-Rot_Fac_X, -Rot_Fac_Y).C
  1906. '        Scrn_Ptr[P3] = Pixel(Rot_Fac_Y, -Rot_Fac_X).C
  1907. '        Scrn_Ptr[P4] = Pixel(-Rot_Fac_Y, Rot_Fac_X).C
  1908. '      Next X
  1909. '    Next Y
  1910. '
  1911. '  ScreenUnLock
  1912. '
  1913. '  Sleep 10, 1
  1914. 'Loop Until InKey() = Chr(27)
  1915.  
  1916. ' UPDATES:
  1917. ' Fixed bug where values 135, 224, and 314 all resolve to -45 degrees.
  1918. ' Fixed bug where an angle of 46-135 degrees caused the image to be flipped wrong.
  1919.  
  1920. ' TODO:
  1921. ' Fix issue where image looks bad at 30, 60, 120, 150, 210, 240, 300, 330 degrees
  1922.  
  1923. Sub ShearRotate (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  1924.     Const Pi = 4 * Atn(1)
  1925.    
  1926.     Dim angle As Integer
  1927.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  1928.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  1929.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  1930.     Dim x As Integer
  1931.     Dim y As Integer
  1932.     Dim nangle As Integer
  1933.     Dim nx As Integer
  1934.     Dim ny As Integer
  1935.     Dim flipper As Integer
  1936.     Dim rotr As Double
  1937.     Dim shear1 As Double
  1938.     Dim shear2 As Double
  1939.     Dim clr As Integer
  1940.     Dim y1 As _Byte
  1941.     Dim xy1 As _Byte
  1942.     Dim fy As _Byte
  1943.     Dim fx As _Byte
  1944.     Dim in$
  1945.     Dim sLine As String
  1946.    
  1947.     ' initialize new with empty
  1948.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  1949.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1950.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1951.             NewArray(x, y, 0).origx = x
  1952.             NewArray(x, y, 0).origy = y
  1953.             NewArray(x, y, 0).c = iEmpty
  1954.         Next y
  1955.     Next x
  1956.    
  1957.     ' angle is reversed
  1958.     angle = 360 - angle1
  1959.    
  1960.     ' Shearing each element 3 times in one shot
  1961.     nangle = angle
  1962.    
  1963.     ' this pre-processing portion basically rotates by 90 to get
  1964.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  1965.     If angle > 45 And angle < 225 Then
  1966.         If angle < 135 Then
  1967.             nangle = angle - 90
  1968.         Else
  1969.             nangle = angle - 180
  1970.         End If
  1971.     End If
  1972.     If angle > 135 And angle < 315 Then
  1973.         If angle < 225 Then
  1974.             nangle = angle - 180
  1975.         Else
  1976.             nangle = angle - 270
  1977.         End If
  1978.     End If
  1979.     If nangle < 0 Then
  1980.         nangle = nangle + 360
  1981.     End If
  1982.     If nangle > 359 Then
  1983.         nangle = nangle - 360
  1984.     End If
  1985.    
  1986.     rotr = nangle * DtoR
  1987.     shear1 = Tan(rotr / 2) ' correct way
  1988.     shear2 = Sin(rotr)
  1989.    
  1990.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  1991.     ' ***       all resolve to -45 degrees.
  1992.     ' ***       Fixed by changing < to <=
  1993.    
  1994.     'if angle >  45 and angle < 134 then
  1995.     If angle > 45 And angle <= 134 Then
  1996.         flipper = 1
  1997.     ElseIf angle > 134 And angle <= 224 Then
  1998.         flipper = 2
  1999.     ElseIf angle > 224 And angle <= 314 Then
  2000.         ' *** NOTE: this had a bug where this flipper was wrong
  2001.         '           Fixed by adding case 7
  2002.         'flipper = 3
  2003.         flipper = 7
  2004.     Else
  2005.         flipper = 0
  2006.     End If
  2007.    
  2008.     ' Here is where it needs some optimizing possibly... kinda slow...
  2009.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2010.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2011.             Select Case flipper
  2012.                 Case 1:
  2013.                     nx = -y
  2014.                     ny = x
  2015.                 Case 2:
  2016.                     nx = -x
  2017.                     ny = -y
  2018.                 Case 3:
  2019.                     nx = -y
  2020.                     ny = -x
  2021.                 Case 4:
  2022.                     nx = -x
  2023.                     ny = y
  2024.                 Case 5:
  2025.                     nx = x
  2026.                     ny = -y
  2027.                 Case 6:
  2028.                     nx = y
  2029.                     ny = x
  2030.                 Case 7:
  2031.                     nx = y
  2032.                     ny = -x
  2033.                 Case Else:
  2034.                     nx = x
  2035.                     ny = y
  2036.             End Select
  2037.            
  2038.             clr = OldArray(nx, ny, 0).c
  2039.            
  2040.             y1 = y * shear1
  2041.             xy1 = x + y1
  2042.             fy = (y - xy1 * shear2)
  2043.             fx = xy1 + fy * shear1
  2044.            
  2045.             If fx >= -16 And fx <= 16 Then
  2046.                 If fy >= -16 And fy <= 16 Then
  2047.                     NewArray(fx, fy, 0).c = clr
  2048.                     NewArray(fx, fy, 0).origx = fx
  2049.                     NewArray(fx, fy, 0).origy = fy
  2050.                 End If
  2051.             End If
  2052.         Next x
  2053.     Next y
  2054. End Sub ' ShearRotate
  2055.  
  2056. ' /////////////////////////////////////////////////////////////////////////////
  2057. ' Same as ShearRotate, except adds iOverwriteCount parameter,
  2058. ' and counts how many points are overwriting existing points,
  2059. ' and return that value byref in parameter iOverwriteCount.
  2060.  
  2061. Sub ShearRotate1 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iOverwriteCount As Integer)
  2062.     Const Pi = 4 * Atn(1)
  2063.    
  2064.     Dim angle As Integer
  2065.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2066.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2067.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2068.     Dim x As Integer
  2069.     Dim y As Integer
  2070.     Dim nangle As Integer
  2071.     Dim nx As Integer
  2072.     Dim ny As Integer
  2073.     Dim flipper As Integer
  2074.     Dim rotr As Double
  2075.     Dim shear1 As Double
  2076.     Dim shear2 As Double
  2077.     Dim clr As Integer
  2078.     Dim y1 As _Byte
  2079.     Dim xy1 As _Byte
  2080.     Dim fy As _Byte
  2081.     Dim fx As _Byte
  2082.     Dim in$
  2083.     Dim sLine As String
  2084.    
  2085.     ' initialize new with empty
  2086.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2087.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2088.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2089.             NewArray(x, y, 0).origx = x
  2090.             NewArray(x, y, 0).origy = y
  2091.             NewArray(x, y, 0).c = iEmpty
  2092.         Next y
  2093.     Next x
  2094.    
  2095.     ' angle is reversed
  2096.     angle = 360 - angle1
  2097.    
  2098.     ' Shearing each element 3 times in one shot
  2099.     nangle = angle
  2100.    
  2101.     ' this pre-processing portion basically rotates by 90 to get
  2102.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2103.     If angle > 45 And angle < 225 Then
  2104.         If angle < 135 Then
  2105.             nangle = angle - 90
  2106.         Else
  2107.             nangle = angle - 180
  2108.         End If
  2109.     End If
  2110.     If angle > 135 And angle < 315 Then
  2111.         If angle < 225 Then
  2112.             nangle = angle - 180
  2113.         Else
  2114.             nangle = angle - 270
  2115.         End If
  2116.     End If
  2117.     If nangle < 0 Then
  2118.         nangle = nangle + 360
  2119.     End If
  2120.     If nangle > 359 Then
  2121.         nangle = nangle - 360
  2122.     End If
  2123.    
  2124.     rotr = nangle * DtoR
  2125.     shear1 = Tan(rotr / 2) ' correct way
  2126.     shear2 = Sin(rotr)
  2127.    
  2128.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2129.     ' ***       all resolve to -45 degrees.
  2130.     ' ***       Fixed by changing < to <=
  2131.    
  2132.     'if angle >  45 and angle < 134 then
  2133.     If angle > 45 And angle <= 134 Then
  2134.         flipper = 1
  2135.     ElseIf angle > 134 And angle <= 224 Then
  2136.         flipper = 2
  2137.     ElseIf angle > 224 And angle <= 314 Then
  2138.         ' *** NOTE: this had a bug where this flipper was wrong
  2139.         '           Fixed by adding case 7
  2140.         'flipper = 3
  2141.         flipper = 7
  2142.     Else
  2143.         flipper = 0
  2144.     End If
  2145.    
  2146.     ' Here is where it needs some optimizing possibly... kinda slow...
  2147.     iOverwriteCount = 0
  2148.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2149.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2150.             Select Case flipper
  2151.                 Case 1:
  2152.                     nx = -y
  2153.                     ny = x
  2154.                 Case 2:
  2155.                     nx = -x
  2156.                     ny = -y
  2157.                 Case 3:
  2158.                     nx = -y
  2159.                     ny = -x
  2160.                 Case 4:
  2161.                     nx = -x
  2162.                     ny = y
  2163.                 Case 5:
  2164.                     nx = x
  2165.                     ny = -y
  2166.                 Case 6:
  2167.                     nx = y
  2168.                     ny = x
  2169.                 Case 7:
  2170.                     nx = y
  2171.                     ny = -x
  2172.                 Case Else:
  2173.                     nx = x
  2174.                     ny = y
  2175.             End Select
  2176.            
  2177.             clr = OldArray(nx, ny, 0).c
  2178.            
  2179.             y1 = y * shear1
  2180.             xy1 = x + y1
  2181.             fy = (y - xy1 * shear2)
  2182.             fx = xy1 + fy * shear1
  2183.            
  2184.             If fx >= -16 And fx <= 16 Then
  2185.                 If fy >= -16 And fy <= 16 Then
  2186.                    
  2187.                     ' count points that will be overwritten
  2188.                     if NewArray(fx, fy, 0).c <> iEmpty then
  2189.                         iOverwriteCount = iOverwriteCount + 1
  2190.                     end if
  2191.                    
  2192.                     NewArray(fx, fy, 0).c = clr
  2193.                     NewArray(fx, fy, 0).origx = fx
  2194.                     NewArray(fx, fy, 0).origy = fy
  2195.                 End If
  2196.             End If
  2197.         Next x
  2198.     Next y
  2199. End Sub ' ShearRotate1
  2200.  
  2201. ' /////////////////////////////////////////////////////////////////////////////
  2202.  
  2203. Sub ShearRotate1Test1
  2204.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2205.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2206.     Dim sMap As String
  2207.     Dim D As Integer
  2208.     Dim in$
  2209.    
  2210.     ' GET A SHAPE TO BE ROTATED
  2211.     Cls
  2212.     Print "3 shear rotation based on code by leopardpm"
  2213.     Print
  2214.    
  2215.     sMap = TestSprite1$
  2216.    
  2217.     ' CONVERT SHAPE TO ARRAY
  2218.     StringToRotationArray RoArray1(), sMap, "."
  2219.     Print "Initial contents of Rotation Array:"
  2220.     Print RotationArrayToStringTest(RoArray1())
  2221.     Print
  2222.    
  2223.     ' ROTATE THE SHAPE
  2224.     Do
  2225.         Print "Type degrees to rotate (0 TO 360) or non-numeric value to quit."
  2226.         Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2227.  
  2228.         Input "Degrees to rotate (q to quit)? "; in$
  2229.         If IsNum%(in$) Then
  2230.             D = Val(in$)
  2231.             If D >= 0 And D <= 360 Then
  2232.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  2233.                 Print
  2234.                 Print "Rotated by " + cstr$(D) + " degrees:"
  2235.                 Print RotationArrayToStringTest(RoArray2())
  2236.                 Print
  2237.             Else
  2238.                 Exit Do
  2239.             End If
  2240.         Else
  2241.             Exit Do
  2242.         End If
  2243.     Loop
  2244. End Sub ' ShearRotate1Test1
  2245.  
  2246. ' /////////////////////////////////////////////////////////////////////////////
  2247. ' Now receives parameter sMap
  2248. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  2249.  
  2250. ' e.g. ShearRotate1Test2 TestSprite1$
  2251.  
  2252. Sub ShearRotate1Test2(sMap As String)
  2253.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2254.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2255.     'Dim sMap As String
  2256.     Dim D As Integer
  2257.     Dim D1 As Integer
  2258.     Dim in$
  2259.     Dim bFinished As Integer
  2260.     Dim iOverwriteCount As Integer
  2261.    
  2262.     ' GET A SHAPE TO BE ROTATED
  2263.     Cls
  2264.     Print "3 shear rotation based on code by leopardpm"
  2265.     'sMap = TestSprite1$
  2266.    
  2267.     ' CONVERT SHAPE TO ARRAY
  2268.     StringToRotationArray RoArray1(), sMap, "."
  2269.  
  2270.     ' GET START ANGLE
  2271.     D = 0
  2272.     Print
  2273.     Print "Rotated by " + cstr$(D) + " degrees:"
  2274.     Print RotationArrayToStringTest(RoArray1())
  2275.     Print
  2276.     Print "Type an angle (-360 to 360) to rotate to, "
  2277.     Print "or blank to increase by 1 degree, or q to quit."
  2278.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2279.     Print "Hold down <ENTER> to rotate continually."
  2280.     Input "Angle (q to quit)? ", in$
  2281.     If Len(in$) > 0 Then
  2282.         If IsNum%(in$) Then
  2283.             D1 = Val(in$)
  2284.         Else
  2285.             D1 = -500
  2286.         End If
  2287.     Else
  2288.         D1 = 1
  2289.     End If
  2290.  
  2291.     ' ROTATE TO EACH ANGLE
  2292.     If D1 >= -360 And D1 <= 360 Then
  2293.         bFinished = FALSE
  2294.         Do
  2295.             ' ROTATE CLOCKWISE
  2296.             For D = D1 To 360
  2297.                 Cls
  2298.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  2299.                 Print
  2300.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2301.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  2302.                
  2303.                 Print RotationArrayToStringTest(RoArray2())
  2304.                 Print
  2305.  
  2306.                 Print "Type an angle (-360 to 360) to rotate to, "
  2307.                 Print "or blank to increase by 1 degree, or q to quit."
  2308.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2309.                 Print "Hold down <ENTER> to rotate continually."
  2310.                 Input "Angle (q to quit)? ", in$
  2311.                 If Len(in$) > 0 Then
  2312.                     If IsNum%(in$) Then
  2313.                         D = Val(in$)
  2314.                         If D >= 0 And D <= 360 Then
  2315.                             D = D - 1
  2316.                         Else
  2317.                             bFinished = TRUE
  2318.                             Exit For
  2319.                         End If
  2320.                     Else
  2321.                         bFinished = TRUE
  2322.                         Exit For
  2323.                     End If
  2324.                 End If
  2325.             Next D
  2326.             If bFinished = TRUE Then Exit Do
  2327.            
  2328.             ' ROTATE COUNTER-CLOCKWISE
  2329.             For D = 360 To D1 Step -1
  2330.                 Cls
  2331.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  2332.                 Print
  2333.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2334.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  2335.                
  2336.                 Print RotationArrayToStringTest(RoArray2())
  2337.                 Print
  2338.  
  2339.                 Print "Type an angle (0 to 360) to rotate to, "
  2340.                 Print "or blank to increase by 1 degree, or q to quit."
  2341.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2342.                 Print "Hold down <ENTER> to rotate continually."
  2343.                 Input "Angle (q to quit)? ", in$
  2344.                 If Len(in$) > 0 Then
  2345.                     If IsNum%(in$) Then
  2346.                         D = Val(in$)
  2347.                         If D >= 0 And D <= 360 Then
  2348.                             D = D + 1
  2349.                         Else
  2350.                             bFinished = TRUE
  2351.                             Exit For
  2352.                         End If
  2353.                     Else
  2354.                         bFinished = TRUE
  2355.                         Exit For
  2356.                     End If
  2357.                 End If
  2358.             Next D
  2359.             If bFinished = TRUE Then Exit Do
  2360.         Loop
  2361.     End If
  2362. End Sub ' ShearRotate1Test2
  2363.  
  2364. ' /////////////////////////////////////////////////////////////////////////////
  2365. ' ShearRotate v2
  2366. ' Tries to fix the problem of 2 points resolving to the same coordinate
  2367. ' (one overwrites the other, which becomes "lost")
  2368.  
  2369. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  2370.  
  2371. Sub ShearRotate2 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iMissing As Integer)
  2372.     Const Pi = 4 * Atn(1)
  2373.    
  2374.     Dim angle As Integer
  2375.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2376.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2377.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2378.     Dim x As Integer
  2379.     Dim y As Integer
  2380.     Dim nangle As Integer
  2381.     Dim nx As Integer
  2382.     Dim ny As Integer
  2383.     Dim flipper As Integer
  2384.     Dim rotr As Double
  2385.     Dim shear1 As Double
  2386.     Dim shear2 As Double
  2387.     Dim clr As Integer
  2388.     Dim y1 As _Byte
  2389.     Dim xy1 As _Byte
  2390.     Dim fy As _Byte
  2391.     Dim fx As _Byte
  2392.     Dim in$
  2393.     Dim sLine As String
  2394.     ReDim arrLost(-1) As RotationType
  2395.     Dim iLoop As Integer
  2396.     Dim bFound As Integer
  2397.    
  2398.     ' initialize new with empty
  2399.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2400.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2401.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2402.             NewArray(x, y, 0).origx = x
  2403.             NewArray(x, y, 0).origy = y
  2404.             NewArray(x, y, 0).c = iEmpty
  2405.         Next y
  2406.     Next x
  2407.    
  2408.     ' angle is reversed
  2409.     angle = 360 - angle1
  2410.    
  2411.     ' Shearing each element 3 times in one shot
  2412.     nangle = angle
  2413.    
  2414.     ' this pre-processing portion basically rotates by 90 to get
  2415.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2416.     If angle > 45 And angle < 225 Then
  2417.         If angle < 135 Then
  2418.             nangle = angle - 90
  2419.         Else
  2420.             nangle = angle - 180
  2421.         End If
  2422.     End If
  2423.     If angle > 135 And angle < 315 Then
  2424.         If angle < 225 Then
  2425.             nangle = angle - 180
  2426.         Else
  2427.             nangle = angle - 270
  2428.         End If
  2429.     End If
  2430.     If nangle < 0 Then
  2431.         nangle = nangle + 360
  2432.     End If
  2433.     If nangle > 359 Then
  2434.         nangle = nangle - 360
  2435.     End If
  2436.    
  2437.     rotr = nangle * DtoR
  2438.     shear1 = Tan(rotr / 2) ' correct way
  2439.     shear2 = Sin(rotr)
  2440.    
  2441.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2442.     ' ***       all resolve to -45 degrees.
  2443.     ' ***       Fixed by changing < to <=
  2444.    
  2445.     'if angle >  45 and angle < 134 then
  2446.     If angle > 45 And angle <= 134 Then
  2447.         flipper = 1
  2448.     ElseIf angle > 134 And angle <= 224 Then
  2449.         flipper = 2
  2450.     ElseIf angle > 224 And angle <= 314 Then
  2451.         ' *** NOTE: this had a bug where this flipper was wrong
  2452.         '           Fixed by adding case 7
  2453.         'flipper = 3
  2454.         flipper = 7
  2455.     Else
  2456.         flipper = 0
  2457.     End If
  2458.    
  2459.     ' Here is where it needs some optimizing possibly... kinda slow...
  2460.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2461.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2462.             Select Case flipper
  2463.                 Case 1:
  2464.                     nx = -y
  2465.                     ny = x
  2466.                 Case 2:
  2467.                     nx = -x
  2468.                     ny = -y
  2469.                 Case 3:
  2470.                     nx = -y
  2471.                     ny = -x
  2472.                 Case 4:
  2473.                     nx = -x
  2474.                     ny = y
  2475.                 Case 5:
  2476.                     nx = x
  2477.                     ny = -y
  2478.                 Case 6:
  2479.                     nx = y
  2480.                     ny = x
  2481.                 Case 7:
  2482.                     nx = y
  2483.                     ny = -x
  2484.                 Case Else:
  2485.                     nx = x
  2486.                     ny = y
  2487.             End Select
  2488.            
  2489.             clr = OldArray(nx, ny, 0).c
  2490.            
  2491.             y1 = y * shear1
  2492.             xy1 = x + y1
  2493.             fy = (y - xy1 * shear2)
  2494.             fx = xy1 + fy * shear1
  2495.            
  2496.             If fx >= -16 And fx <= 16 Then
  2497.                 If fy >= -16 And fy <= 16 Then
  2498.                     ' only draw here if this spot is empty
  2499.                     if NewArray(fx, fy, 0).c = iEmpty then
  2500.                         NewArray(fx, fy, 0).c = clr
  2501.                         NewArray(fx, fy, 0).origx = fx
  2502.                         NewArray(fx, fy, 0).origy = fy
  2503.                     else
  2504.                         ' don't draw, but save it to a list to handle later
  2505.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  2506.                         arrLost(UBound(arrLost)).c = clr
  2507.                         arrLost(UBound(arrLost)).origx = fx
  2508.                         arrLost(UBound(arrLost)).origy = fy
  2509.                     end if
  2510.                 End If
  2511.             End If
  2512.         Next x
  2513.     Next y
  2514.    
  2515.     ' try to place any points that would have overwritten to a spot nearby
  2516.     ' can nearby be determined by the angle of rotation?
  2517.     ' perhaps if we divide the screen up into 4 zones:
  2518.     '
  2519.     ' --------------------------------------
  2520.     '|                   |                  |
  2521.     '| zone 4            | zone 1           |
  2522.     '| 271-359 degrees)  | (1-89 degrees)   |
  2523.     '|--------------------------------------|
  2524.     '|                   |                  |
  2525.     '| zone 3            | zone 2           |
  2526.     '| (181-269 degrees) | (91-179 degrees) |
  2527.     '|                   |                  |
  2528.     ' --------------------------------------
  2529.    
  2530.     ' in zone   search direction (y,x)
  2531.     ' -------   ----------------------
  2532.     ' 1         up   + right
  2533.     ' 2         down + right
  2534.     ' 3         down + left
  2535.     ' 4         up   + left
  2536.    
  2537.     iMissing = 0
  2538.     For iLoop = 0 To UBound(arrLost)
  2539.         bFound = FindEmptyShearRotationPoint2%(arrLost(iLoop), angle1, iEmpty, x, y, NewArray())
  2540.         if bFound = TRUE then
  2541.             If m_bDebug = TRUE Then
  2542.                 _echo "Plotted  missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  2543.             End If
  2544.         else
  2545.             iMissing = iMissing + 1
  2546.             If m_bDebug = TRUE Then
  2547.                 _echo "Detected missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  2548.             End If
  2549.         end if
  2550.     Next iLoop
  2551.    
  2552. End Sub ' ShearRotate2
  2553.  
  2554. ' /////////////////////////////////////////////////////////////////////////////
  2555. ' Receives
  2556. ' FindMe (RotationType) = contains the starting location (.origx, .origy) to start looking from, and the value (.c) to write
  2557. ' angle1 (Integer) = angle we were rotating to, to determine direction to look in
  2558. ' iEmpty (Integer) = value to test against for empty
  2559. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  2560. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  2561. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  2562.  
  2563. ' Returns
  2564. ' FALSE if no empty spot was found
  2565. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  2566.  
  2567. Function FindEmptyShearRotationPoint2%(FindMe As RotationType, angle1 As Integer, iEmpty as Integer, destX as integer, destY as integer, NewArray() As RotationType)
  2568.     Dim bResult as Integer : bResult = FALSE
  2569.     Dim x As Integer
  2570.     Dim y As Integer
  2571.     Dim dirX As Integer
  2572.     Dim dirY As Integer
  2573.    
  2574.     destX = 0
  2575.     destY = 0
  2576.    
  2577.     ' Choose search direction depending on the angle
  2578.     If angle1 > 0 And angle1 < 90 Then
  2579.         dirX = 1
  2580.         dirY = -1
  2581.     ElseIf angle1 > 90 And angle1 < 180 Then
  2582.         dirX = 1
  2583.         dirY = 1
  2584.     ElseIf angle1 > 180 And angle1 < 270 Then
  2585.         dirX = -1
  2586.         dirY = 1
  2587.     ElseIf angle1 > 270 And angle1 < 360 Then
  2588.         dirX = -1
  2589.         dirY = -1
  2590.     Else
  2591.         dirX = 0
  2592.         dirY = 0
  2593.     End If
  2594.    
  2595.     If dirX <> 0 Then
  2596.         x = FindMe.origx
  2597.         y = FindMe.origy
  2598.         Do
  2599.             ' quit if we're out of bounds
  2600.             if x < LBound(NewArray, 1) then Exit Do
  2601.             if x > UBound(NewArray, 1) then Exit do
  2602.             if y < LBound(NewArray, 2) then Exit Do
  2603.             if y > UBound(NewArray, 2) then Exit do
  2604.            
  2605.             ' =============================================================================
  2606.             ' BEGIN SEARCH
  2607.             ' =============================================================================
  2608.             ' look along y axis for a blank spot
  2609.             destX = x
  2610.             destY = y + dirY
  2611.             if destX >= LBound(NewArray, 1) then
  2612.                 if destX <= UBound(NewArray, 1) then
  2613.                     if destY >= LBound(NewArray, 2) then
  2614.                         if destY <= UBound(NewArray, 2) then
  2615.                             if NewArray(destX, destY, 0).c = iEmpty then
  2616.                                 NewArray(destX, destY, 0).c = FindMe.c
  2617.                                 bResult = TRUE
  2618.                                 Exit Do
  2619.                             end if
  2620.                         end if
  2621.                     end if
  2622.                 end if
  2623.             end if
  2624.            
  2625.             ' look along x axis for a blank spot
  2626.             destX = x + dirX
  2627.             destY = y
  2628.             if destX >= LBound(NewArray, 1) then
  2629.                 if destX <= UBound(NewArray, 1) then
  2630.                     if destY >= LBound(NewArray, 2) then
  2631.                         if destY <= UBound(NewArray, 2) then
  2632.                             if NewArray(x + dirX, y, 0).c = iEmpty then
  2633.                                 NewArray(destX, destY, 0).c = FindMe.c
  2634.                                 bResult = TRUE
  2635.                                 Exit Do
  2636.                             end if
  2637.                         end if
  2638.                     end if
  2639.                 end if
  2640.             end if
  2641.            
  2642.             ' look diagonally for a blank spot
  2643.             destX = x + dirX
  2644.             destY = y + dirY
  2645.             if destX >= LBound(NewArray, 1) then
  2646.                 if destX <= UBound(NewArray, 1) then
  2647.                     if destY >= LBound(NewArray, 2) then
  2648.                         if destY <= UBound(NewArray, 2) then
  2649.                             if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  2650.                                 NewArray(destX, destY, 0).c = FindMe.c
  2651.                                 bResult = TRUE
  2652.                                 Exit Do
  2653.                             end if
  2654.                         end if
  2655.                     end if
  2656.                 end if
  2657.             end if
  2658.             ' =============================================================================
  2659.             ' END SEARCH
  2660.             ' =============================================================================
  2661.            
  2662.             ' Keep looking
  2663.             x = x + dirX
  2664.             y = y + dirY
  2665.         Loop
  2666.     End If
  2667.    
  2668.     ' Return result
  2669.     FindEmptyShearRotationPoint2% = bResult
  2670. End Sub ' FindEmptyShearRotationPoint2%
  2671.  
  2672. ' /////////////////////////////////////////////////////////////////////////////
  2673. ' Tries to correct for missing points.
  2674.  
  2675. ' Receives parameter sMap
  2676. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  2677.  
  2678. ' e.g. ShearRotate2Test1 TestSprite1$
  2679.  
  2680. Sub ShearRotate2Test1(sMap As String)
  2681.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2682.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2683.     'Dim sMap As String
  2684.     Dim D As Integer
  2685.     Dim D1 As Integer
  2686.     Dim in$
  2687.     Dim bFinished As Integer
  2688.     Dim iMissing As Integer
  2689.    
  2690.     ' GET A SHAPE TO BE ROTATED
  2691.     Cls
  2692.     Print "3 shear rotation based on code by leopardpm"
  2693.     'sMap = TestSprite1$
  2694.    
  2695.     ' CONVERT SHAPE TO ARRAY
  2696.     StringToRotationArray RoArray1(), sMap, "."
  2697.  
  2698.     ' GET START ANGLE
  2699.     D = 0
  2700.     Print
  2701.     Print "Rotated by " + cstr$(D) + " degrees:"
  2702.     Print RotationArrayToStringTest(RoArray1())
  2703.     Print
  2704.     Print "Type an angle (-360 to 360) to rotate to, "
  2705.     Print "or blank to increase by 1 degree, or q to quit."
  2706.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2707.     Print "Hold down <ENTER> to rotate continually."
  2708.     Input "Angle (q to quit)? ", in$
  2709.     If Len(in$) > 0 Then
  2710.         If IsNum%(in$) Then
  2711.             D1 = Val(in$)
  2712.         Else
  2713.             D1 = -500
  2714.         End If
  2715.     Else
  2716.         D1 = 1
  2717.     End If
  2718.  
  2719.     ' ROTATE TO EACH ANGLE
  2720.     If D1 >= -360 And D1 <= 360 Then
  2721.         bFinished = FALSE
  2722.         Do
  2723.             ' ROTATE CLOCKWISE
  2724.             For D = D1 To 360
  2725.                 Cls
  2726.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  2727.                 Print
  2728.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2729.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  2730.                
  2731.                 Print RotationArrayToStringTest(RoArray2())
  2732.                 Print
  2733.                
  2734.                 Print "Type an angle (-360 to 360) to rotate to, "
  2735.                 Print "or blank to increase by 1 degree, or q to quit."
  2736.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2737.                 Print "Hold down <ENTER> to rotate continually."
  2738.                 Input "Angle (q to quit)? ", in$
  2739.                 If Len(in$) > 0 Then
  2740.                     If IsNum%(in$) Then
  2741.                         D = Val(in$)
  2742.                         If D >= 0 And D <= 360 Then
  2743.                             D = D - 1
  2744.                         Else
  2745.                             bFinished = TRUE
  2746.                             Exit For
  2747.                         End If
  2748.                     Else
  2749.                         bFinished = TRUE
  2750.                         Exit For
  2751.                     End If
  2752.                 End If
  2753.             Next D
  2754.             If bFinished = TRUE Then Exit Do
  2755.            
  2756.             ' ROTATE COUNTER-CLOCKWISE
  2757.             For D = 360 To D1 Step -1
  2758.                 Cls
  2759.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  2760.                 Print
  2761.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2762.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  2763.                
  2764.                 Print RotationArrayToStringTest(RoArray2())
  2765.                 Print
  2766.  
  2767.                 Print "Type an angle (0 to 360) to rotate to, "
  2768.                 Print "or blank to increase by 1 degree, or q to quit."
  2769.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2770.                 Print "Hold down <ENTER> to rotate continually."
  2771.                 Input "Angle (q to quit)? ", in$
  2772.                 If Len(in$) > 0 Then
  2773.                     If IsNum%(in$) Then
  2774.                         D = Val(in$)
  2775.                         If D >= 0 And D <= 360 Then
  2776.                             D = D + 1
  2777.                         Else
  2778.                             bFinished = TRUE
  2779.                             Exit For
  2780.                         End If
  2781.                     Else
  2782.                         bFinished = TRUE
  2783.                         Exit For
  2784.                     End If
  2785.                 End If
  2786.             Next D
  2787.             If bFinished = TRUE Then Exit Do
  2788.         Loop
  2789.     End If
  2790. End Sub ' ShearRotate2Test1
  2791.  
  2792. ' /////////////////////////////////////////////////////////////////////////////
  2793. ' ShearRotate v3
  2794.  
  2795. ' Tries to fix the problem of 2 points resolving to the same coordinate
  2796. ' (one overwrites the other, which becomes "lost")
  2797. ' a little more accurately, using iDirection parameter
  2798. ' (which can be cClockwise or cCounterClockwise)
  2799. ' together with which quarter of the screen the point is in,
  2800.  
  2801. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  2802.  
  2803. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  2804.  
  2805. Sub ShearRotate3 ( _
  2806.         OldArray() As RotationType, _
  2807.         NewArray() As RotationType, _
  2808.         angle1 As Integer, _
  2809.         iDirection As Integer, _
  2810.         iEmpty As Integer, _
  2811.         iMissing As Integer)
  2812.        
  2813.     Const Pi = 4 * Atn(1)
  2814.    
  2815.     Dim angle As Integer
  2816.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2817.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2818.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2819.     Dim x As Integer
  2820.     Dim y As Integer
  2821.     Dim nangle As Integer
  2822.     Dim nx As Integer
  2823.     Dim ny As Integer
  2824.     Dim flipper As Integer
  2825.     Dim rotr As Double
  2826.     Dim shear1 As Double
  2827.     Dim shear2 As Double
  2828.     Dim clr As Integer
  2829.     Dim y1 As _Byte
  2830.     Dim xy1 As _Byte
  2831.     Dim fy As _Byte
  2832.     Dim fx As _Byte
  2833.     Dim in$
  2834.     Dim sLine As String
  2835.     ReDim arrLost(-1) As RotationType
  2836.     Dim iLoop As Integer
  2837.     Dim bFound As Integer
  2838.     Dim iScreenZone As Integer
  2839.         Dim iMidX As Integer
  2840.         Dim iMidY As Integer
  2841.        
  2842.     ' initialize new with empty
  2843.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2844.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2845.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2846.             NewArray(x, y, 0).origx = x
  2847.             NewArray(x, y, 0).origy = y
  2848.             NewArray(x, y, 0).c = iEmpty
  2849.         Next y
  2850.     Next x
  2851.    
  2852.         ' find midpoints
  2853.         iMidX = (UBound(OldArray, 1) - LBound(OldArray, 1)) / 2
  2854.         iMidY = (UBound(OldArray, 2) - LBound(OldArray, 2)) / 2
  2855.        
  2856.     ' angle is reversed
  2857.     angle = 360 - angle1
  2858.    
  2859.     ' Shearing each element 3 times in one shot
  2860.     nangle = angle
  2861.    
  2862.     ' this pre-processing portion basically rotates by 90 to get
  2863.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2864.     If angle > 45 And angle < 225 Then
  2865.         If angle < 135 Then
  2866.             nangle = angle - 90
  2867.         Else
  2868.             nangle = angle - 180
  2869.         End If
  2870.     End If
  2871.     If angle > 135 And angle < 315 Then
  2872.         If angle < 225 Then
  2873.             nangle = angle - 180
  2874.         Else
  2875.             nangle = angle - 270
  2876.         End If
  2877.     End If
  2878.     If nangle < 0 Then
  2879.         nangle = nangle + 360
  2880.     End If
  2881.     If nangle > 359 Then
  2882.         nangle = nangle - 360
  2883.     End If
  2884.    
  2885.     rotr = nangle * DtoR
  2886.     shear1 = Tan(rotr / 2) ' correct way
  2887.     shear2 = Sin(rotr)
  2888.    
  2889.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2890.     ' ***       all resolve to -45 degrees.
  2891.     ' ***       Fixed by changing < to <=
  2892.    
  2893.     'if angle >  45 and angle < 134 then
  2894.     If angle > 45 And angle <= 134 Then
  2895.         flipper = 1
  2896.     ElseIf angle > 134 And angle <= 224 Then
  2897.         flipper = 2
  2898.     ElseIf angle > 224 And angle <= 314 Then
  2899.         ' *** NOTE: this had a bug where this flipper was wrong
  2900.         '           Fixed by adding case 7
  2901.         'flipper = 3
  2902.         flipper = 7
  2903.     Else
  2904.         flipper = 0
  2905.     End If
  2906.    
  2907.     ' Here is where it needs some optimizing possibly... kinda slow...
  2908.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2909.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2910.            
  2911.                         ' find which part of screen the current point is in
  2912.                         if y > iMidY then
  2913.                                 ' bottom half of screen
  2914.                                 if x > iMidX then
  2915.                                         ' right half of screen
  2916.                                         iScreenZone = 2
  2917.                                 else
  2918.                                         ' left half of screen
  2919.                                         iScreenZone = 3
  2920.                                 end if
  2921.                         else
  2922.                                 ' top half of screen
  2923.                                 if x > iMidX then
  2924.                                         ' right half of screen
  2925.                                         iScreenZone = 1
  2926.                                 else
  2927.                                         ' left half of screen
  2928.                                         iScreenZone = 4
  2929.                                 end if
  2930.                         end if
  2931.                        
  2932.                         ' calculate directions
  2933.                         Select Case flipper
  2934.                 Case 1:
  2935.                     nx = -y
  2936.                     ny = x
  2937.                 Case 2:
  2938.                     nx = -x
  2939.                     ny = -y
  2940.                 Case 3:
  2941.                     nx = -y
  2942.                     ny = -x
  2943.                 Case 4:
  2944.                     nx = -x
  2945.                     ny = y
  2946.                 Case 5:
  2947.                     nx = x
  2948.                     ny = -y
  2949.                 Case 6:
  2950.                     nx = y
  2951.                     ny = x
  2952.                 Case 7:
  2953.                     nx = y
  2954.                     ny = -x
  2955.                 Case Else:
  2956.                     nx = x
  2957.                     ny = y
  2958.             End Select
  2959.            
  2960.             clr = OldArray(nx, ny, 0).c
  2961.            
  2962.             y1 = y * shear1
  2963.             xy1 = x + y1
  2964.             fy = (y - xy1 * shear2)
  2965.             fx = xy1 + fy * shear1
  2966.            
  2967.             If fx >= -16 And fx <= 16 Then
  2968.                 If fy >= -16 And fy <= 16 Then
  2969.                     ' only draw here if this spot is empty
  2970.                     if NewArray(fx, fy, 0).c = iEmpty then
  2971.                         NewArray(fx, fy, 0).c = clr
  2972.                         NewArray(fx, fy, 0).origx = fx
  2973.                         NewArray(fx, fy, 0).origy = fy
  2974.                     else
  2975.                         ' don't draw, but save it to a list to handle later
  2976.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  2977.                         arrLost(UBound(arrLost)).c = clr
  2978.                         arrLost(UBound(arrLost)).origx = fx
  2979.                         arrLost(UBound(arrLost)).origy = fy
  2980.                                                
  2981.                                                 ' preserve which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  2982.                                                 arrLost(UBound(arrLost)).z = iScreenZone
  2983.                     end if
  2984.                 End If
  2985.             End If
  2986.         Next x
  2987.     Next y
  2988.    
  2989.     ' try to place any points that would have overwritten to a spot nearby
  2990.     ' can nearby be determined by the direction of rotation  (iDirection)
  2991.         ' together with which quarter of the screen the point is in (iScreenZone)
  2992.     ' where we divide the screen up into 4 zones:
  2993.    
  2994.     ' --------------------------------------
  2995.     '|                   |                  |
  2996.     '| zone 4            | zone 1           |
  2997.     '|                   |                  |
  2998.     '|--------------------------------------|
  2999.     '|                   |                  |
  3000.     '| zone 3            | zone 2           |
  3001.     '|                   |                  |
  3002.     '|                   |                  |
  3003.     ' --------------------------------------
  3004.    
  3005.     ' in zone   rotation direction   search direction (y,x)
  3006.     ' -------   ------------------   ----------------------
  3007.     ' 1         clockwise            down + right
  3008.         ' 1         counter-clockwise    up   + left
  3009.     ' 2         clockwise            down + left
  3010.     ' 2         counter-clockwise    up   + right
  3011.     ' 3         clockwise            up   + left
  3012.     ' 3         counter-clockwise    down + right
  3013.     ' 4         clockwise            up   + right
  3014.     ' 4         counter-clockwise    down + left
  3015.    
  3016.     iMissing = 0
  3017.     For iLoop = 0 To UBound(arrLost)
  3018.         bFound = FindEmptyShearRotationPoint3%(arrLost(iLoop), iDirection, iEmpty, x, y, NewArray())
  3019.         if bFound = TRUE then
  3020.             If m_bDebug = TRUE Then
  3021.                 _echo "Plotted  missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3022.             End If
  3023.         else
  3024.             iMissing = iMissing + 1
  3025.             If m_bDebug = TRUE Then
  3026.                 _echo "Detected missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3027.             End If
  3028.         end if
  3029.     Next iLoop
  3030.    
  3031. End Sub ' ShearRotate3
  3032.  
  3033. ' /////////////////////////////////////////////////////////////////////////////
  3034. ' Looks for a new point
  3035. ' a little more accurately, using iDirection parameter
  3036. ' which can be cClockwise or cCounterClockwise.
  3037.  
  3038. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3039.  
  3040. ' Receives
  3041. ' FindMe (RotationType) = contains
  3042. '                         .origx, .origy = the starting location to start looking from,
  3043. '                         .z = which area of the screen the point is in
  3044. '                              (1=top right, 2=bottom right, 3=bottom left, 4=top left)
  3045. '                              to determine direction to look in
  3046. '                         .c = the value to write
  3047. ' iDirection (Integer) = direction of rotation, can be cClockwise or cCounterClockwise (constants must be declared globally)
  3048. ' iEmpty (Integer) = value to test against for empty
  3049. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  3050. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  3051. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  3052.  
  3053. ' Returns
  3054. ' FALSE if no empty spot was found
  3055. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  3056.  
  3057. Function FindEmptyShearRotationPoint3%(FindMe As RotationType, iDirection As Integer, iEmpty as Integer, destX as integer, destY as integer, NewArray() As RotationType)
  3058.     Dim bResult as Integer : bResult = FALSE
  3059.     Dim x As Integer
  3060.     Dim y As Integer
  3061.     Dim dirX As Integer
  3062.     Dim dirY As Integer
  3063.     Dim bContinue As Integer
  3064.        
  3065.         ' Initialize
  3066.     destX = 0
  3067.     destY = 0
  3068.     bContinue = TRUE
  3069.        
  3070.     ' Choose search direction based on the quadrant of the screen
  3071.         ' and the direction of rotation:
  3072.        
  3073.         ' iScreenZone   iDirection           search direction (y,x)
  3074.     ' -----------   ------------------   ----------------------
  3075.     ' 1             cClockwise           down + right ( 1, 1)
  3076.         ' 1             cCounterClockwise    up   + left  (-1,-1)
  3077.     ' 2             cClockwise           down + left  ( 1,-1)
  3078.     ' 2             cCounterClockwise    up   + right (-1, 1)
  3079.     ' 3             cClockwise           up   + left  (-1,-1)
  3080.     ' 3             cCounterClockwise    down + right ( 1, 1)
  3081.     ' 4             cClockwise           up   + right (-1, 1)
  3082.     ' 4             cCounterClockwise    down + left  ( 1,-1)
  3083.        
  3084.     If     FindMe.z = 1 And iDirection = cClockwise Then
  3085.         dirY = 1
  3086.         dirX = 1
  3087.     ElseIf FindMe.z = 1 And iDirection = cCounterClockwise Then
  3088.         dirY = -1
  3089.         dirX = -1
  3090.     ElseIf FindMe.z = 2 And iDirection = cClockwise Then
  3091.         dirY = 1
  3092.         dirX = -1
  3093.     ElseIf FindMe.z = 2 And iDirection = cCounterClockwise Then
  3094.         dirY = -1
  3095.         dirX = 1
  3096.     ElseIf FindMe.z = 3 And iDirection = cClockwise Then
  3097.         dirY = -1
  3098.         dirX = -1
  3099.     ElseIf FindMe.z = 3 And iDirection = cCounterClockwise Then
  3100.         dirY = 1
  3101.         dirX = 1
  3102.     ElseIf FindMe.z = 4 And iDirection = cClockwise Then
  3103.         dirY = -1
  3104.         dirX = 1
  3105.     ElseIf FindMe.z = 4 And iDirection = cCounterClockwise Then
  3106.         dirY = 1
  3107.         dirX = -1
  3108.     Else
  3109.         bContinue = FALSE
  3110.     End If
  3111.    
  3112.         ' Quit if we're out of bounds
  3113.     If bContinue = TRUE Then
  3114.                 bContinue = FALSE
  3115.         x = FindMe.origx
  3116.         y = FindMe.origy
  3117.                 if x >= LBound(NewArray, 1) then
  3118.                         if x <= UBound(NewArray, 1) then
  3119.                                 if y >= LBound(NewArray, 2) then
  3120.                                         if y <= UBound(NewArray, 2) then
  3121.                                                 bContinue = TRUE
  3122.                                         end if
  3123.                                 end if
  3124.                         end if
  3125.                 end if
  3126.         End If
  3127.        
  3128.         ' look along y axis for an available adjacent point
  3129.         If bContinue = TRUE Then
  3130.                 destX = x
  3131.                 destY = y + dirY
  3132.                 if destX >= LBound(NewArray, 1) then
  3133.                         if destX <= UBound(NewArray, 1) then
  3134.                                 if destY >= LBound(NewArray, 2) then
  3135.                                         if destY <= UBound(NewArray, 2) then
  3136.                                                 if NewArray(destX, destY, 0).c = iEmpty then
  3137.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3138.                                                         bResult = TRUE
  3139.                                                         bContinue = FALSE
  3140.                                                 end if
  3141.                                         end if
  3142.                                 end if
  3143.                         end if
  3144.                 end if
  3145.         end if
  3146.        
  3147.         ' look along x axis for an available adjacent point
  3148.         If bContinue = TRUE Then
  3149.                 destX = x + dirX
  3150.                 destY = y
  3151.                 if destX >= LBound(NewArray, 1) then
  3152.                         if destX <= UBound(NewArray, 1) then
  3153.                                 if destY >= LBound(NewArray, 2) then
  3154.                                         if destY <= UBound(NewArray, 2) then
  3155.                                                 if NewArray(x + dirX, y, 0).c = iEmpty then
  3156.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3157.                                                         bResult = TRUE
  3158.                                                         bContinue = FALSE
  3159.                                                 end if
  3160.                                         end if
  3161.                                 end if
  3162.                         end if
  3163.                 end if
  3164.         end if
  3165.        
  3166.         ' look diagonally for an available adjacent point
  3167.         If bContinue = TRUE Then
  3168.                 destX = x + dirX
  3169.                 destY = y + dirY
  3170.                 if destX >= LBound(NewArray, 1) then
  3171.                         if destX <= UBound(NewArray, 1) then
  3172.                                 if destY >= LBound(NewArray, 2) then
  3173.                                         if destY <= UBound(NewArray, 2) then
  3174.                                                 if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  3175.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3176.                                                         bResult = TRUE
  3177.                                                         bContinue = FALSE
  3178.                                                 end if
  3179.                                         end if
  3180.                                 end if
  3181.                         end if
  3182.                 end if
  3183.     End If
  3184.        
  3185.     ' Return result
  3186.     FindEmptyShearRotationPoint3% = bResult
  3187. End Sub ' FindEmptyShearRotationPoint3%
  3188.  
  3189. ' /////////////////////////////////////////////////////////////////////////////
  3190. ' Receives parameter sMap
  3191. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3192.  
  3193. ' e.g. ShearRotate3Test1 TestSprite1$
  3194.  
  3195. Sub ShearRotate3Test1(sMap As String)
  3196.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3197.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3198.     'Dim sMap As String
  3199.     Dim D As Integer
  3200.     Dim D1 As Integer
  3201.     Dim in$
  3202.     Dim bFinished As Integer
  3203.     Dim iMissing As Integer
  3204.    
  3205.     ' GET A SHAPE TO BE ROTATED
  3206.     Cls
  3207.     Print "3 shear rotation based on code by leopardpm"
  3208.     'sMap = TestSprite1$
  3209.    
  3210.     ' CONVERT SHAPE TO ARRAY
  3211.     StringToRotationArray RoArray1(), sMap, "."
  3212.  
  3213.     ' GET START ANGLE
  3214.     D = 0
  3215.     Print
  3216.     Print "Rotated by " + cstr$(D) + " degrees:"
  3217.     Print RotationArrayToStringTest(RoArray1())
  3218.     Print
  3219.     Print "Type an angle (-360 to 360) to rotate to, "
  3220.     Print "or blank to increase by 1 degree, or q to quit."
  3221.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3222.     Print "Hold down <ENTER> to rotate continually."
  3223.     Input "Angle (q to quit)? ", in$
  3224.     If Len(in$) > 0 Then
  3225.         If IsNum%(in$) Then
  3226.             D1 = Val(in$)
  3227.         Else
  3228.             D1 = -500
  3229.         End If
  3230.     Else
  3231.         D1 = 1
  3232.     End If
  3233.  
  3234.     ' ROTATE TO EACH ANGLE
  3235.     If D1 >= -360 And D1 <= 360 Then
  3236.         bFinished = FALSE
  3237.         Do
  3238.             ' ROTATE CLOCKWISE
  3239.             For D = D1 To 360
  3240.                 Cls
  3241.                                
  3242.                 ShearRotate3 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  3243.                 Print
  3244.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3245.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3246.                
  3247.                 Print RotationArrayToStringTest(RoArray2())
  3248.                 Print
  3249.                
  3250.                 Print "Type an angle (-360 to 360) to rotate to, "
  3251.                 Print "or blank to increase by 1 degree, or q to quit."
  3252.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3253.                 Print "Hold down <ENTER> to rotate continually."
  3254.                 Input "Angle (q to quit)? ", in$
  3255.                 If Len(in$) > 0 Then
  3256.                     If IsNum%(in$) Then
  3257.                         D = Val(in$)
  3258.                         If D >= 0 And D <= 360 Then
  3259.                             D = D - 1
  3260.                         Else
  3261.                             bFinished = TRUE
  3262.                             Exit For
  3263.                         End If
  3264.                     Else
  3265.                         bFinished = TRUE
  3266.                         Exit For
  3267.                     End If
  3268.                 End If
  3269.             Next D
  3270.             If bFinished = TRUE Then Exit Do
  3271.            
  3272.             ' ROTATE COUNTER-CLOCKWISE
  3273.             For D = 360 To D1 Step -1
  3274.                 Cls
  3275.                 ShearRotate3 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  3276.                 Print
  3277.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3278.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3279.                
  3280.                 Print RotationArrayToStringTest(RoArray2())
  3281.                 Print
  3282.  
  3283.                 Print "Type an angle (0 to 360) to rotate to, "
  3284.                 Print "or blank to increase by 1 degree, or q to quit."
  3285.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3286.                 Print "Hold down <ENTER> to rotate continually."
  3287.                 Input "Angle (q to quit)? ", in$
  3288.                 If Len(in$) > 0 Then
  3289.                     If IsNum%(in$) Then
  3290.                         D = Val(in$)
  3291.                         If D >= 0 And D <= 360 Then
  3292.                             D = D + 1
  3293.                         Else
  3294.                             bFinished = TRUE
  3295.                             Exit For
  3296.                         End If
  3297.                     Else
  3298.                         bFinished = TRUE
  3299.                         Exit For
  3300.                     End If
  3301.                 End If
  3302.             Next D
  3303.             If bFinished = TRUE Then Exit Do
  3304.         Loop
  3305.     End If
  3306. End Sub ' ShearRotate3Test1
  3307.  
  3308. ' /////////////////////////////////////////////////////////////////////////////
  3309. ' ShearRotate v4
  3310.  
  3311. ' Tries to fix the problem of 2 points resolving to the same coordinate
  3312. ' (one overwrites the other, which becomes "lost")
  3313. ' using a different approach, by just looking at the problem angles:
  3314. ' 30, 60, 120, 150, 210, 240, 300, 330 degrees
  3315.  
  3316. ' (which can be cClockwise or cCounterClockwise)
  3317. ' together with which quarter of the screen the point is in,
  3318.  
  3319. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3320.  
  3321. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  3322.  
  3323. Sub ShearRotate4 ( _
  3324.         OldArray() As RotationType, _
  3325.         NewArray() As RotationType, _
  3326.         angle1 As Integer, _
  3327.         iDirection As Integer, _
  3328.         iEmpty As Integer, _
  3329.         iMissing As Integer)
  3330.        
  3331.     Const Pi = 4 * Atn(1)
  3332.    
  3333.     Dim angle As Integer
  3334.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  3335.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  3336.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  3337.     Dim x As Integer
  3338.     Dim y As Integer
  3339.     Dim nangle As Integer
  3340.     Dim nx As Integer
  3341.     Dim ny As Integer
  3342.     Dim flipper As Integer
  3343.     Dim rotr As Double
  3344.     Dim shear1 As Double
  3345.     Dim shear2 As Double
  3346.     Dim clr As Integer
  3347.     Dim y1 As _Byte
  3348.     Dim xy1 As _Byte
  3349.     Dim fy As _Byte
  3350.     Dim fx As _Byte
  3351.     Dim in$
  3352.     Dim sLine As String
  3353.     ReDim arrLost(-1) As RotationType
  3354.     Dim iLoop As Integer
  3355.     Dim bFound As Integer
  3356.     Dim iScreenZone As Integer
  3357.         Dim iMidX As Integer
  3358.         Dim iMidY As Integer
  3359.        
  3360.     ' initialize new with empty
  3361.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3362.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3363.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3364.             NewArray(x, y, 0).origx = x
  3365.             NewArray(x, y, 0).origy = y
  3366.             NewArray(x, y, 0).c = iEmpty
  3367.         Next y
  3368.     Next x
  3369.    
  3370.         ' find midpoints
  3371.         iMidX = (UBound(OldArray, 1) - LBound(OldArray, 1)) / 2
  3372.         iMidY = (UBound(OldArray, 2) - LBound(OldArray, 2)) / 2
  3373.        
  3374.     ' angle is reversed
  3375.     angle = 360 - angle1
  3376.    
  3377.     ' Shearing each element 3 times in one shot
  3378.     nangle = angle
  3379.    
  3380.     ' this pre-processing portion basically rotates by 90 to get
  3381.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  3382.     If angle > 45 And angle < 225 Then
  3383.         If angle < 135 Then
  3384.             nangle = angle - 90
  3385.         Else
  3386.             nangle = angle - 180
  3387.         End If
  3388.     End If
  3389.     If angle > 135 And angle < 315 Then
  3390.         If angle < 225 Then
  3391.             nangle = angle - 180
  3392.         Else
  3393.             nangle = angle - 270
  3394.         End If
  3395.     End If
  3396.     If nangle < 0 Then
  3397.         nangle = nangle + 360
  3398.     End If
  3399.     If nangle > 359 Then
  3400.         nangle = nangle - 360
  3401.     End If
  3402.    
  3403.     rotr = nangle * DtoR
  3404.     shear1 = Tan(rotr / 2) ' correct way
  3405.     shear2 = Sin(rotr)
  3406.    
  3407.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  3408.     ' ***       all resolve to -45 degrees.
  3409.     ' ***       Fixed by changing < to <=
  3410.    
  3411.     'if angle >  45 and angle < 134 then
  3412.     If angle > 45 And angle <= 134 Then
  3413.         flipper = 1
  3414.     ElseIf angle > 134 And angle <= 224 Then
  3415.         flipper = 2
  3416.     ElseIf angle > 224 And angle <= 314 Then
  3417.         ' *** NOTE: this had a bug where this flipper was wrong
  3418.         '           Fixed by adding case 7
  3419.         'flipper = 3
  3420.         flipper = 7
  3421.     Else
  3422.         flipper = 0
  3423.     End If
  3424.    
  3425.     ' Here is where it needs some optimizing possibly... kinda slow...
  3426.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3427.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3428.            
  3429.                         ' find which part of screen the current point is in
  3430.                         if y > iMidY then
  3431.                                 ' bottom half of screen
  3432.                                 if x > iMidX then
  3433.                                         ' right half of screen
  3434.                                         iScreenZone = 2
  3435.                                 else
  3436.                                         ' left half of screen
  3437.                                         iScreenZone = 3
  3438.                                 end if
  3439.                         else
  3440.                                 ' top half of screen
  3441.                                 if x > iMidX then
  3442.                                         ' right half of screen
  3443.                                         iScreenZone = 1
  3444.                                 else
  3445.                                         ' left half of screen
  3446.                                         iScreenZone = 4
  3447.                                 end if
  3448.                         end if
  3449.                        
  3450.                         ' calculate directions
  3451.                         Select Case flipper
  3452.                 Case 1:
  3453.                     nx = -y
  3454.                     ny = x
  3455.                 Case 2:
  3456.                     nx = -x
  3457.                     ny = -y
  3458.                 Case 3:
  3459.                     nx = -y
  3460.                     ny = -x
  3461.                 Case 4:
  3462.                     nx = -x
  3463.                     ny = y
  3464.                 Case 5:
  3465.                     nx = x
  3466.                     ny = -y
  3467.                 Case 6:
  3468.                     nx = y
  3469.                     ny = x
  3470.                 Case 7:
  3471.                     nx = y
  3472.                     ny = -x
  3473.                 Case Else:
  3474.                     nx = x
  3475.                     ny = y
  3476.             End Select
  3477.            
  3478.             clr = OldArray(nx, ny, 0).c
  3479.            
  3480.             y1 = y * shear1
  3481.             xy1 = x + y1
  3482.             fy = (y - xy1 * shear2)
  3483.             fx = xy1 + fy * shear1
  3484.            
  3485.             If fx >= -16 And fx <= 16 Then
  3486.                 If fy >= -16 And fy <= 16 Then
  3487.                     ' only draw here if this spot is empty
  3488.                     if NewArray(fx, fy, 0).c = iEmpty then
  3489.                         NewArray(fx, fy, 0).c = clr
  3490.                         NewArray(fx, fy, 0).origx = fx
  3491.                         NewArray(fx, fy, 0).origy = fy
  3492.                     else
  3493.                         ' don't draw, but save it to a list to handle later
  3494.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  3495.                         arrLost(UBound(arrLost)).c = clr
  3496.                         arrLost(UBound(arrLost)).origx = fx
  3497.                         arrLost(UBound(arrLost)).origy = fy
  3498.                                                
  3499.                                                 ' preserve which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  3500.                                                 arrLost(UBound(arrLost)).z = iScreenZone
  3501.                     end if
  3502.                 End If
  3503.             End If
  3504.         Next x
  3505.     Next y
  3506.    
  3507.     ' try to place any points that would have overwritten to a spot nearby
  3508.     ' can nearby be determined by the direction of rotation  (iDirection)
  3509.         ' together with which quarter of the screen the point is in (iScreenZone)
  3510.     ' where we divide the screen up into 4 zones:
  3511.    
  3512.     ' --------------------------------------
  3513.     '|                   |                  |
  3514.     '| zone 4            | zone 1           |
  3515.     '|                   |                  |
  3516.     '|--------------------------------------|
  3517.     '|                   |                  |
  3518.     '| zone 3            | zone 2           |
  3519.     '|                   |                  |
  3520.     '|                   |                  |
  3521.     ' --------------------------------------
  3522.    
  3523.     ' in zone   rotation direction   search direction (y,x)
  3524.     ' -------   ------------------   ----------------------
  3525.     ' 1         clockwise            down + right
  3526.         ' 1         counter-clockwise    up   + left
  3527.     ' 2         clockwise            down + left
  3528.     ' 2         counter-clockwise    up   + right
  3529.     ' 3         clockwise            up   + left
  3530.     ' 3         counter-clockwise    down + right
  3531.     ' 4         clockwise            up   + right
  3532.     ' 4         counter-clockwise    down + left
  3533.    
  3534.         if IsProblemAngle%(angle1) then
  3535.                 iMissing = 0
  3536.                 For iLoop = 0 To UBound(arrLost)
  3537.                         bFound = FindEmptyShearRotationPoint4%(arrLost(iLoop), iDirection, iEmpty, x, y, NewArray())
  3538.                         if bFound = TRUE then
  3539.                                 If m_bDebug = TRUE Then
  3540.                                         _echo "Plotted  missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3541.                                 End If
  3542.                         else
  3543.                                 iMissing = iMissing + 1
  3544.                                 If m_bDebug = TRUE Then
  3545.                                         _echo "Detected missing point " + chr$(34) + chr$(arrLost(iLoop).c) + chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3546.                                 End If
  3547.                         end if
  3548.                 Next iLoop
  3549.     end if
  3550. End Sub ' ShearRotate4
  3551.  
  3552. ' /////////////////////////////////////////////////////////////////////////////
  3553. ' Returns TRUE if angle is any of
  3554. ' 30, 60, 120, 150, 210, 240, 300, 330
  3555.  
  3556. ' div: int1% = num1% \ den1%
  3557. ' mod: rem1% = num1% MOD den1%
  3558.  
  3559. function IsProblemAngle%(angle as integer)
  3560.         dim bResult as integer : bResult = FALSE
  3561.         Dim i%
  3562.         For i% = 0 To 360 Step 30
  3563.                 If i% Mod 90 <> 0 Then
  3564.                         if angle = i% then
  3565.                                 bResult = TRUE
  3566.                                 exit for
  3567.                         end if
  3568.                 End If
  3569.         Next i%
  3570.         IsProblemAngle% = bResult
  3571. end function ' IsProblemAngle%
  3572.  
  3573. ' /////////////////////////////////////////////////////////////////////////////
  3574. ' Looks for a new point
  3575. ' a little more accurately, using iDirection parameter
  3576. ' which can be cClockwise or cCounterClockwise.
  3577.  
  3578. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3579.  
  3580. ' Receives
  3581. ' FindMe (RotationType) = contains
  3582. '                         .origx, .origy = the starting location to start looking from,
  3583. '                         .z = which area of the screen the point is in
  3584. '                              (1=top right, 2=bottom right, 3=bottom left, 4=top left)
  3585. '                              to determine direction to look in
  3586. '                         .c = the value to write
  3587. ' iDirection (Integer) = direction of rotation, can be cClockwise or cCounterClockwise (constants must be declared globally)
  3588. ' iEmpty (Integer) = value to test against for empty
  3589. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  3590. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  3591. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  3592.  
  3593. ' Returns
  3594. ' FALSE if no empty spot was found
  3595. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  3596.  
  3597. Function FindEmptyShearRotationPoint4%(FindMe As RotationType, iDirection As Integer, iEmpty as Integer, destX as integer, destY as integer, NewArray() As RotationType)
  3598.     Dim bResult as Integer : bResult = FALSE
  3599.     Dim x As Integer
  3600.     Dim y As Integer
  3601.     Dim dirX As Integer
  3602.     Dim dirY As Integer
  3603.     Dim bContinue As Integer
  3604.        
  3605.         ' Initialize
  3606.     destX = 0
  3607.     destY = 0
  3608.     bContinue = TRUE
  3609.        
  3610.     ' Choose search direction based on the quadrant of the screen
  3611.         ' and the direction of rotation:
  3612.        
  3613.         ' iScreenZone   iDirection           search direction (y,x)
  3614.     ' -----------   ------------------   ----------------------
  3615.     ' 1             cClockwise           down + right ( 1, 1)
  3616.         ' 1             cCounterClockwise    up   + left  (-1,-1)
  3617.     ' 2             cClockwise           down + left  ( 1,-1)
  3618.     ' 2             cCounterClockwise    up   + right (-1, 1)
  3619.     ' 3             cClockwise           up   + left  (-1,-1)
  3620.     ' 3             cCounterClockwise    down + right ( 1, 1)
  3621.     ' 4             cClockwise           up   + right (-1, 1)
  3622.     ' 4             cCounterClockwise    down + left  ( 1,-1)
  3623.        
  3624.     If     FindMe.z = 1 And iDirection = cClockwise Then
  3625.         dirY = 1
  3626.         dirX = 1
  3627.     ElseIf FindMe.z = 1 And iDirection = cCounterClockwise Then
  3628.         dirY = -1
  3629.         dirX = -1
  3630.     ElseIf FindMe.z = 2 And iDirection = cClockwise Then
  3631.         dirY = 1
  3632.         dirX = -1
  3633.     ElseIf FindMe.z = 2 And iDirection = cCounterClockwise Then
  3634.         dirY = -1
  3635.         dirX = 1
  3636.     ElseIf FindMe.z = 3 And iDirection = cClockwise Then
  3637.         dirY = -1
  3638.         dirX = -1
  3639.     ElseIf FindMe.z = 3 And iDirection = cCounterClockwise Then
  3640.         dirY = 1
  3641.         dirX = 1
  3642.     ElseIf FindMe.z = 4 And iDirection = cClockwise Then
  3643.         dirY = -1
  3644.         dirX = 1
  3645.     ElseIf FindMe.z = 4 And iDirection = cCounterClockwise Then
  3646.         dirY = 1
  3647.         dirX = -1
  3648.     Else
  3649.         bContinue = FALSE
  3650.     End If
  3651.    
  3652.         ' Quit if we're out of bounds
  3653.     If bContinue = TRUE Then
  3654.                 bContinue = FALSE
  3655.         x = FindMe.origx
  3656.         y = FindMe.origy
  3657.                 if x >= LBound(NewArray, 1) then
  3658.                         if x <= UBound(NewArray, 1) then
  3659.                                 if y >= LBound(NewArray, 2) then
  3660.                                         if y <= UBound(NewArray, 2) then
  3661.                                                 bContinue = TRUE
  3662.                                         end if
  3663.                                 end if
  3664.                         end if
  3665.                 end if
  3666.         End If
  3667.        
  3668.         ' look along y axis for an available adjacent point
  3669.         If bContinue = TRUE Then
  3670.                 destX = x
  3671.                 destY = y + dirY
  3672.                 if destX >= LBound(NewArray, 1) then
  3673.                         if destX <= UBound(NewArray, 1) then
  3674.                                 if destY >= LBound(NewArray, 2) then
  3675.                                         if destY <= UBound(NewArray, 2) then
  3676.                                                 if NewArray(destX, destY, 0).c = iEmpty then
  3677.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3678.                                                         bResult = TRUE
  3679.                                                         bContinue = FALSE
  3680.                                                 end if
  3681.                                         end if
  3682.                                 end if
  3683.                         end if
  3684.                 end if
  3685.         end if
  3686.        
  3687.         ' look along x axis for an available adjacent point
  3688.         If bContinue = TRUE Then
  3689.                 destX = x + dirX
  3690.                 destY = y
  3691.                 if destX >= LBound(NewArray, 1) then
  3692.                         if destX <= UBound(NewArray, 1) then
  3693.                                 if destY >= LBound(NewArray, 2) then
  3694.                                         if destY <= UBound(NewArray, 2) then
  3695.                                                 if NewArray(x + dirX, y, 0).c = iEmpty then
  3696.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3697.                                                         bResult = TRUE
  3698.                                                         bContinue = FALSE
  3699.                                                 end if
  3700.                                         end if
  3701.                                 end if
  3702.                         end if
  3703.                 end if
  3704.         end if
  3705.        
  3706.         ' look diagonally for an available adjacent point
  3707.         If bContinue = TRUE Then
  3708.                 destX = x + dirX
  3709.                 destY = y + dirY
  3710.                 if destX >= LBound(NewArray, 1) then
  3711.                         if destX <= UBound(NewArray, 1) then
  3712.                                 if destY >= LBound(NewArray, 2) then
  3713.                                         if destY <= UBound(NewArray, 2) then
  3714.                                                 if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  3715.                                                         NewArray(destX, destY, 0).c = FindMe.c
  3716.                                                         bResult = TRUE
  3717.                                                         bContinue = FALSE
  3718.                                                 end if
  3719.                                         end if
  3720.                                 end if
  3721.                         end if
  3722.                 end if
  3723.     End If
  3724.        
  3725. '       ' look (in the opposite direction) along y axis for an available adjacent point
  3726. '       If bContinue = TRUE Then
  3727. '               destX = x
  3728. '               destY = y - dirY
  3729. '               if destX >= LBound(NewArray, 1) then
  3730. '                       if destX <= UBound(NewArray, 1) then
  3731. '                               if destY >= LBound(NewArray, 2) then
  3732. '                                       if destY <= UBound(NewArray, 2) then
  3733. '                                               if NewArray(destX, destY, 0).c = iEmpty then
  3734. '                                                       NewArray(destX, destY, 0).c = FindMe.c
  3735. '                                                       bResult = TRUE
  3736. '                                                       bContinue = FALSE
  3737. '                                               end if
  3738. '                                       end if
  3739. '                               end if
  3740. '                       end if
  3741. '               end if
  3742. '       end if
  3743. '      
  3744. '       ' look (in the opposite direction) along x axis for an available adjacent point
  3745. '       If bContinue = TRUE Then
  3746. '               destX = x - dirX
  3747. '               destY = y
  3748. '               if destX >= LBound(NewArray, 1) then
  3749. '                       if destX <= UBound(NewArray, 1) then
  3750. '                               if destY >= LBound(NewArray, 2) then
  3751. '                                       if destY <= UBound(NewArray, 2) then
  3752. '                                               if NewArray(x + dirX, y, 0).c = iEmpty then
  3753. '                                                       NewArray(destX, destY, 0).c = FindMe.c
  3754. '                                                       bResult = TRUE
  3755. '                                                       bContinue = FALSE
  3756. '                                               end if
  3757. '                                       end if
  3758. '                               end if
  3759. '                       end if
  3760. '               end if
  3761. '       end if
  3762. '      
  3763. '       ' look (in the opposite direction) diagonally for an available adjacent point
  3764. '       If bContinue = TRUE Then
  3765. '               destX = x - dirX
  3766. '               destY = y - dirY
  3767. '               if destX >= LBound(NewArray, 1) then
  3768. '                       if destX <= UBound(NewArray, 1) then
  3769. '                               if destY >= LBound(NewArray, 2) then
  3770. '                                       if destY <= UBound(NewArray, 2) then
  3771. '                                               if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  3772. '                                                       NewArray(destX, destY, 0).c = FindMe.c
  3773. '                                                       bResult = TRUE
  3774. '                                                       bContinue = FALSE
  3775. '                                               end if
  3776. '                                       end if
  3777. '                               end if
  3778. '                       end if
  3779. '               end if
  3780. '    End If
  3781.        
  3782.     ' Return result
  3783.     FindEmptyShearRotationPoint4% = bResult
  3784. End Sub ' FindEmptyShearRotationPoint4%
  3785.  
  3786. ' /////////////////////////////////////////////////////////////////////////////
  3787. ' Tries to correct for missing points with improved logic v3
  3788.  
  3789. ' Receives parameter sMap
  3790. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3791.  
  3792. ' e.g. ShearRotate4Test1 TestSprite1$
  3793.  
  3794. Sub ShearRotate4Test1(sMap As String)
  3795.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3796.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3797.     'Dim sMap As String
  3798.     Dim D As Integer
  3799.     Dim D1 As Integer
  3800.     Dim in$
  3801.     Dim bFinished As Integer
  3802.     Dim iMissing As Integer
  3803.    
  3804.     ' GET A SHAPE TO BE ROTATED
  3805.     Cls
  3806.     Print "3 shear rotation based on code by leopardpm"
  3807.     'sMap = TestSprite1$
  3808.    
  3809.     ' CONVERT SHAPE TO ARRAY
  3810.     StringToRotationArray RoArray1(), sMap, "."
  3811.  
  3812.     ' GET START ANGLE
  3813.     D = 0
  3814.     Print
  3815.     Print "Rotated by " + cstr$(D) + " degrees:"
  3816.     Print RotationArrayToStringTest(RoArray1())
  3817.     Print
  3818.     Print "Type an angle (-360 to 360) to rotate to, "
  3819.     Print "or blank to increase by 1 degree, or q to quit."
  3820.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3821.     Print "Hold down <ENTER> to rotate continually."
  3822.     Input "Angle (q to quit)? ", in$
  3823.     If Len(in$) > 0 Then
  3824.         If IsNum%(in$) Then
  3825.             D1 = Val(in$)
  3826.         Else
  3827.             D1 = -500
  3828.         End If
  3829.     Else
  3830.         D1 = 1
  3831.     End If
  3832.  
  3833.     ' ROTATE TO EACH ANGLE
  3834.     If D1 >= -360 And D1 <= 360 Then
  3835.         bFinished = FALSE
  3836.         Do
  3837.             ' ROTATE CLOCKWISE
  3838.             For D = D1 To 360
  3839.                 Cls
  3840.                                
  3841.                 ShearRotate4 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  3842.                 Print
  3843.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3844.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3845.                
  3846.                 Print RotationArrayToStringTest(RoArray2())
  3847.                 Print
  3848.                
  3849.                 Print "Type an angle (-360 to 360) to rotate to, "
  3850.                 Print "or blank to increase by 1 degree, or q to quit."
  3851.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3852.                 Print "Hold down <ENTER> to rotate continually."
  3853.                 Input "Angle (q to quit)? ", in$
  3854.                 If Len(in$) > 0 Then
  3855.                     If IsNum%(in$) Then
  3856.                         D = Val(in$)
  3857.                         If D >= 0 And D <= 360 Then
  3858.                             D = D - 1
  3859.                         Else
  3860.                             bFinished = TRUE
  3861.                             Exit For
  3862.                         End If
  3863.                     Else
  3864.                         bFinished = TRUE
  3865.                         Exit For
  3866.                     End If
  3867.                 End If
  3868.             Next D
  3869.             If bFinished = TRUE Then Exit Do
  3870.            
  3871.             ' ROTATE COUNTER-CLOCKWISE
  3872.             For D = 360 To D1 Step -1
  3873.                 Cls
  3874.                 ShearRotate4 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  3875.                 Print
  3876.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3877.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3878.                
  3879.                 Print RotationArrayToStringTest(RoArray2())
  3880.                 Print
  3881.  
  3882.                 Print "Type an angle (0 to 360) to rotate to, "
  3883.                 Print "or blank to increase by 1 degree, or q to quit."
  3884.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3885.                 Print "Hold down <ENTER> to rotate continually."
  3886.                 Input "Angle (q to quit)? ", in$
  3887.                 If Len(in$) > 0 Then
  3888.                     If IsNum%(in$) Then
  3889.                         D = Val(in$)
  3890.                         If D >= 0 And D <= 360 Then
  3891.                             D = D + 1
  3892.                         Else
  3893.                             bFinished = TRUE
  3894.                             Exit For
  3895.                         End If
  3896.                     Else
  3897.                         bFinished = TRUE
  3898.                         Exit For
  3899.                     End If
  3900.                 End If
  3901.             Next D
  3902.             If bFinished = TRUE Then Exit Do
  3903.         Loop
  3904.     End If
  3905. End Sub ' ShearRotate4Test1
  3906.  
  3907. ' /////////////////////////////////////////////////////////////////////////////
  3908. ' Correct for overwriting points issue
  3909. ' (happens at 30, 60, 120, 150, 210, 240, 300, 330 degrees)
  3910. ' using STxAxTIC's method of merging array rotated to angle-1 and angle+1
  3911.  
  3912. Sub ShearRotate5 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  3913.     ReDim arrCW(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3914.     ReDim arrCCW(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3915.        
  3916.         ' If rotation is 30, 60, 120, 150, 210, 240, 300, 330 degrees
  3917.         ' then try correcting for overwriting.
  3918.         if IsProblemAngle%(angle1) then
  3919.                 ' get array rotated to angle-1
  3920.                 ShearRotate OldArray(), arrCW(), angle1-1, iEmpty
  3921.                
  3922.                 ' get array rotated to angle
  3923.                 ShearRotate OldArray(), NewArray(), angle1-1, iEmpty
  3924.                
  3925.                 ' get array rotated to angle=1
  3926.                 ShearRotate OldArray(), arrCCW(), angle1+1, iEmpty
  3927.                
  3928.                 ' merge the results
  3929.                 For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3930.                         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3931.                                 ' is point empty?
  3932.                                 if NewArray(x, y, 0).c = iEmpty then
  3933.                                         ' see if point is occupied 1 deg. counter-clockwise
  3934.                                         if arrCCW(x, y, 0).c <> iEmpty then
  3935.                                                 NewArray(x, y, 0).c = arrCCW(x, y, 0).c
  3936.                                         ' see if point is occupied 1 deg. clockwise
  3937.                                         elseif arrCW(x, y, 0).c <> iEmpty then
  3938.                                                 NewArray(x, y, 0).c = arrCW(x, y, 0).c
  3939.                                         end if
  3940.                                 end if
  3941.                         Next y
  3942.                 Next x
  3943.         ' Otherwise rotate without correcting.
  3944.         else
  3945.                 ShearRotate OldArray(), NewArray(), angle1, iEmpty
  3946.         end if
  3947. End Sub ' ShearRotate5
  3948.  
  3949. ' /////////////////////////////////////////////////////////////////////////////
  3950. ' Tries to correct for missing (overwritten) points
  3951. ' using STxAxTIC's method to correct for overwritten points
  3952.  
  3953. ' Receives parameter sMap
  3954. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3955.  
  3956. ' e.g. ShearRotate5Test1 TestSprite1$
  3957.  
  3958. Sub ShearRotate5Test1(sMap As String)
  3959.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3960.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3961.     'Dim sMap As String
  3962.     Dim D As Integer
  3963.     Dim D1 As Integer
  3964.     Dim in$
  3965.     Dim bFinished As Integer
  3966.     'Dim iMissing As Integer
  3967.    
  3968.     ' GET A SHAPE TO BE ROTATED
  3969.     Cls
  3970.     Print "3 shear rotation based on code by leopardpm"
  3971.         Print "using STxAxTIC's method to correct for overwritten points"
  3972.     'sMap = TestSprite1$
  3973.    
  3974.     ' CONVERT SHAPE TO ARRAY
  3975.     StringToRotationArray RoArray1(), sMap, "."
  3976.  
  3977.     ' GET START ANGLE
  3978.     D = 0
  3979.     Print
  3980.     Print "Rotated by " + cstr$(D) + " degrees:"
  3981.     Print RotationArrayToStringTest(RoArray1())
  3982.     Print
  3983.     Print "Type an angle (-360 to 360) to rotate to, "
  3984.     Print "or blank to increase by 1 degree, or q to quit."
  3985.     Print "Note: Tries to fix for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3986.     Print "Hold down <ENTER> to rotate continually."
  3987.     Input "Angle (q to quit)? ", in$
  3988.     If Len(in$) > 0 Then
  3989.         If IsNum%(in$) Then
  3990.             D1 = Val(in$)
  3991.         Else
  3992.             D1 = -500
  3993.         End If
  3994.     Else
  3995.         D1 = 1
  3996.     End If
  3997.  
  3998.     ' ROTATE TO EACH ANGLE
  3999.     If D1 >= -360 And D1 <= 360 Then
  4000.         bFinished = FALSE
  4001.         Do
  4002.             ' ROTATE CLOCKWISE
  4003.             For D = D1 To 360
  4004.                 Cls
  4005.                                
  4006.                 'ShearRotate4 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  4007.                                 ShearRotate5 RoArray1(), RoArray2(), D, Asc(".")
  4008.                 Print
  4009.                 Print "Rotated by " + cstr$(D) + " degrees:"
  4010.                 'Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  4011.                
  4012.                 Print RotationArrayToStringTest(RoArray2())
  4013.                 Print
  4014.                
  4015.                 Print "Type an angle (-360 to 360) to rotate to, "
  4016.                 Print "or blank to increase by 1 degree, or q to quit."
  4017.                 Print "Note: Tries to fix for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4018.                 Print "Hold down <ENTER> to rotate continually."
  4019.                 Input "Angle (q to quit)? ", in$
  4020.                 If Len(in$) > 0 Then
  4021.                     If IsNum%(in$) Then
  4022.                         D = Val(in$)
  4023.                         If D >= 0 And D <= 360 Then
  4024.                             D = D - 1
  4025.                         Else
  4026.                             bFinished = TRUE
  4027.                             Exit For
  4028.                         End If
  4029.                     Else
  4030.                         bFinished = TRUE
  4031.                         Exit For
  4032.                     End If
  4033.                 End If
  4034.             Next D
  4035.             If bFinished = TRUE Then Exit Do
  4036.            
  4037.             ' ROTATE COUNTER-CLOCKWISE
  4038.             For D = 360 To D1 Step -1
  4039.                 Cls
  4040.                 'ShearRotate4 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  4041.                                 ShearRotate5 RoArray1(), RoArray2(), D, Asc(".")
  4042.                 Print
  4043.                 Print "Rotated by " + cstr$(D) + " degrees:"
  4044.                 'Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  4045.                
  4046.                 Print RotationArrayToStringTest(RoArray2())
  4047.                 Print
  4048.  
  4049.                 Print "Type an angle (0 to 360) to rotate to, "
  4050.                 Print "or blank to increase by 1 degree, or q to quit."
  4051.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4052.                 Print "Hold down <ENTER> to rotate continually."
  4053.                 Input "Angle (q to quit)? ", in$
  4054.                 If Len(in$) > 0 Then
  4055.                     If IsNum%(in$) Then
  4056.                         D = Val(in$)
  4057.                         If D >= 0 And D <= 360 Then
  4058.                             D = D + 1
  4059.                         Else
  4060.                             bFinished = TRUE
  4061.                             Exit For
  4062.                         End If
  4063.                     Else
  4064.                         bFinished = TRUE
  4065.                         Exit For
  4066.                     End If
  4067.                 End If
  4068.             Next D
  4069.             If bFinished = TRUE Then Exit Do
  4070.         Loop
  4071.     End If
  4072. End Sub ' ShearRotate5Test1
  4073.  
  4074. ' /////////////////////////////////////////////////////////////////////////////
  4075.  
  4076. Function TestSprite1$
  4077.     Dim m$
  4078.     m$ = ""
  4079.     '                   11111111112222222222333
  4080.     '          12345678901234567890123456789012
  4081.     m$ = m$ + "11111111111111111111111111111111" + Chr$(13) ' 1
  4082.     m$ = m$ + "4..............................2" + Chr$(13) ' 2
  4083.     m$ = m$ + "4....##.....#######.....####...2" + Chr$(13) ' 3
  4084.     m$ = m$ + "4...####....##...###...######..2" + Chr$(13) ' 4
  4085.     m$ = m$ + "4..##..##...##...###..##....##.2" + Chr$(13) ' 5
  4086.     m$ = m$ + "4.##....##..#######...##.......2" + Chr$(13) ' 6
  4087.     m$ = m$ + "4.########..#######...##.......2" + Chr$(13) ' 7
  4088.     m$ = m$ + "4.########..##...###..##....##.2" + Chr$(13) ' 8
  4089.     m$ = m$ + "4.##....##..##...###...######..2" + Chr$(13) ' 9
  4090.     m$ = m$ + "4.##....##..#######.....####...2" + Chr$(13) ' 10
  4091.     m$ = m$ + "4..............................2" + Chr$(13) ' 11
  4092.     m$ = m$ + "4..............................2" + Chr$(13) ' 12
  4093.     m$ = m$ + "4..ABBBBBBBBBBBBBBBBBBBBBBBBC..2" + Chr$(13) ' 13
  4094.     m$ = m$ + "4..A...........EE...........C..2" + Chr$(13) ' 14
  4095.     m$ = m$ + "4..A..........FFFF..........C..2" + Chr$(13) ' 15
  4096.     m$ = m$ + "4..A.........GGGGGG.........C..2" + Chr$(13) ' 16
  4097.     m$ = m$ + "4..A........HHHHHHHH........C..2" + Chr$(13) ' 17
  4098.     m$ = m$ + "4..A.......IIIIIIIIII.......C..2" + Chr$(13) ' 18
  4099.     m$ = m$ + "4..A......JJJJJJJJJJJJ......C..2" + Chr$(13) ' 19
  4100.     m$ = m$ + "4..DDDDDDDDDDDDDDDDDDDDDDDDDC..2" + Chr$(13) ' 20
  4101.     m$ = m$ + "4..............................2" + Chr$(13) ' 21
  4102.     m$ = m$ + "4..............................2" + Chr$(13) ' 22
  4103.     m$ = m$ + "4.######....########..########.2" + Chr$(13) ' 23
  4104.     m$ = m$ + "4.#######...########..########.2" + Chr$(13) ' 24
  4105.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 25
  4106.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 26
  4107.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 27
  4108.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 28
  4109.     m$ = m$ + "4.#######...##........##.......2" + Chr$(13) ' 29
  4110.     m$ = m$ + "4.######....########..##.......2" + Chr$(13) ' 30
  4111.     m$ = m$ + "4..............................2" + Chr$(13) ' 31
  4112.     m$ = m$ + "33333333333333333333333333333332" + Chr$(13) ' 32
  4113.     TestSprite1$ = m$
  4114. End Function ' TestSprite1$
  4115.  
  4116. ' /////////////////////////////////////////////////////////////////////////////
  4117.  
  4118. Function TestSprite2$
  4119.     Dim m$
  4120.     m$ = ""
  4121.     '                   11111111112222222222333
  4122.     '          12345678901234567890123456789012
  4123.     m$ = m$ + "...............AA..............." + Chr$(13) ' 1
  4124.     m$ = m$ + "..............//BB.............." + Chr$(13) ' 2
  4125.     m$ = m$ + ".............??..CC............." + Chr$(13) ' 3
  4126.     m$ = m$ + "............==....DD............" + Chr$(13) ' 4
  4127.     m$ = m$ + "...........++......EE..........." + Chr$(13) ' 5
  4128.     m$ = m$ + "..........&&........FF.........." + Chr$(13) ' 6
  4129.     m$ = m$ + ".........zz..........GG........." + Chr$(13) ' 7
  4130.     m$ = m$ + "........yy............HH........" + Chr$(13) ' 8
  4131.     m$ = m$ + ".......xx..............II......." + Chr$(13) ' 9
  4132.     m$ = m$ + "......ww................JJ......" + Chr$(13) ' 10
  4133.     m$ = m$ + ".....vv..................KK....." + Chr$(13) ' 11
  4134.     m$ = m$ + "....uu....................LL...." + Chr$(13) ' 12
  4135.     m$ = m$ + "...tt......DDAAAAAAA.......MM..." + Chr$(13) ' 13
  4136.     m$ = m$ + "..ss.......DDAAAAAAA........NN.." + Chr$(13) ' 14
  4137.     m$ = m$ + ".rr........DD.....BB.........OO." + Chr$(13) ' 15
  4138.     m$ = m$ + "qq.........DD.....BB..........PP" + Chr$(13) ' 16
  4139.     m$ = m$ + "pp.........DD.....BB..........QQ" + Chr$(13) ' 17
  4140.     m$ = m$ + ".oo........DD.....BB.........RR." + Chr$(13) ' 18
  4141.     m$ = m$ + "..nn.......CCCCCCCBB........SS.." + Chr$(13) ' 19
  4142.     m$ = m$ + "...mm......CCCCCCCBB.......TT..." + Chr$(13) ' 20
  4143.     m$ = m$ + "....ll....................UU...." + Chr$(13) ' 21
  4144.     m$ = m$ + ".....kk..................VV....." + Chr$(13) ' 22
  4145.     m$ = m$ + "......jj................WW......" + Chr$(13) ' 23
  4146.     m$ = m$ + ".......ii..............XX......." + Chr$(13) ' 24
  4147.     m$ = m$ + "........hh............YY........" + Chr$(13) ' 25
  4148.     m$ = m$ + ".........gg..........ZZ........." + Chr$(13) ' 26
  4149.     m$ = m$ + "..........ff........@@.........." + Chr$(13) ' 27
  4150.     m$ = m$ + "...........ee......##..........." + Chr$(13) ' 28
  4151.     m$ = m$ + "............dd....$$............" + Chr$(13) ' 29
  4152.     m$ = m$ + ".............cc..%%............." + Chr$(13) ' 30
  4153.     m$ = m$ + "..............bb\\.............." + Chr$(13) ' 31
  4154.     m$ = m$ + "...............aa..............." + Chr$(13) ' 32
  4155.     TestSprite2$ = m$
  4156. End Function ' TestSprite2$
  4157.  
  4158. ' /////////////////////////////////////////////////////////////////////////////
  4159.  
  4160. Function PetrText1$
  4161.     Dim m$
  4162.     m$ = ""
  4163.     '                   11111111112222222222333
  4164.     '          12345678901234567890123456789012
  4165.     m$ = m$ + "................................" + Chr$(13) ' 1
  4166.     m$ = m$ + "................................" + Chr$(13) ' 2
  4167.     m$ = m$ + "................................" + Chr$(13) ' 3
  4168.     m$ = m$ + "................................" + Chr$(13) ' 4
  4169.     m$ = m$ + "................................" + Chr$(13) ' 5
  4170.     m$ = m$ + "................................" + Chr$(13) ' 6
  4171.     m$ = m$ + "................................" + Chr$(13) ' 7
  4172.     m$ = m$ + "................................" + Chr$(13) ' 8
  4173.     m$ = m$ + "................................" + Chr$(13) ' 9
  4174.     m$ = m$ + "................................" + Chr$(13) ' 10
  4175.     m$ = m$ + "................................" + Chr$(13) ' 11
  4176.     m$ = m$ + "................................" + Chr$(13) ' 12
  4177.     m$ = m$ + "................................" + Chr$(13) ' 13
  4178.     m$ = m$ + "................................" + Chr$(13) ' 14
  4179.     m$ = m$ + "....It's a SCREEN resolution?..." + Chr$(13) ' 15
  4180.     m$ = m$ + "................................" + Chr$(13) ' 16
  4181.     m$ = m$ + "................................" + Chr$(13) ' 17
  4182.     m$ = m$ + "................................" + Chr$(13) ' 18
  4183.     m$ = m$ + "................................" + Chr$(13) ' 19
  4184.     m$ = m$ + "................................" + Chr$(13) ' 20
  4185.     m$ = m$ + "................................" + Chr$(13) ' 21
  4186.     m$ = m$ + "................................" + Chr$(13) ' 22
  4187.     m$ = m$ + "................................" + Chr$(13) ' 23
  4188.     m$ = m$ + "................................" + Chr$(13) ' 24
  4189.     m$ = m$ + "................................" + Chr$(13) ' 25
  4190.     m$ = m$ + "................................" + Chr$(13) ' 26
  4191.     m$ = m$ + "................................" + Chr$(13) ' 27
  4192.     m$ = m$ + "................................" + Chr$(13) ' 28
  4193.     m$ = m$ + "................................" + Chr$(13) ' 29
  4194.     m$ = m$ + "................................" + Chr$(13) ' 30
  4195.     m$ = m$ + "................................" + Chr$(13) ' 31
  4196.     m$ = m$ + "................................" + Chr$(13) ' 32
  4197.     PetrText1$ = m$
  4198. End Function ' PetrText1$
  4199.  
  4200. ' /////////////////////////////////////////////////////////////////////////////
  4201.  
  4202. Function ArrayToString$ (MyArray( 1 To 32 , 1 To 32) As String)
  4203.     Dim MyString As String
  4204.     Dim iY As Integer
  4205.     Dim iX As Integer
  4206.     Dim sLine As String
  4207.     MyString = ""
  4208.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  4209.         sLine = ""
  4210.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  4211.             sLine = sLine + MyArray(iY, iX)
  4212.         Next iX
  4213.         MyString = MyString + sLine + Chr$(13)
  4214.     Next iY
  4215.     ArrayToString$ = MyString
  4216. End Function ' ArrayToString$
  4217.  
  4218. ' /////////////////////////////////////////////////////////////////////////////
  4219.  
  4220. Function ArrayToStringTest$ (MyArray() As String)
  4221.     Dim MyString As String
  4222.     Dim iY As Integer
  4223.     Dim iX As Integer
  4224.     Dim sLine As String
  4225.     MyString = ""
  4226.  
  4227.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  4228.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  4229.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  4230.         sLine = ""
  4231.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  4232.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  4233.             sLine = sLine + MyArray(iY, iX)
  4234.         Next iX
  4235.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  4236.         MyString = MyString + sLine + Chr$(13)
  4237.     Next iY
  4238.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  4239.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  4240.     ArrayToStringTest$ = MyString
  4241. End Function ' ArrayToStringTest$
  4242.  
  4243. ' /////////////////////////////////////////////////////////////////////////////
  4244.  
  4245. Function RotationArrayToStringTest$ (RoArray() As RotationType)
  4246.     Dim MyString As String
  4247.     Dim iY As Integer
  4248.     Dim iX As Integer
  4249.     Dim sLine As String
  4250.     MyString = ""
  4251.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  4252.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  4253.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  4254.     For iY = LBound(RoArray, 1) To UBound(RoArray, 1)
  4255.         sLine = ""
  4256.         sLine = sLine + Right$("    " + cstr$(iY), 3)
  4257.         For iX = LBound(RoArray, 2) To UBound(RoArray, 2)
  4258.             sLine = sLine + Chr$(RoArray(iX, iY, 0).c)
  4259.         Next iX
  4260.         sLine = sLine + Right$("   " + cstr$(iY), 3)
  4261.         MyString = MyString + sLine + Chr$(13)
  4262.     Next iY
  4263.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  4264.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  4265.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  4266.     RotationArrayToStringTest$ = MyString
  4267. End Function ' RotationArrayToStringTest$
  4268.  
  4269. ' /////////////////////////////////////////////////////////////////////////////
  4270. ' 1. split string by line breaks CHR$(13)
  4271. ' 2. split lines up to 1 column per char
  4272. ' 3. count rows, columns
  4273. ' 4. DIM array, making sure array has
  4274. '    a) an _ODD_ number of rows/columns, with a center point
  4275. '    b) index is in cartesian format, where center is (0,0)
  4276. ' 5. populate array with contents of string
  4277.  
  4278. ' dimension #1 = columns
  4279. ' dimension #2 = rows
  4280.  
  4281. Sub StringToRotationArray (RoArray() As RotationType, MyString As String, EmptyChar As String)
  4282.     Dim RoutineName As String: RoutineName = "StringToRotationArray"
  4283.     ReDim arrLines$(0)
  4284.     Dim delim$
  4285.     Dim iRow%
  4286.     Dim iCol%
  4287.     Dim sChar$
  4288.     Dim iColCount As Integer
  4289.     Dim iRowCount As Integer
  4290.     Dim iCount As Integer
  4291.     Dim bAddedRow As Integer: bAddedRow = FALSE
  4292.     Dim bAddedColumn As Integer: bAddedColumn = FALSE
  4293.     Dim iHalf1 As Integer
  4294.     Dim iHalf2 As Integer
  4295.     Dim iFrom1 As Integer
  4296.     Dim iFrom2 As Integer
  4297.     Dim iTo1 As Integer
  4298.     Dim iTo2 As Integer
  4299.     Dim iEmpty As Integer
  4300.     Dim iX As Integer
  4301.     Dim iY As Integer
  4302.  
  4303.     delim$ = Chr$(13)
  4304.     split MyString, delim$, arrLines$()
  4305.  
  4306.     iRowCount = UBound(arrLines$) + 1
  4307.  
  4308.     ' look at all the rows and find the max # of columns used
  4309.     iColCount = 0
  4310.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4311.  
  4312.         ' count the columns for this row
  4313.         iCount = 0
  4314.         For iCol% = 1 To Len(arrLines$(iRow%))
  4315.             iCount = iCount + 1
  4316.         Next iCol%
  4317.  
  4318.         ' if this row has the most so far, then set that to the max
  4319.         If iCount > iColCount Then
  4320.             iColCount = iCount
  4321.         End If
  4322.     Next iRow%
  4323.  
  4324.     ' adjust columns to be odd
  4325.     If IsEven%(iColCount) Then
  4326.         iColCount = iColCount + 1
  4327.         bAddedColumn = TRUE
  4328.     End If
  4329.  
  4330.     ' calculate array bounds for columns
  4331.     iHalf1 = (iColCount - 1) / 2
  4332.     iFrom1 = 0 - iHalf1
  4333.     iTo1 = iHalf1
  4334.  
  4335.     ' adjust rows to be odd
  4336.     If IsEven%(iRowCount) Then
  4337.         iRowCount = iRowCount + 1
  4338.         bAddedRow = TRUE
  4339.     End If
  4340.  
  4341.     ' calculate array bounds for rows
  4342.     iHalf2 = (iRowCount - 1) / 2
  4343.     iFrom2 = 0 - iHalf2
  4344.     iTo2 = iHalf2
  4345.  
  4346.     ' size array to new bounds
  4347.     ReDim RoArray(iFrom1 To iTo1, iFrom2 To iTo2, 127) As RotationType
  4348.  
  4349.     ' get value for empty
  4350.     If Len(EmptyChar) > 0 Then
  4351.         iEmpty = Asc(EmptyChar)
  4352.     Else
  4353.         iEmpty = 32 ' (use space as default)
  4354.     End If
  4355.  
  4356.     ' clear array
  4357.     For iY = LBound(RoArray, 2) To UBound(RoArray, 2)
  4358.         For iX = LBound(RoArray, 1) To UBound(RoArray, 1)
  4359.             RoArray(iX, iY, 0).c = iEmpty
  4360.             RoArray(iX, iY, 0).origx = iX
  4361.             RoArray(iX, iY, 0).origy = iY
  4362.         Next iX
  4363.     Next iY
  4364.  
  4365.     ' fill array
  4366.     iY = LBound(RoArray, 2) - 1
  4367.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4368.         iY = iY + 1
  4369.         iX = LBound(RoArray, 1) - 1
  4370.         For iCol% = 1 To Len(arrLines$(iRow%))
  4371.             iX = iX + 1
  4372.             sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  4373.             RoArray(iX, iY, 0).c = Asc(sChar$)
  4374.         Next iCol%
  4375.     Next iRow%
  4376.  
  4377. End Sub ' StringToRotationArray
  4378.  
  4379. ' /////////////////////////////////////////////////////////////////////////////
  4380.  
  4381. Sub StringToArray (MyArray() As String, MyString As String)
  4382.     Dim delim$
  4383.     ReDim arrLines$(0)
  4384.     Dim iRow%
  4385.     Dim iCol%
  4386.     Dim sChar$
  4387.     Dim iDim1 As Integer
  4388.     Dim iDim2 As Integer
  4389.     iDim1 = LBound(MyArray, 1)
  4390.     iDim2 = LBound(MyArray, 2)
  4391.     delim$ = Chr$(13)
  4392.     split MyString, delim$, arrLines$()
  4393.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4394.         If iRow% <= UBound(MyArray, 2) Then
  4395.             For iCol% = 1 To Len(arrLines$(iRow%))
  4396.                 If iCol% <= UBound(MyArray, 1) Then
  4397.                     sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  4398.  
  4399.                     If Len(sChar$) > 1 Then
  4400.                         sChar$ = Left$(sChar$, 1)
  4401.                     Else
  4402.                         If Len(sChar$) = 0 Then
  4403.                             sChar$ = "."
  4404.                         End If
  4405.                     End If
  4406.                     MyArray(iRow% + iDim1, (iCol% - 1) + iDim2) = sChar$
  4407.                 Else
  4408.                     ' Exit if out of bounds
  4409.                     Exit For
  4410.                 End If
  4411.             Next iCol%
  4412.         Else
  4413.             ' Exit if out of bounds
  4414.             Exit For
  4415.         End If
  4416.     Next iRow%
  4417. End Sub ' StringToArray
  4418.  
  4419. ' /////////////////////////////////////////////////////////////////////////////
  4420.  
  4421. 'SUB ClearArray (MyArray(1 To 32, 1 To 32) AS STRING, MyString As String)
  4422. Sub ClearArray (MyArray() As String, MyString As String)
  4423.     Dim iRow As Integer
  4424.     Dim iCol As Integer
  4425.     Dim sChar$
  4426.     If Len(MyString) = 1 Then
  4427.         sChar$ = MyString
  4428.     Else
  4429.         If Len(MyString) = 0 Then
  4430.             sChar$ = " "
  4431.         Else
  4432.             sChar$ = Left$(MyString, 1)
  4433.         End If
  4434.     End If
  4435.     For iRow = LBound(MyArray, 1) To UBound(MyArray, 1)
  4436.         For iCol = LBound(MyArray, 2) To UBound(MyArray, 2)
  4437.             MyArray(iRow, iCol) = sChar$
  4438.         Next iCol
  4439.     Next iRow
  4440. End Sub ' ClearArray
  4441.  
  4442. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4443. ' BEGIN GENERAL PURPOSE ROUTINES
  4444. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4445.  
  4446. ' /////////////////////////////////////////////////////////////////////////////
  4447.  
  4448. Function cstr$ (myValue)
  4449.     'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
  4450.     cstr$ = _Trim$(Str$(myValue))
  4451. End Function ' cstr$
  4452.  
  4453. Function cstrl$ (myValue As Long)
  4454.     cstrl$ = _Trim$(Str$(myValue))
  4455. End Function ' cstrl$
  4456.  
  4457. ' /////////////////////////////////////////////////////////////////////////////
  4458.  
  4459. Function IIF (Condition, IfTrue, IfFalse)
  4460.     If Condition Then IIF = IfTrue Else IIF = IfFalse
  4461.  
  4462. ' /////////////////////////////////////////////////////////////////////////////
  4463.  
  4464. Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
  4465.     If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
  4466.  
  4467. ' /////////////////////////////////////////////////////////////////////////////
  4468. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  4469.  
  4470. Function IsEven% (n)
  4471.     If n Mod 2 = 0 Then
  4472.         IsEven% = TRUE
  4473.     Else
  4474.         IsEven% = FALSE
  4475.     End If
  4476. End Function ' IsEven%
  4477.  
  4478. ' /////////////////////////////////////////////////////////////////////////////
  4479. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  4480.  
  4481. Function IsOdd% (n)
  4482.     If n Mod 2 = 1 Then
  4483.         IsOdd% = TRUE
  4484.     Else
  4485.         IsOdd% = FALSE
  4486.     End If
  4487. End Function ' IsOdd%
  4488.  
  4489. ' /////////////////////////////////////////////////////////////////////////////
  4490. ' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0
  4491.  
  4492. Function IsNum% (text$)
  4493.     Dim a$
  4494.     Dim b$
  4495.     a$ = _Trim$(text$)
  4496.     b$ = _Trim$(Str$(Val(text$)))
  4497.     If a$ = b$ Then
  4498.         IsNum% = TRUE
  4499.     Else
  4500.         IsNum% = FALSE
  4501.     End If
  4502. End Function ' IsNum%
  4503.  
  4504. ' /////////////////////////////////////////////////////////////////////////////
  4505. ' Split and join strings
  4506. ' https://www.qb64.org/forum/index.php?topic=1073.0
  4507.  
  4508. 'Combine all elements of in$() into a single string with delimiter$ separating the elements.
  4509.  
  4510. Function join$ (in$(), delimiter$)
  4511.     result$ = in$(LBound(in$))
  4512.     For i = LBound(in$) + 1 To UBound(in$)
  4513.         result$ = result$ + delimiter$ + in$(i)
  4514.     Next i
  4515.     join$ = result$
  4516. End Function ' join$
  4517.  
  4518. ' /////////////////////////////////////////////////////////////////////////////
  4519. ' FROM: String Manipulation
  4520. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index_topic_5964-0/
  4521. '
  4522. 'SUMMARY:
  4523. '   Purpose:  A library of custom functions that transform strings.
  4524. '   Author:   Dustinian Camburides (dustinian@gmail.com)
  4525. '   Platform: QB64 (www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there])
  4526. '   Revision: 1.6
  4527. '   Updated:  5/28/2012
  4528.  
  4529. 'SUMMARY:
  4530. '[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
  4531. 'INPUT:
  4532. 'Text: The input string; the text that's being manipulated.
  4533. 'Find: The specified sub-string; the string sought within the [Text] string.
  4534. 'Add: The sub-string that's being added to the [Text] string.
  4535.  
  4536. Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
  4537.     ' VARIABLES:
  4538.     Dim Text2 As String
  4539.     Dim Find2 As String
  4540.     Dim Add2 As String
  4541.     Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
  4542.     Dim strBefore As String ' The characters before the string to be replaced.
  4543.     Dim strAfter As String ' The characters after the string to be replaced.
  4544.  
  4545.     ' INITIALIZE:
  4546.     ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
  4547.     Text2 = Text1
  4548.     Find2 = Find1
  4549.     Add2 = Add1
  4550.  
  4551.     lngLocation = InStr(1, Text2, Find2)
  4552.  
  4553.     ' PROCESSING:
  4554.     ' While [Find2] appears in [Text2]...
  4555.     While lngLocation
  4556.         ' Extract all Text2 before the [Find2] substring:
  4557.         strBefore = Left$(Text2, lngLocation - 1)
  4558.  
  4559.         ' Extract all text after the [Find2] substring:
  4560.         strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
  4561.  
  4562.         ' Return the substring:
  4563.         Text2 = strBefore + Add2 + strAfter
  4564.  
  4565.         ' Locate the next instance of [Find2]:
  4566.         lngLocation = InStr(1, Text2, Find2)
  4567.  
  4568.         ' Next instance of [Find2]...
  4569.     Wend
  4570.  
  4571.     ' OUTPUT:
  4572.     Replace$ = Text2
  4573. End Function ' Replace$
  4574.  
  4575. ' /////////////////////////////////////////////////////////////////////////////
  4576. ' Split and join strings
  4577. ' https://www.qb64.org/forum/index.php?topic=1073.0
  4578. '
  4579. ' FROM luke, QB64 Developer
  4580. ' Date: February 15, 2019, 04:11:07 AM
  4581. '
  4582. ' Given a string of words separated by spaces (or any other character),
  4583. ' splits it into an array of the words. I've no doubt many people have
  4584. ' written a version of this over the years and no doubt there's a million
  4585. ' ways to do it, but I thought I'd put mine here so we have at least one
  4586. ' version. There's also a join function that does the opposite
  4587. ' array -> single string.
  4588. '
  4589. ' Code is hopefully reasonably self explanatory with comments and a little demo.
  4590. ' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.
  4591.  
  4592. 'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
  4593. 'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
  4594. '
  4595. 'delimiter$ must be one character long.
  4596. 'result$() must have been REDIMmed previously.
  4597.  
  4598. Sub split (in$, delimiter$, result$())
  4599.     ReDim result$(-1)
  4600.     start = 1
  4601.     Do
  4602.         While Mid$(in$, start, 1) = delimiter$
  4603.             start = start + 1
  4604.             If start > Len(in$) Then Exit Sub
  4605.         Wend
  4606.         finish = InStr(start, in$, delimiter$)
  4607.         If finish = 0 Then finish = Len(in$) + 1
  4608.         ReDim _Preserve result$(0 To UBound(result$) + 1)
  4609.         result$(UBOUND(result$)) = MID$(in$, start, finish - start)
  4610.         start = finish + 1
  4611.     LOOP WHILE start <= LEN(in$)
  4612. END SUB ' split
  4613.  
  4614. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4615. ' END GENERAL PURPOSE ROUTINES
  4616. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4617.  
  4618. ' #END
  4619. ' ################################################################################################################################################################
  4620.  

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
So I have to do a bunch of reading to catch up to where the discussion is,

After some further thinking on it, I had another idea - what if the mask arrays were precalculated? For a given size 2D array, we could precalculate the rotation for all of the problem angles (there are only 8 of them) and the adjacent angles (angle-1, angle+1), so that would be 24 copies of the array, which can even be hardcoded since they're just arrays of numbers. That eliminates the bulk of the copying of arrays work, so you get accuracy and the performance hit is much less. The main cost becomes the memory to store those 24 arrays, which depends on how big a sprite or screen or grid you want to rotate. A 32x32 sprite would be 32x32x24 times whatever it is you're storing as a "point", whether a byte, integer, unsigned long (for an rgb color), a text character, user defined type, etc.

Thoughts?

Update: I started on some code to try above, code below. Option 23 from the menu...
Code: QB64: [Select]
  1. ' ################################################################################################################################################################
  2. ' #TOP
  3.  
  4. ' Basic 2D plotting functions
  5. ' Version 1.00 by madscijr
  6. ' with help from various (sources cited below).
  7. ' ################################################################################################################################################################
  8.  
  9. ' =============================================================================
  10. ' GLOBAL DECLARATIONS
  11. ' =============================================================================
  12.  
  13. ' boolean constants
  14. Const FALSE = 0
  15. Const TRUE = Not FALSE
  16.  
  17. ' rotational constants
  18. Const cCounterClockwise = -1
  19. Const cClockwise = 1
  20.  
  21. ' -----------------------------------------------------------------------------
  22. ' USER DEFINED TYPES
  23. ' -----------------------------------------------------------------------------
  24. Type RotationType
  25.     origx As Integer
  26.     origy As Integer
  27.     c As Integer
  28.     z As Integer ' which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  29. End Type ' RotationType
  30.  
  31. ' -----------------------------------------------------------------------------
  32. ' GLOBAL VARIABLES
  33. ' -----------------------------------------------------------------------------
  34. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  35. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  36. Dim Shared m_bDebug: m_bDebug = TRUE
  37.  
  38. ' =============================================================================
  39. ' BEGIN MAIN PROGRAM
  40. ' =============================================================================
  41. Dim in$
  42.  
  43. ' ****************************************************************************************************************************************************************
  44. ' ACTIVATE DEBUGGING WINDOW
  45. If m_bDebug = TRUE Then
  46.     $Console
  47.     _Delay 4
  48.     _Console On
  49.     _Echo "Started " + m_ProgramName$
  50.     _Echo "Debugging on..."
  51. ' ****************************************************************************************************************************************************************
  52.  
  53. ' -----------------------------------------------------------------------------
  54. ' START THE MENU
  55. main
  56.  
  57. ' -----------------------------------------------------------------------------
  58. ' DONE
  59. Print m_ProgramName$ + " finished."
  60. 'Screen 0
  61. Input "Press <ENTER> to continue", in$
  62.  
  63. ' ****************************************************************************************************************************************************************
  64. ' DEACTIVATE DEBUGGING WINDOW
  65. If m_bDebug = TRUE Then
  66. ' ****************************************************************************************************************************************************************
  67.  
  68. ' -----------------------------------------------------------------------------
  69. ' EXIT
  70. System ' return control to the operating system
  71.  
  72. ' =============================================================================
  73. ' END MAIN PROGRAM
  74. ' =============================================================================
  75.  
  76. ' /////////////////////////////////////////////////////////////////////////////
  77. ' MAIN MENU
  78.  
  79. Sub main
  80.     Dim RoutineName As String: RoutineName = "main"
  81.     Dim in$
  82.  
  83.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  84.     Do
  85.         Cls
  86.         Print m_ProgramName$
  87.         Print
  88.         Print "Some basic 2D plotting"
  89.         Print
  90.         Print " 1. PlotPointTest"
  91.         Print " 2. PlotSquareTest"
  92.         Print " 3. PlotCircleTest"
  93.         Print " 4. PlotCircleTopLeftTest"
  94.         Print " 5. PlotSemicircleTest"
  95.         Print " 6. CircleFillTest"
  96.         Print " 7. CircleFillTopLeftTest"
  97.         Print " 8. SemiCircleFillTest"
  98.         Print " 9. EllipseTest"
  99.         Print "10. EllipseFillTest"
  100.         Print "11. PlotLineTest"
  101.         Print "12. ShearRotate1Test1"
  102.         Print "13. ShearRotate1Test2 (auto advances 0-360 degrees)"
  103.         Print "14. ShearRotate1Test2 (auto advances 0-360 degrees) (uses Petr's text)"
  104.         Print "15. ShearRotate2Test1 (correct for missing points logic v1)"
  105.         Print "16. ShearRotate2Test1 (correct for missing points logic v1) (uses Petr's text)"
  106.         Print "17. ShearRotate3Test1 (correct for missing points logic v2)"
  107.         Print "18. ShearRotate3Test1 (correct for missing points logic v2) (uses Petr's text)"
  108.         Print "19. ShearRotate4Test1 (correct for missing points logic v3)"
  109.         Print "20. ShearRotate4Test1 (correct for missing points logic v3) (uses Petr's text)"
  110.         Print "21. ShearRotate5Test1 (correct for missing points, STxAxTIC logic)"
  111.         Print "22. ShearRotate5Test1 (correct for missing points, STxAxTIC logic) (uses Petr's text)"
  112.         Print "23. GetRotationMaskTest"
  113.         Print
  114.         Print "What to do? ('q' to exit)"
  115.  
  116.         Input in$: in$ = LCase$(_Trim$(in$))
  117.  
  118.         If in$ = "1" Then
  119.             PlotPointTest
  120.         ElseIf in$ = "2" Then
  121.             PlotSquareTest
  122.         ElseIf in$ = "3" Then
  123.             PlotCircleTest
  124.         ElseIf in$ = "4" Then
  125.             PlotCircleTopLeftTest
  126.         ElseIf in$ = "5" Then
  127.             PlotSemicircleTest
  128.         ElseIf in$ = "6" Then
  129.             CircleFillTest
  130.         ElseIf in$ = "7" Then
  131.             CircleFillTopLeftTest
  132.         ElseIf in$ = "8" Then
  133.             SemiCircleFillTest
  134.         ElseIf in$ = "9" Then
  135.             EllipseTest
  136.         ElseIf in$ = "10" Then
  137.             EllipseFillTest
  138.         ElseIf in$ = "11" Then
  139.             PlotLineTest
  140.         ElseIf in$ = "12" Then
  141.             ShearRotate1Test1
  142.         ElseIf in$ = "13" Then
  143.             ShearRotate1Test2 TestSprite1$
  144.         ElseIf in$ = "14" Then
  145.             ShearRotate1Test2 PetrText1$
  146.         ElseIf in$ = "15" Then
  147.             ShearRotate2Test1 TestSprite1$
  148.         ElseIf in$ = "16" Then
  149.             ShearRotate2Test1 PetrText1$
  150.         ElseIf in$ = "17" Then
  151.             ShearRotate3Test1 TestSprite1$
  152.         ElseIf in$ = "18" Then
  153.             ShearRotate3Test1 PetrText1$
  154.         ElseIf in$ = "19" Then
  155.             ShearRotate4Test1 TestSprite1$
  156.         ElseIf in$ = "20" Then
  157.             ShearRotate4Test1 PetrText1$
  158.         ElseIf in$ = "21" Then
  159.             ShearRotate5Test1 TestSprite1$
  160.         ElseIf in$ = "22" Then
  161.             ShearRotate5Test1 PetrText1$
  162.         ElseIf in$ = "23" Then
  163.             GetRotationMaskTest
  164.         End If
  165.     Loop Until in$ = "q"
  166. End Sub ' main
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.  
  177.  
  178. ' /////////////////////////////////////////////////////////////////////////////
  179. ' MyArray(1 To 32, 1 To 32) AS STRING
  180. ' where index is MyArray(Y, X)
  181.  
  182. Sub PlotPoint (X As Integer, Y As Integer, S As String, MyArray() As String)
  183.     _Echo "PlotPoint X=" + cstr$(X) + ", Y=" + cstr$(Y) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
  184.     If (X >= LBound(MyArray, 2)) Then
  185.         If (X <= UBound(MyArray, 2)) Then
  186.             If (Y >= LBound(MyArray, 1)) Then
  187.                 If (Y <= UBound(MyArray, 1)) Then
  188.                     If Len(S) = 1 Then
  189.                         MyArray(Y, X) = S
  190.                     Else
  191.                         If Len(S) > 1 Then
  192.                             MyArray(Y, X) = Left$(S, 1)
  193.                         End If
  194.                     End If
  195.                 End If
  196.             End If
  197.         End If
  198.     End If
  199. End Sub ' PlotPoint
  200.  
  201. ' /////////////////////////////////////////////////////////////////////////////
  202.  
  203. Sub PlotPointTest
  204.     Dim MyArray(1 To 32, 1 To 32) As String
  205.     Dim iX As Integer
  206.     Dim iY As Integer
  207.     Dim in$
  208.     Dim X As Integer
  209.     Dim Y As Integer
  210.     Dim L As Integer
  211.     Dim iChar As Integer
  212.  
  213.     ClearArray MyArray(), "."
  214.     iChar = 64
  215.  
  216.     Cls
  217.     Print "Plot a point."
  218.     Print ArrayToStringTest(MyArray())
  219.     Print
  220.  
  221.     Do
  222.         Print "Type x,y (1-32, 1-32) coordinate to plot point at."
  223.         Input "X,Y OR 0 TO QUIT? "; X, Y
  224.         If X > 0 And Y > 0 Then
  225.             iChar = iChar + 1
  226.             If iChar > 90 Then iChar = 65
  227.  
  228.             Print "X=" + cstr$(X) + ", Y=" + cstr$(Y)
  229.             PlotPoint X, Y, Chr$(iChar), MyArray()
  230.  
  231.             Print "Current point plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  232.             Print ArrayToStringTest(MyArray())
  233.             Print
  234.  
  235.         Else
  236.             Exit Do
  237.         End If
  238.     Loop
  239. End Sub ' PlotPointTest
  240.  
  241. ' /////////////////////////////////////////////////////////////////////////////
  242.  
  243. Sub PlotSquare (X1 As Integer, Y1 As Integer, L As Integer, S As String, MyArray() As String)
  244.     Dim X As Integer
  245.     Dim X2 As Integer
  246.     Dim Y As Integer
  247.     Dim Y2 As Integer
  248.     Dim sChar$
  249.  
  250.     If Len(S) = 1 Then
  251.         sChar$ = S
  252.     Else
  253.         If Len(S) = 0 Then
  254.             sChar$ = " "
  255.         Else
  256.             sChar$ = Left$(S, 1)
  257.         End If
  258.     End If
  259.  
  260.     X2 = (X1 + L) - 1
  261.     Y2 = (Y1 + L) - 1
  262.     For X = X1 To X2
  263.         For Y = Y1 To Y2
  264.             PlotPoint X, Y, sChar$, MyArray()
  265.         Next Y
  266.     Next X
  267. End Sub ' PlotSquare
  268.  
  269. ' /////////////////////////////////////////////////////////////////////////////
  270.  
  271. Sub PlotSquareTest
  272.     Dim MyArray(1 To 32, 1 To 32) As String
  273.     Dim iX As Integer
  274.     Dim iY As Integer
  275.     Dim in$
  276.     Dim X As Integer
  277.     Dim Y As Integer
  278.     Dim L As Integer
  279.     Dim iChar As Integer
  280.  
  281.     ClearArray MyArray(), "."
  282.     iChar = 64
  283.  
  284.     Cls
  285.     Print "Enter parameters to draw a square."
  286.     Print ArrayToStringTest(MyArray())
  287.     Print
  288.     Do
  289.         Print "Type top left x,y (1-32, 1-32) coordinate to plot square,"
  290.         Print "and size (1-32) of square."
  291.         Input "X,Y,L OR 0 TO QUIT? "; X, Y, L
  292.         If X > 0 And Y > 0 And L > 0 Then
  293.             iChar = iChar + 1
  294.             If iChar > 90 Then iChar = 65
  295.  
  296.             Print
  297.             Print "X=" + cstr$(X)
  298.             Print "Y=" + cstr$(Y)
  299.             Print "L=" + cstr$(L)
  300.             Print
  301.             PlotSquare X, Y, L, Chr$(iChar), MyArray()
  302.  
  303.             Print "Square plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  304.             Print ArrayToStringTest(MyArray())
  305.             Print
  306.         Else
  307.             Exit Do
  308.         End If
  309.     Loop
  310. End Sub ' PlotSquareTest
  311.  
  312. ' /////////////////////////////////////////////////////////////////////////////
  313. ' Fast circle drawing in pure Atari BASIC#
  314. ' https://atariwiki.org/wiki/Wiki.jsp?page=Super%20fast%20circle%20routine
  315.  
  316. ' * Magazine: Moj Mikro, 1989/3
  317. ' * Author : Zlatko Bleha
  318. ' * Page : 27 - 31
  319. ' * Atari BASIC listing on disk (tokenized): M8903282.BAS
  320. ' * Atari BASIC listing (listed): M8903282.LST
  321.  
  322. ' Next example is demonstration of implementing mentioned circle algorithm
  323. ' in pure Atari BASIC. This program shows how much faster it is compared to
  324. ' classic program using sine and cosine functions from Atari BASIC
  325. ' (shown in last example).
  326.  
  327. ' Basic Listing M8903282.LST#
  328. '1 REM *******************************
  329. '2 REM PROGRAM  : FAST CIRCLE DRAWING
  330. '3 REM AUTHOR   : ZLATKO BLEHA
  331. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  332. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  333. '6 REM *******************************
  334. '7 REM
  335. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  336. '20 PRINT "ENTER X, Y AND R"
  337. '30 INPUT X,Y,R
  338. '40 IF R=0 THEN PLOT X,Y:END
  339. '50 B=R:C=0:A=R-1
  340. '60 PLOT X+C,Y+B
  341. '70 PLOT X+C,Y-B
  342. '80 PLOT X-C,Y-B
  343. '90 PLOT X-C,Y+B
  344. '100 PLOT X+B,Y+C
  345. '110 PLOT X+B,Y-C
  346. '120 PLOT X-B,Y-C
  347. '130 PLOT X-B,Y+C
  348. '140 C=C+1
  349. '150 A=A+1-C-C
  350. '160 IF A>=0 THEN 190
  351. '170 B=B-1
  352. '180 A=A+B+B
  353. '190 IF B>=C THEN 60
  354.  
  355. ' Use some valid values for coordinates and radius, for example:
  356. ' X=40, Y=40, R=30
  357. ' X=130, Y=90, R=60
  358. ' Slow circle drawing in Atari BASIC#
  359. ' * Magazine: Moj Mikro, 1989/3
  360. ' * Author : Zlatko Bleha
  361. ' * Page : 27 - 31
  362. ' * Atari BASIC listing on disk (tokenized): M8903281.BAS
  363. ' * Atari BASIC listing (listed): M8903281.LST
  364.  
  365. ' This is classic example for drawing circles from Atari BASIC
  366. ' using sine and cosine functions. Unfortunatelly, this is very slow
  367. ' way of doing it and not recommended.
  368. ' Just use routine shown above and everybody will be happy
  369.  
  370. ' Basic Listing M8903281.LST#
  371. '1 REM *******************************
  372. '2 REM PROGRAM  : SLOW CIRCLE DRAWING
  373. '3 REM AUTHOR   : ZLATKO BLEHA
  374. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  375. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  376. '6 REM *******************************
  377. '7 REM
  378. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  379. '20 FOR A=0 TO 6.28 STEP 0.02
  380. '30 X=SIN(A)*50+150
  381. '40 Y=COS(A)*50+80
  382. '50 PLOT X,Y
  383. '60 NEXT A
  384.  
  385. ' Conclusion#
  386. ' Returning back to first program with the fastest way of drawing circles...
  387. ' There is one more thing to note. In case you want to use PLOT subroutine,
  388. ' which is part of the main circle routine, then read following explanation.
  389. ' PLOT routine is written so it can be used easily from Atari BASIC program
  390. ' independently from main circle routine, by using like this:
  391. ' A=USR(30179,POK,X,Y)
  392. '
  393. ' POK   1 (drawing a pixel), 0 (erasing a pixel)
  394. ' X     X coordinate of the pixel
  395. ' Y     Y coordinate of the pixel
  396. '
  397. ' The routine alone is not any faster than normal PLOT command
  398. ' from Atari BASIC, because USR command takes approximately 75%
  399. ' of whole execution. But, used as part of the main circle routine
  400. ' it does not matter anymore, because it is integrated in one larger
  401. ' entity. There the execution is very fast, with no overhead.
  402. ' PLOT routine is here for you to examine anyway.
  403. ' You never know if you will maybe need it in the future.
  404.  
  405. ' More on plotting circles:
  406. '     Drawing a circle in BASIC - fast
  407. '     https://www.cpcwiki.eu/forum/programming/drawing-a-circle-in-basic-fast/
  408.  
  409. ' X,Y     = center point of circle
  410. ' R       = radius
  411. ' S       = char to draw
  412. ' MyArray = 2D string array to plot circle in
  413.  
  414. Sub PlotCircle (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  415.     Dim A As Integer
  416.     Dim B As Integer
  417.     Dim C As Integer
  418.     Dim S2 As String
  419.  
  420.     If Len(S) = 1 Then
  421.         S2 = S
  422.     Else
  423.         If Len(S) = 0 Then
  424.             S2 = " "
  425.         Else
  426.             S2 = Left$(S, 1)
  427.         End If
  428.     End If
  429.  
  430.     If R > 0 Then
  431.         B = R
  432.         C = 0
  433.         A = R - 1
  434.         Do
  435.             PlotPoint X + C, Y + B, S2, MyArray()
  436.             PlotPoint X + C, Y - B, S2, MyArray()
  437.             PlotPoint X - C, Y - B, S2, MyArray()
  438.             PlotPoint X - C, Y + B, S2, MyArray()
  439.             PlotPoint X + B, Y + C, S2, MyArray()
  440.             PlotPoint X + B, Y - C, S2, MyArray()
  441.             PlotPoint X - B, Y - C, S2, MyArray()
  442.             PlotPoint X - B, Y + C, S2, MyArray()
  443.             C = C + 1
  444.             A = A + 1 - C - C
  445.             If A < 0 Then ' IF A>=0 THEN 190
  446.                 B = B - 1
  447.                 A = A + B + B
  448.             End If
  449.             If B < C Then Exit Do ' 190 IF B>=C THEN 60
  450.         Loop
  451.     End If
  452. End Sub ' PlotCircle
  453.  
  454. ' /////////////////////////////////////////////////////////////////////////////
  455.  
  456. Sub PlotCircleTest
  457.     Dim MyArray(1 To 32, 1 To 32) As String
  458.     Dim iX As Integer
  459.     Dim iY As Integer
  460.     Dim in$
  461.     Dim X As Integer
  462.     Dim Y As Integer
  463.     Dim R As Integer
  464.     Dim iChar As Integer
  465.  
  466.     ClearArray MyArray(), "."
  467.     iChar = 64
  468.  
  469.     Cls
  470.     Print "Plot a raster circle"
  471.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  472.     Print
  473.     Print "Enter parameters to draw a circle."
  474.     Print ArrayToStringTest(MyArray())
  475.     Print
  476.  
  477.     Do
  478.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  479.         Print "and radius (1-32) of circle."
  480.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  481.         If X > 0 And Y > 0 And R > 0 Then
  482.             iChar = iChar + 1
  483.             If iChar > 90 Then iChar = 65
  484.  
  485.             Print "X=" + cstr$(X)
  486.             Print "Y=" + cstr$(Y)
  487.             Print "R=" + cstr$(R)
  488.  
  489.             PlotCircle X, Y, R, Chr$(iChar), MyArray()
  490.  
  491.             Print "Circle plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  492.             Print ArrayToStringTest(MyArray())
  493.             Print
  494.         Else
  495.             Exit Do
  496.         End If
  497.     Loop
  498.  
  499. End Sub ' PlotCircleTest
  500.  
  501. ' /////////////////////////////////////////////////////////////////////////////
  502. ' X,Y     = top left point of circle
  503. ' R       = radius
  504. ' S       = char to draw
  505. ' MyArray = 2D string array to plot circle in
  506.  
  507. Sub PlotCircleTopLeft (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  508.     Dim RoutineName As String: RoutineName = "PlotCircleTopLeft"
  509.     Dim A As Integer
  510.     Dim B As Integer
  511.     Dim C As Integer
  512.     Dim S2 As String
  513.     Dim W As Integer
  514.     ReDim arrTemp(0, 0) As String
  515.     Dim DY As Integer
  516.     Dim DX As Integer
  517.     Dim TX As Integer
  518.     Dim TY As Integer
  519.     Dim MinY As Integer
  520.     Dim MaxY As Integer
  521.     Dim MinX As Integer
  522.     Dim MaxX As Integer
  523.  
  524.     ' Get total width
  525.     W = (R * 2) + 1
  526.  
  527.     ' Define a temp array
  528.     ReDim arrTemp(0 To W, 0 To W) As String
  529.  
  530.     ' Get minimum X, Y of target array
  531.     MinY = LBound(MyArray, 1)
  532.     MaxY = UBound(MyArray, 1)
  533.     MinX = LBound(MyArray, 2)
  534.     MaxX = UBound(MyArray, 2)
  535.  
  536.     If Len(S) = 1 Then
  537.         S2 = S
  538.     Else
  539.         If Len(S) = 0 Then
  540.             S2 = " "
  541.         Else
  542.             S2 = Left$(S, 1)
  543.         End If
  544.     End If
  545.  
  546.     If R > 0 Then
  547.         ' Draw circle to temporary array
  548.         B = R
  549.         C = 0
  550.         A = R - 1
  551.         Do
  552.             ' PORTIONS OF CIRCLE:
  553.             ' .......3333222.......
  554.             ' .....33.......22.....
  555.             ' ....3...........2....
  556.             ' ...7.............6...
  557.             ' ..7...............6..
  558.             ' .7.................6.
  559.             ' .7.................6.
  560.             ' 7...................6
  561.             ' 7...................6
  562.             ' 7...................6
  563.             ' 8...................6
  564.             ' 8...................5
  565.             ' 8...................5
  566.             ' 8...................5
  567.             ' .8.................5.
  568.             ' .8.................5.
  569.             ' ..8...............5..
  570.             ' ...8.............5...
  571.             ' ....4...........1....
  572.             ' .....44.......11.....
  573.             ' .......4444111.......
  574.             PlotPoint R + C, R + B, S2, arrTemp() ' 1
  575.             PlotPoint R + C, R - B, S2, arrTemp() ' 2
  576.             PlotPoint R - C, R - B, S2, arrTemp() ' 3
  577.             PlotPoint R - C, R + B, S2, arrTemp() ' 4
  578.             PlotPoint R + B, R + C, S2, arrTemp() ' 5
  579.             PlotPoint R + B, R - C, S2, arrTemp() ' 6
  580.             PlotPoint R - B, R - C, S2, arrTemp() ' 7
  581.             PlotPoint R - B, R + C, S2, arrTemp() ' 8
  582.             C = C + 1
  583.             A = A + 1 - C - C
  584.             If A < 0 Then
  585.                 B = B - 1
  586.                 A = A + B + B
  587.             End If
  588.             If B < C Then Exit Do
  589.         Loop
  590.  
  591.         ' Copy circle to destination Y,X
  592.         For DY = LBound(arrTemp, 1) To UBound(arrTemp, 1)
  593.             For DX = LBound(arrTemp, 2) To UBound(arrTemp, 2)
  594.                 If Len(arrTemp(DY, DX)) > 0 Then
  595.                     TY = Y + DY
  596.                     If TY >= MinY Then
  597.                         If TY <= MaxY Then
  598.                             TX = X + DX
  599.                             If TX >= MinX Then
  600.                                 If TX <= MaxX Then
  601.                                     MyArray(TY, TX) = arrTemp(DY, DX)
  602.                                 End If
  603.                             End If
  604.                         End If
  605.                     End If
  606.  
  607.                 End If
  608.             Next DX
  609.         Next DY
  610.     End If
  611. End Sub ' PlotCircleTopLeft
  612.  
  613. ' /////////////////////////////////////////////////////////////////////////////
  614.  
  615. Sub PlotCircleTopLeftTest
  616.     Dim MyArray(1 To 32, 1 To 32) As String
  617.     Dim iX As Integer
  618.     Dim iY As Integer
  619.     Dim in$
  620.     Dim X As Integer
  621.     Dim Y As Integer
  622.     Dim R As Integer
  623.     Dim iChar As Integer
  624.  
  625.     ClearArray MyArray(), "."
  626.     iChar = 64
  627.  
  628.     Cls
  629.     Print "Plot a raster circle, specifying top left x,y position"
  630.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  631.     Print
  632.     Print "Enter parameters to draw a circle."
  633.     Print ArrayToStringTest(MyArray())
  634.     Print
  635.  
  636.     Do
  637.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot circle,"
  638.         Print "and radius (1-32) of circle."
  639.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  640.         If X > 0 And Y > 0 And R > 0 Then
  641.             iChar = iChar + 1
  642.             If iChar > 90 Then iChar = 65
  643.  
  644.             Print "X=" + cstr$(X)
  645.             Print "Y=" + cstr$(Y)
  646.             Print "R=" + cstr$(R)
  647.  
  648.             PlotCircleTopLeft X, Y, R, Chr$(iChar), MyArray()
  649.  
  650.             Print "Circle plotted (from top left), drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  651.             Print ArrayToStringTest(MyArray())
  652.             Print
  653.         Else
  654.             Exit Do
  655.         End If
  656.     Loop
  657.  
  658. End Sub ' PlotCircleTopLeftTest
  659.  
  660. ' /////////////////////////////////////////////////////////////////////////////
  661. ' Based on PlotCircleTopLeft.
  662.  
  663. ' X,Y     = top left point of circle
  664. ' R       = radius
  665. ' Q       = which quarter of the circle to return
  666. '           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
  667. '           like this:
  668. ' .......4444111.......
  669. ' .....44.......11.....
  670. ' ....4...........1....
  671. ' ...4.............1...
  672. ' ..4...............1..
  673. ' .4.................1.
  674. ' .4.................1.
  675. ' 4...................1
  676. ' 4...................1
  677. ' 4...................1
  678. ' 3...................1
  679. ' 3...................2
  680. ' 3...................2
  681. ' 3...................2
  682. ' .3.................2.
  683. ' .3.................2.
  684. ' ..3...............2..
  685. ' ...3.............2...
  686. ' ....3...........2....
  687. ' .....33.......22.....
  688. ' .......3333222.......
  689. ' S       = char to draw
  690. ' MyArray = 2D string array to plot circle in
  691.  
  692. Sub PlotSemicircle (X As Integer, Y As Integer, R As Integer, Q As Integer, S As String, MyArray() As String)
  693.     Dim RoutineName As String: RoutineName = "PlotCircleTopLeft"
  694.     Dim A As Integer
  695.     Dim B As Integer
  696.     Dim C As Integer
  697.     Dim S2 As String
  698.     Dim W As Integer
  699.     ReDim arrTemp(0, 0) As String
  700.     Dim DY As Integer
  701.     Dim DX As Integer
  702.     Dim TX As Integer
  703.     Dim TY As Integer
  704.     Dim MinY As Integer
  705.     Dim MaxY As Integer
  706.     Dim MinX As Integer
  707.     Dim MaxX As Integer
  708.  
  709.     ' Get total width
  710.     W = (R * 2) + 1
  711.  
  712.     ' Define a temp array
  713.     ReDim arrTemp(0 To W, 0 To W) As String
  714.  
  715.     ' Get minimum X, Y of target array
  716.     MinY = LBound(MyArray, 1)
  717.     MaxY = UBound(MyArray, 1)
  718.     MinX = LBound(MyArray, 2)
  719.     MaxX = UBound(MyArray, 2)
  720.  
  721.     If Len(S) = 1 Then
  722.         S2 = S
  723.     Else
  724.         If Len(S) = 0 Then
  725.             S2 = " "
  726.         Else
  727.             S2 = Left$(S, 1)
  728.         End If
  729.     End If
  730.  
  731.     If R > 0 Then
  732.         ' Draw circle to temporary array
  733.         B = R
  734.         C = 0
  735.         A = R - 1
  736.         Do
  737.             ' PORTIONS OF CIRCLE:
  738.             ' .......3333222.......
  739.             ' .....33.......22.....
  740.             ' ....3...........2....
  741.             ' ...7.............6...
  742.             ' ..7...............6..
  743.             ' .7.................6.
  744.             ' .7.................6.
  745.             ' 7...................6
  746.             ' 7...................6
  747.             ' 7...................6
  748.             ' 8...................6
  749.             ' 8...................5
  750.             ' 8...................5
  751.             ' 8...................5
  752.             ' .8.................5.
  753.             ' .8.................5.
  754.             ' ..8...............5..
  755.             ' ...8.............5...
  756.             ' ....4...........1....
  757.             ' .....44.......11.....
  758.             ' .......4444111.......
  759.  
  760.             ' JUST PLOT SELECTED QUADRANT:
  761.             Select Case Q
  762.                 Case 1:
  763.                     ' quadrant #1
  764.                     PlotPoint C, R - B, S2, arrTemp() ' 2
  765.                     PlotPoint B, R - C, S2, arrTemp() ' 6
  766.                 Case 2:
  767.                     ' quadrant #2
  768.                     PlotPoint B, C, S2, arrTemp() ' 5
  769.                     PlotPoint C, B, S2, arrTemp() ' 1
  770.                 Case 3:
  771.                     ' quadrant #3
  772.                     PlotPoint R - C, B, S2, arrTemp() ' 4
  773.                     PlotPoint R - B, C, S2, arrTemp() ' 8
  774.                 Case 4:
  775.                     ' quadrant #4
  776.                     PlotPoint R - B, R - C, S2, arrTemp() ' 7
  777.                     PlotPoint R - C, R - B, S2, arrTemp() ' 3
  778.                 Case Else:
  779.                     ' (DO NOTHING)
  780.             End Select
  781.  
  782.             '' PLOT CIRCLE:
  783.             '' quadrant #1
  784.             'PlotPoint R + C, R - B, S2, arrTemp() ' 2
  785.             'PlotPoint R + B, R - C, S2, arrTemp() ' 6
  786.             '
  787.             '' quadrant #2
  788.             'PlotPoint R + B, R + C, S2, arrTemp() ' 5
  789.             'PlotPoint R + C, R + B, S2, arrTemp() ' 1
  790.             '
  791.             '' quadrant #3
  792.             'PlotPoint R - C, R + B, S2, arrTemp() ' 4
  793.             'PlotPoint R - B, R + C, S2, arrTemp() ' 8
  794.             '
  795.             '' quadrant #4
  796.             'PlotPoint R - B, R - C, S2, arrTemp() ' 7
  797.             'PlotPoint R - C, R - B, S2, arrTemp() ' 3
  798.  
  799.             C = C + 1
  800.             A = A + 1 - C - C
  801.             If A < 0 Then
  802.                 B = B - 1
  803.                 A = A + B + B
  804.             End If
  805.             If B < C Then Exit Do
  806.         Loop
  807.  
  808.         ' Copy semicircle to destination Y,X
  809.         For DY = LBound(arrTemp, 1) To UBound(arrTemp, 1)
  810.             For DX = LBound(arrTemp, 2) To UBound(arrTemp, 2)
  811.                 If Len(arrTemp(DY, DX)) > 0 Then
  812.                     TY = Y + DY
  813.                     If TY >= MinY Then
  814.                         If TY <= MaxY Then
  815.                             TX = X + DX
  816.                             If TX >= MinX Then
  817.                                 If TX <= MaxX Then
  818.                                     MyArray(TY, TX) = arrTemp(DY, DX)
  819.                                 End If
  820.                             End If
  821.                         End If
  822.                     End If
  823.                 End If
  824.             Next DX
  825.         Next DY
  826.     End If
  827. End Sub ' PlotSemicircle
  828.  
  829. ' /////////////////////////////////////////////////////////////////////////////
  830.  
  831. Sub PlotSemicircleTest
  832.     Dim MyArray(1 To 32, 1 To 32) As String
  833.     Dim iX As Integer
  834.     Dim iY As Integer
  835.     Dim in$
  836.     Dim X As Integer
  837.     Dim Y As Integer
  838.     Dim R As Integer
  839.     Dim Q As Integer
  840.     Dim iChar As Integer
  841.  
  842.     ClearArray MyArray(), "."
  843.     iChar = 64
  844.  
  845.     Cls
  846.     Print "Plot a semicircle"
  847.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  848.     Print
  849.     Print "Enter parameters to draw a semicircle."
  850.     Print ArrayToStringTest(MyArray())
  851.     Print
  852.  
  853.     Do
  854.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot semicircle,"
  855.         Print "radius (1-32) of semicircle, and quadrant of circle to use:"
  856.         Print "41"
  857.         Print "32"
  858.         Input "X,Y,R,Q OR 0 TO QUIT: "; X, Y, R, Q
  859.         If X > 0 And Y > 0 And R > 0 Then
  860.             iChar = iChar + 1
  861.             If iChar > 90 Then iChar = 65
  862.  
  863.             Print "X=" + cstr$(X)
  864.             Print "Y=" + cstr$(Y)
  865.             Print "R=" + cstr$(R)
  866.  
  867.             PlotSemicircle X, Y, R, Q, Chr$(iChar), MyArray()
  868.  
  869.             Print "Semicircle plotted (from top left), drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  870.             Print ArrayToStringTest(MyArray())
  871.             Print
  872.         Else
  873.             Exit Do
  874.         End If
  875.     Loop
  876.  
  877. End Sub ' PlotSemicircleTest
  878.  
  879. ' /////////////////////////////////////////////////////////////////////////////
  880. ' Re: Is this fast enough as general circle fill?
  881. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg1913#msg1913
  882.  
  883. ' From: SMcNeill
  884. ' Date: « Reply #30 on: June 26, 2018, 03:34:18 pm »
  885. '
  886. ' Sometimes, computers do things that are completely counter-intuitive to us, and
  887. ' we find ourselves having to step back as programmers and simply say, "WOW!!"
  888. ' Here's a perfect example of that:
  889. ' Here we look at two different circle fill routines -- one, which I'd assume to
  890. ' be faster, which precalculates the offset needed to find the endpoints for each
  891. ' line which composes a circle, and another, which is the same old CircleFill
  892. ' program which I've shared countless times over the years with people on various
  893. ' QB64 forums.
  894. '
  895. ' When all is said and done though, CircleFill is STILL even faster than
  896. ' CircleFillFast, which pregenerates those end-points for us!
  897.  
  898. ' CX,CY     = center point of circle
  899. ' R         = radius
  900. ' S         = char to draw
  901. ' MyArray = 2D string array to plot circle in
  902.  
  903. Sub CircleFill (CX As Integer, CY As Integer, R As Integer, S As String, MyArray() As String)
  904.     Dim Radius As Integer
  905.     Dim RadiusError As Integer
  906.     Dim X As Integer
  907.     Dim Y As Integer
  908.     Dim iLoopX As Integer
  909.     Dim iLoopY As Integer
  910.  
  911.     Radius = Abs(R)
  912.     RadiusError = -Radius
  913.     X = Radius
  914.     Y = 0
  915.  
  916.     If Radius = 0 Then
  917.         'PSET (CX, CY), C
  918.         'PlotPoint CX, CY, S, MyArray()
  919.         Exit Sub
  920.     End If
  921.  
  922.     ' Draw the middle span here so we don't draw it twice in the main loop,
  923.     ' which would be a problem with blending turned on.
  924.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  925.     For iLoopX = CX - X To CX + X
  926.         PlotPoint iLoopX, CY, S, MyArray()
  927.     Next iLoopX
  928.  
  929.     While X > Y
  930.         RadiusError = RadiusError + Y * 2 + 1
  931.         If RadiusError >= 0 Then
  932.             If X <> Y + 1 Then
  933.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  934.                 iLoopY = CY - X
  935.                 For iLoopX = CX - Y To CX + Y
  936.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  937.                 Next iLoopX
  938.  
  939.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  940.                 iLoopY = CY + X
  941.                 For iLoopX = CX - Y To CX + Y
  942.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  943.                 Next iLoopX
  944.             End If
  945.             X = X - 1
  946.             RadiusError = RadiusError - X * 2
  947.         End If
  948.         Y = Y + 1
  949.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  950.         iLoopY = CY - Y
  951.         For iLoopX = CX - X To CX + X
  952.             PlotPoint iLoopX, iLoopY, S, MyArray()
  953.         Next iLoopX
  954.  
  955.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  956.         iLoopY = CY + Y
  957.         For iLoopX = CX - X To CX + X
  958.             PlotPoint iLoopX, iLoopY, S, MyArray()
  959.         Next iLoopX
  960.     Wend
  961. End Sub ' CircleFill
  962.  
  963. ' /////////////////////////////////////////////////////////////////////////////
  964.  
  965. Sub CircleFillTest
  966.     Dim MyArray(1 To 32, 1 To 32) As String
  967.     Dim iX As Integer
  968.     Dim iY As Integer
  969.     Dim in$
  970.     Dim X As Integer
  971.     Dim Y As Integer
  972.     Dim R As Integer
  973.     Dim iChar As Integer
  974.  
  975.     ClearArray MyArray(), "."
  976.     iChar = 64
  977.  
  978.     Cls
  979.     Print "Plot a filled circle"
  980.     Print "Based on CircleFill by SMcNeill."
  981.     Print
  982.     Print "Enter parameters to draw a circle."
  983.     Print ArrayToStringTest(MyArray())
  984.     Print
  985.  
  986.     Do
  987.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  988.         Print "and radius (1-32) of circle."
  989.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  990.         If X > 0 And Y > 0 And R > 0 Then
  991.             iChar = iChar + 1
  992.             If iChar > 90 Then iChar = 65
  993.  
  994.             Print "X=" + cstr$(X)
  995.             Print "Y=" + cstr$(Y)
  996.             Print "R=" + cstr$(R)
  997.  
  998.             'PlotCircle X, Y, R, Chr$(iChar), MyArray()
  999.             CircleFill X, Y, R, Chr$(iChar), MyArray()
  1000.  
  1001.             Print "Circle plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1002.             Print ArrayToStringTest(MyArray())
  1003.             Print
  1004.         Else
  1005.             Exit Do
  1006.         End If
  1007.     Loop
  1008.  
  1009. End Sub ' CircleFillTest
  1010.  
  1011. ' /////////////////////////////////////////////////////////////////////////////
  1012. ' Based on CircleFill and PlotCircleTopLeft.
  1013. ' CX,CY     = top left point of circle
  1014. ' R         = radius
  1015. ' S         = char to draw
  1016. ' MyArray = 2D string array to plot circle in
  1017.  
  1018. Sub CircleFillTopLeft (CX As Integer, CY As Integer, R As Integer, S As String, MyArray() As String)
  1019.     Dim Radius As Integer
  1020.     Dim RadiusError As Integer
  1021.     Dim X As Integer
  1022.     Dim Y As Integer
  1023.     Dim iLoopX As Integer
  1024.     Dim iLoopY As Integer
  1025.     ReDim arrTemp(0, 0) As String
  1026.     Dim DY As Integer
  1027.     Dim DX As Integer
  1028.     Dim W As Integer
  1029.     Dim TX As Integer
  1030.     Dim TY As Integer
  1031.     Dim MinY As Integer
  1032.     Dim MaxY As Integer
  1033.     Dim MinX As Integer
  1034.     Dim MaxX As Integer
  1035.  
  1036.     Radius = Abs(R)
  1037.     RadiusError = -Radius
  1038.     X = Radius
  1039.     Y = 0
  1040.  
  1041.     If Radius = 0 Then
  1042.         'PSET (CX, CY), C
  1043.         'PlotPoint CX, CY, S, MyArray()
  1044.         Exit Sub
  1045.     End If
  1046.  
  1047.     ' Get total width
  1048.     W = (Radius * 2) + 1
  1049.  
  1050.     ' Define a temp array
  1051.     ReDim arrTemp(0 To W, 0 To W) As String
  1052.  
  1053.     ' Get minimum X, Y of target array
  1054.     MinY = LBound(MyArray, 1)
  1055.     MaxY = UBound(MyArray, 1)
  1056.     MinX = LBound(MyArray, 2)
  1057.     MaxX = UBound(MyArray, 2)
  1058.  
  1059.     ' Draw the middle span here so we don't draw it twice in the main loop,
  1060.     ' which would be a problem with blending turned on.
  1061.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  1062.     'FOR iLoopX = CX - X TO CX + X
  1063.     For iLoopX = R - X To R + X
  1064.         'PlotPoint iLoopX, CY, S, MyArray()
  1065.         'PlotPoint iLoopX, CY, S, arrTemp()
  1066.         PlotPoint iLoopX, R, S, arrTemp()
  1067.     Next iLoopX
  1068.  
  1069.     While X > Y
  1070.         RadiusError = RadiusError + Y * 2 + 1
  1071.         If RadiusError >= 0 Then
  1072.             If X <> Y + 1 Then
  1073.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1074.                 'iLoopY = CY - X
  1075.                 iLoopY = R - X
  1076.                 'FOR iLoopX = CX - Y TO CX + Y
  1077.                 For iLoopX = R - Y To R + Y
  1078.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1079.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1080.                 Next iLoopX
  1081.  
  1082.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1083.                 'iLoopY = CY + X
  1084.                 iLoopY = R + X
  1085.                 'FOR iLoopX = CX - Y TO CX + Y
  1086.                 For iLoopX = R - Y To R + Y
  1087.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1088.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1089.                 Next iLoopX
  1090.             End If
  1091.             X = X - 1
  1092.             RadiusError = RadiusError - X * 2
  1093.         End If
  1094.         Y = Y + 1
  1095.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1096.         'iLoopY = CY - Y
  1097.         iLoopY = R - Y
  1098.         'FOR iLoopX = CX - X TO CX + X
  1099.         For iLoopX = R - X To R + X
  1100.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1101.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1102.         Next iLoopX
  1103.  
  1104.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1105.         'iLoopY = CY + Y
  1106.         iLoopY = R + Y
  1107.         'FOR iLoopX = CX - X TO CX + X
  1108.         For iLoopX = R - X To R + X
  1109.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1110.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1111.         Next iLoopX
  1112.     Wend
  1113.  
  1114.     ' Copy circle to destination Y,X
  1115.     For DY = LBound(arrTemp, 1) To UBound(arrTemp, 1)
  1116.         For DX = LBound(arrTemp, 2) To UBound(arrTemp, 2)
  1117.             If Len(arrTemp(DY, DX)) > 0 Then
  1118.                 TY = DY + CY
  1119.                 If TY >= MinY Then
  1120.                     If TY <= MaxY Then
  1121.                         TX = DX + CX
  1122.                         If TX >= MinX Then
  1123.                             If TX <= MaxX Then
  1124.                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1125.                             End If
  1126.                         End If
  1127.                     End If
  1128.                 End If
  1129.             End If
  1130.         Next DX
  1131.     Next DY
  1132.  
  1133. End Sub ' CircleFillTopLeft
  1134.  
  1135. ' /////////////////////////////////////////////////////////////////////////////
  1136.  
  1137. Sub CircleFillTopLeftTest
  1138.     Dim MyArray(1 To 32, 1 To 32) As String
  1139.     Dim iX As Integer
  1140.     Dim iY As Integer
  1141.     Dim in$
  1142.     Dim X As Integer
  1143.     Dim Y As Integer
  1144.     Dim R As Integer
  1145.     Dim iChar As Integer
  1146.  
  1147.     ClearArray MyArray(), "."
  1148.     iChar = 64
  1149.  
  1150.     Cls
  1151.     Print "Plot a solid circle, specifying top left x,y position"
  1152.     Print "Based on CircleFill by SMcNeill."
  1153.     Print
  1154.     Print "Enter parameters to draw a circle."
  1155.     Print ArrayToStringTest(MyArray())
  1156.     Print
  1157.  
  1158.     Do
  1159.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot circle,"
  1160.         Print "and radius (1-32) of circle."
  1161.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  1162.         If X > 0 And Y > 0 And R > 0 Then
  1163.             iChar = iChar + 1
  1164.             If iChar > 90 Then iChar = 65
  1165.  
  1166.             Print "X=" + cstr$(X)
  1167.             Print "Y=" + cstr$(Y)
  1168.             Print "R=" + cstr$(R)
  1169.  
  1170.             CircleFillTopLeft X, Y, R, Chr$(iChar), MyArray()
  1171.  
  1172.             Print "Circle plotted (from top left), drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1173.             Print ArrayToStringTest(MyArray())
  1174.             Print
  1175.         Else
  1176.             Exit Do
  1177.         End If
  1178.     Loop
  1179.  
  1180. End Sub ' CircleFillTopLeftTest
  1181.  
  1182. ' /////////////////////////////////////////////////////////////////////////////
  1183. ' Based on CircleFill and PlotSemiCircle
  1184.  
  1185. ' CX,CY   = top left point of circle
  1186. ' R       = radius
  1187. ' Q       = which quarter of the circle to return semicircle from
  1188. '           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
  1189. '           like this:
  1190. ' .......4444111.......
  1191. ' .....44444411111.....
  1192. ' ....4444444111111....
  1193. ' ...444444441111111...
  1194. ' ..44444444411111111..
  1195. ' .4444444444111111111.
  1196. ' .4444444444111111111.
  1197. ' 444444444441111111111
  1198. ' 444444444441111111111
  1199. ' 444444444441111111111
  1200. ' 333333333331111111111
  1201. ' 333333333332222222222
  1202. ' 333333333332222222222
  1203. ' 333333333332222222222
  1204. ' .3333333333222222222.
  1205. ' .3333333333222222222.
  1206. ' ..33333333322222222..
  1207. ' ...333333332222222...
  1208. ' ....3333333222222....
  1209. ' .....33333322222.....
  1210. ' .......3333222.......
  1211. ' S       = char to draw
  1212. ' MyArray = 2D string array to plot semicircle in
  1213.  
  1214. Sub SemiCircleFill (CX As Integer, CY As Integer, R As Integer, Q As Integer, S As String, MyArray() As String)
  1215.     Dim Radius As Integer
  1216.     Dim RadiusError As Integer
  1217.     Dim X As Integer
  1218.     Dim Y As Integer
  1219.     Dim iLoopX As Integer
  1220.     Dim iLoopY As Integer
  1221.     ReDim arrTemp(0, 0) As String
  1222.     Dim DY As Integer
  1223.     Dim DX As Integer
  1224.     Dim W As Integer
  1225.     Dim AX As Integer
  1226.     Dim AY As Integer
  1227.     Dim TX As Integer
  1228.     Dim TY As Integer
  1229.     Dim MinY As Integer
  1230.     Dim MaxY As Integer
  1231.     Dim MinX As Integer
  1232.     Dim MaxX As Integer
  1233.  
  1234.     Radius = Abs(R)
  1235.     RadiusError = -Radius
  1236.     X = Radius
  1237.     Y = 0
  1238.  
  1239.     If Radius = 0 Then
  1240.         'PSET (CX, CY), C
  1241.         'PlotPoint CX, CY, S, MyArray()
  1242.         Exit Sub
  1243.     End If
  1244.  
  1245.     ' Get total width
  1246.     W = (Radius * 2) + 1
  1247.  
  1248.     ' Define a temp array
  1249.     ReDim arrTemp(0 To W, 0 To W) As String
  1250.  
  1251.     ' Get minimum X, Y of target array
  1252.     MinY = LBound(MyArray, 1)
  1253.     MaxY = UBound(MyArray, 1)
  1254.     MinX = LBound(MyArray, 2)
  1255.     MaxX = UBound(MyArray, 2)
  1256.  
  1257.     ' Temp array's lbound is 0
  1258.     ' Calculate difference from MyArray the indices of arrTemp are
  1259.     AY = 0 - MinY
  1260.     AX = 0 - MinX
  1261.  
  1262.     ' Draw the middle span here so we don't draw it twice in the main loop,
  1263.     ' which would be a problem with blending turned on.
  1264.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  1265.     'FOR iLoopX = CX - X TO CX + X
  1266.     For iLoopX = R - X To R + X
  1267.         'PlotPoint iLoopX, CY, S, MyArray()
  1268.         'PlotPoint iLoopX, CY, S, arrTemp()
  1269.         PlotPoint iLoopX, R, S, arrTemp()
  1270.     Next iLoopX
  1271.  
  1272.     While X > Y
  1273.         RadiusError = RadiusError + Y * 2 + 1
  1274.         If RadiusError >= 0 Then
  1275.             If X <> Y + 1 Then
  1276.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1277.                 'iLoopY = CY - X
  1278.                 iLoopY = R - X
  1279.                 'FOR iLoopX = CX - Y TO CX + Y
  1280.                 For iLoopX = R - Y To R + Y
  1281.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1282.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1283.                 Next iLoopX
  1284.  
  1285.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1286.                 'iLoopY = CY + X
  1287.                 iLoopY = R + X
  1288.                 'FOR iLoopX = CX - Y TO CX + Y
  1289.                 For iLoopX = R - Y To R + Y
  1290.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1291.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1292.                 Next iLoopX
  1293.             End If
  1294.             X = X - 1
  1295.             RadiusError = RadiusError - X * 2
  1296.         End If
  1297.         Y = Y + 1
  1298.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1299.         'iLoopY = CY - Y
  1300.         iLoopY = R - Y
  1301.         'FOR iLoopX = CX - X TO CX + X
  1302.         For iLoopX = R - X To R + X
  1303.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1304.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1305.         Next iLoopX
  1306.  
  1307.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1308.         'iLoopY = CY + Y
  1309.         iLoopY = R + Y
  1310.         'FOR iLoopX = CX - X TO CX + X
  1311.         For iLoopX = R - X To R + X
  1312.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1313.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1314.         Next iLoopX
  1315.     Wend
  1316.  
  1317.     '_echo "MyArray(" + _Trim$(Str$(lbound(MyArray,1))) + " To " + _Trim$(Str$(ubound(MyArray,1))) + ", " + _Trim$(Str$(lbound(MyArray,2))) + " To " + _Trim$(Str$(ubound(MyArray,2))) + ")"
  1318.  
  1319.     ' Copy semicircle to destination Y,X
  1320.     ' JUST COPY SELECTED QUADRANT:
  1321.     Select Case Q
  1322.         Case 1:
  1323.             ' quadrant #1
  1324.             For DY = 0 To Radius
  1325.                 For DX = Radius To W
  1326.                     '_echo "DY=" + cstr$(DY) + ", DX=" + cstr$(DX)
  1327.                     If Len(arrTemp(DY, DX)) > 0 Then
  1328.                         TY = (DY + CY) - (AY + 1)
  1329.                         If TY >= MinY Then
  1330.                             If TY <= MaxY Then
  1331.                                 TX = (DX - Radius) - AX
  1332.                                 If TX >= MinX Then
  1333.                                     If TX <= MaxX Then
  1334.                                         MyArray(TY, TX) = arrTemp(DY, DX)
  1335.                                     End If
  1336.                                 End If
  1337.                             End If
  1338.                         End If
  1339.                     End If
  1340.                 Next DX
  1341.             Next DY
  1342.         Case 2:
  1343.             ' quadrant #2
  1344.             For DY = Radius To W
  1345.                 For DX = Radius To W
  1346.                     If Len(arrTemp(DY, DX)) > 0 Then
  1347.                         TY = (DY - Radius) - AY
  1348.                         If TY >= MinY Then
  1349.                             If TY <= MaxY Then
  1350.                                 TX = (DX - Radius) - AX
  1351.                                 If TX >= MinX Then
  1352.                                     If TX <= MaxX Then
  1353.                                         MyArray(TY, TX) = arrTemp(DY, DX)
  1354.                                     End If
  1355.                                 End If
  1356.                             End If
  1357.                         End If
  1358.                     End If
  1359.                 Next DX
  1360.             Next DY
  1361.         Case 3:
  1362.             ' quadrant #3
  1363.             For DY = Radius To W
  1364.                 For DX = 0 To Radius
  1365.                     If Len(arrTemp(DY, DX)) > 0 Then
  1366.                         TY = (DY - Radius) - AY
  1367.                         If TY >= MinY Then
  1368.                             If TY <= MaxY Then
  1369.                                 TX = (DX + CX) - (AX + 1)
  1370.                                 If TX >= MinX Then
  1371.                                     If TX <= MaxX Then
  1372.                                         MyArray(TY, TX) = arrTemp(DY, DX)
  1373.                                     End If
  1374.                                 End If
  1375.                             End If
  1376.                         End If
  1377.                     End If
  1378.                 Next DX
  1379.             Next DY
  1380.         Case 4:
  1381.             ' quadrant #4
  1382.             For DY = 0 To Radius
  1383.                 For DX = 0 To Radius
  1384.                     If Len(arrTemp(DY, DX)) > 0 Then
  1385.                         TY = (DY + CY) - (AY + 1)
  1386.                         If TY >= MinY Then
  1387.                             If TY <= MaxY Then
  1388.                                 TX = (DX + CX) - (AX + 1)
  1389.                                 If TX >= MinX Then
  1390.                                     If TX <= MaxX Then
  1391.                                         MyArray(TY, TX) = arrTemp(DY, DX)
  1392.                                     End If
  1393.                                 End If
  1394.                             End If
  1395.                         End If
  1396.                     End If
  1397.                 Next DX
  1398.             Next DY
  1399.         Case Else:
  1400.             ' (DO NOTHING)
  1401.     End Select
  1402.  
  1403.     '' Copy circle to destination:
  1404.     'For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  1405.     '    For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  1406.     '        IF LEN(arrTemp(DY, DX)) > 0 THEN
  1407.     '            MyArray(DY + CY, DX + CX) = arrTemp(DY, DX)
  1408.     '        END IF
  1409.     '    Next DX
  1410.     'Next DY
  1411.  
  1412. End Sub ' SemiCircleFill
  1413.  
  1414. ' /////////////////////////////////////////////////////////////////////////////
  1415.  
  1416. Sub SemiCircleFillTest
  1417.     Dim MyArray(1 To 32, 1 To 32) As String
  1418.     Dim iX As Integer
  1419.     Dim iY As Integer
  1420.     Dim in$
  1421.     Dim X As Integer
  1422.     Dim Y As Integer
  1423.     Dim R As Integer
  1424.     Dim Q As Integer
  1425.     Dim iChar As Integer
  1426.  
  1427.     ClearArray MyArray(), "."
  1428.     iChar = 64
  1429.  
  1430.     Cls
  1431.     Print "Plot a solid semicircle"
  1432.     Print "Based on CircleFill by SMcNeill."
  1433.     Print
  1434.     Print "Enter parameters to draw a semicircle."
  1435.     Print ArrayToStringTest(MyArray())
  1436.     Print
  1437.  
  1438.     Do
  1439.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot semicircle,"
  1440.         Print "radius (1-32) of semicircle, and quadrant of circle to use:"
  1441.         Print "41"
  1442.         Print "32"
  1443.         Input "X,Y,R,Q OR 0 TO QUIT: "; X, Y, R, Q
  1444.         If X > 0 And Y > 0 And R > 0 Then
  1445.             iChar = iChar + 1
  1446.             If iChar > 90 Then iChar = 65
  1447.  
  1448.             Print "X=" + cstr$(X)
  1449.             Print "Y=" + cstr$(Y)
  1450.             Print "R=" + cstr$(R)
  1451.  
  1452.             SemiCircleFill X, Y, R, Q, Chr$(iChar), MyArray()
  1453.  
  1454.             Print "Semicircle plotted (from top left), drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1455.             Print ArrayToStringTest(MyArray())
  1456.             Print
  1457.         Else
  1458.             Exit Do
  1459.         End If
  1460.     Loop
  1461.  
  1462. End Sub ' SemiCircleFillTest
  1463.  
  1464. ' /////////////////////////////////////////////////////////////////////////////
  1465. ' Re: Is this fast enough as general circle fill?
  1466. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  1467.  
  1468. ' From: bplus
  1469. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  1470.  
  1471. Sub Ellipse (CX As Integer, CY As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String)
  1472.     Dim scale As Single
  1473.     Dim xs As Integer
  1474.     Dim x As Integer
  1475.     Dim y As Integer
  1476.     Dim lastx As Integer
  1477.     Dim lasty As Integer
  1478.     Dim iLoopX As Integer
  1479.     Dim iLoopY As Integer
  1480.  
  1481.     scale = yRadius / xRadius
  1482.     xs = xRadius * xRadius
  1483.  
  1484.     'PSET (CX, CY - yRadius)
  1485.     PlotPoint CX, CY - yRadius, S, MyArray()
  1486.  
  1487.     'PSET (CX, CY + yRadius)
  1488.     PlotPoint CX, CY + yRadius, S, MyArray()
  1489.  
  1490.     lastx = 0: lasty = yRadius
  1491.     For x = 1 To xRadius
  1492.         y = scale * Sqr(xs - x * x)
  1493.         'LINE (CX + lastx, CY - lasty)-(CX + x, CY - y)
  1494.         PlotLine CX + lastx, CY - lasty, CX + x, CY - y, S, MyArray()
  1495.  
  1496.         'LINE (CX + lastx, CY + lasty)-(CX + x, CY + y)
  1497.         PlotLine CX + lastx, CY + lasty, CX + x, CY + y, S, MyArray()
  1498.  
  1499.         'LINE (CX - lastx, CY - lasty)-(CX - x, CY - y)
  1500.         PlotLine CX - lastx, CY - lasty, CX - x, CY - y, S, MyArray()
  1501.  
  1502.         'LINE (CX - lastx, CY + lasty)-(CX - x, CY + y)
  1503.         PlotLine CX - lastx, CY + lasty, CX - x, CY + y, S, MyArray()
  1504.  
  1505.         lastx = x
  1506.         lasty = y
  1507.     Next x
  1508. End Sub ' Ellipse
  1509.  
  1510. ' /////////////////////////////////////////////////////////////////////////////
  1511.  
  1512. Sub EllipseTest
  1513.     Dim MyArray(1 To 32, 1 To 32) As String
  1514.     Dim iX As Integer
  1515.     Dim iY As Integer
  1516.     Dim in$
  1517.     Dim X As Integer
  1518.     Dim Y As Integer
  1519.     Dim RX As Integer
  1520.     Dim RY As Integer
  1521.     Dim iChar As Integer
  1522.  
  1523.     ClearArray MyArray(), "."
  1524.     iChar = 64
  1525.  
  1526.     Cls
  1527.     Print "Plot an ellipse"
  1528.     Print "Based on ellipse by bplus."
  1529.     Print
  1530.     Print "Enter parameters to draw an ellipse."
  1531.     Print ArrayToStringTest(MyArray())
  1532.     Print
  1533.  
  1534.     Do
  1535.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  1536.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  1537.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  1538.         If X > 0 And Y > 0 And RX > 0 And RY > 0 Then
  1539.             iChar = iChar + 1
  1540.             If iChar > 90 Then iChar = 65
  1541.  
  1542.             Print "X =" + cstr$(X)
  1543.             Print "Y =" + cstr$(Y)
  1544.             Print "RX=" + cstr$(RX)
  1545.             Print "RY=" + cstr$(RY)
  1546.  
  1547.             Ellipse X, Y, RX, RY, Chr$(iChar), MyArray()
  1548.  
  1549.             Print "Ellipse plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1550.             Print ArrayToStringTest(MyArray())
  1551.             Print
  1552.         Else
  1553.             Exit Do
  1554.         End If
  1555.     Loop
  1556.  
  1557. End Sub ' EllipseTest
  1558.  
  1559. ' /////////////////////////////////////////////////////////////////////////////
  1560. ' Re: Is this fast enough as general circle fill?
  1561. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  1562.  
  1563. ' From: bplus
  1564. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  1565. '
  1566. ' Here is my ellipse and filled ellipse routines, no where near
  1567. ' Steve's level of performance. The speed is cut in half at
  1568. ' least because you probably have to do a whole quadrants worth
  1569. ' of calculations (ellipse not as symmetric as circle).
  1570. '
  1571. ' But I am sure this code can be optimized more than it is:
  1572.  
  1573. Sub EllipseFill (CX As Integer, CY As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String)
  1574.     Dim scale As Single
  1575.     Dim x As Integer
  1576.     Dim y As Integer
  1577.     Dim iLoopX As Integer
  1578.     Dim iLoopY As Integer
  1579.  
  1580.     scale = yRadius / xRadius
  1581.  
  1582.     'LINE (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  1583.     For iLoopY = CY - yRadius To CY + yRadius
  1584.         PlotPoint CX, iLoopY, S, MyArray()
  1585.     Next iLoopY
  1586.  
  1587.     For x = 1 To xRadius
  1588.         y = scale * Sqr(xRadius * xRadius - x * x)
  1589.  
  1590.         'LINE (CX + x, CY - y)-(CX + x, CY + y), , BF
  1591.         iLoopX = CX + x
  1592.         For iLoopY = CY - y To CY + y
  1593.             PlotPoint iLoopX, iLoopY, S, MyArray()
  1594.         Next iLoopY
  1595.  
  1596.         'LINE (CX - x, CY - y)-(CX - x, CY + y), , BF
  1597.         iLoopX = CX - x
  1598.         For iLoopY = CY - y To CY + y
  1599.             PlotPoint iLoopX, iLoopY, S, MyArray()
  1600.         Next iLoopY
  1601.     Next x
  1602. End Sub ' EllipseFill
  1603.  
  1604. ' /////////////////////////////////////////////////////////////////////////////
  1605.  
  1606. Sub EllipseFillTest
  1607.     Dim MyArray(1 To 32, 1 To 32) As String
  1608.     Dim iX As Integer
  1609.     Dim iY As Integer
  1610.     Dim in$
  1611.     Dim X As Integer
  1612.     Dim Y As Integer
  1613.     Dim RX As Integer
  1614.     Dim RY As Integer
  1615.     Dim iChar As Integer
  1616.  
  1617.     ClearArray MyArray(), "."
  1618.     iChar = 64
  1619.  
  1620.     Cls
  1621.     Print "Plot a filled ellipse"
  1622.     Print "Based on fellipse by bplus."
  1623.     Print
  1624.     Print "Enter parameters to draw an ellipse."
  1625.     Print ArrayToStringTest(MyArray())
  1626.     Print
  1627.  
  1628.     Do
  1629.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  1630.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  1631.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  1632.         If X > 0 And Y > 0 And RX > 0 And RY > 0 Then
  1633.             iChar = iChar + 1
  1634.             If iChar > 90 Then iChar = 65
  1635.  
  1636.             Print "X =" + cstr$(X)
  1637.             Print "Y =" + cstr$(Y)
  1638.             Print "RX=" + cstr$(RX)
  1639.             Print "RY=" + cstr$(RY)
  1640.  
  1641.             EllipseFill X, Y, RX, RY, Chr$(iChar), MyArray()
  1642.  
  1643.             Print "Ellipse plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1644.             Print ArrayToStringTest(MyArray())
  1645.             Print
  1646.         Else
  1647.             Exit Do
  1648.         End If
  1649.     Loop
  1650.  
  1651. End Sub ' EllipseFillTest
  1652.  
  1653. ' /////////////////////////////////////////////////////////////////////////////
  1654. ' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
  1655. ' From: http://www.thedubber.altervista.org/qbsrc.htm
  1656.  
  1657. Sub PlotLine (x1%, y1%, x2%, y2%, c$, MyArray() As String)
  1658.     Dim iLoop%
  1659.     Dim steep%: steep% = 0
  1660.     Dim ev%: ev% = 0
  1661.     Dim sx%
  1662.     Dim sy%
  1663.     Dim dx%
  1664.     Dim dy%
  1665.  
  1666.     If (x2% - x1%) > 0 Then
  1667.         sx% = 1
  1668.     Else
  1669.         sx% = -1
  1670.     End If
  1671.  
  1672.     dx% = Abs(x2% - x1%)
  1673.     If (y2% - y1%) > 0 Then
  1674.         sy% = 1
  1675.     Else
  1676.         sy% = -1
  1677.     End If
  1678.  
  1679.     dy% = Abs(y2% - y1%)
  1680.     If (dy% > dx%) Then
  1681.         steep% = 1
  1682.         Swap x1%, y1%
  1683.         Swap dx%, dy%
  1684.         Swap sx%, sy%
  1685.     End If
  1686.  
  1687.     ev% = 2 * dy% - dx%
  1688.     For iLoop% = 0 To dx% - 1
  1689.         If steep% = 1 Then
  1690.             ''PSET (y1%, x1%), c%:
  1691.             'LOCATE y1%, x1%
  1692.             'PRINT c$;
  1693.             PlotPoint y1%, x1%, c$, MyArray()
  1694.         Else
  1695.             ''PSET (x1%, y1%), c%
  1696.             'LOCATE x1%, y1%
  1697.             'PRINT c$;
  1698.             PlotPoint x1%, y1%, c$, MyArray()
  1699.         End If
  1700.  
  1701.         While ev% >= 0
  1702.             y1% = y1% + sy%
  1703.             ev% = ev% - 2 * dx%
  1704.         Wend
  1705.         x1% = x1% + sx%
  1706.         ev% = ev% + 2 * dy%
  1707.     Next iLoop%
  1708.     ''PSET (x2%, y2%), c%
  1709.     'LOCATE x2%, y2%
  1710.     'PRINT c$;
  1711.     PlotPoint x2%, y2%, c$, MyArray()
  1712. End Sub ' PlotLine
  1713.  
  1714. ' /////////////////////////////////////////////////////////////////////////////
  1715.  
  1716. Sub PlotLineTest
  1717.     Dim MyArray(1 To 32, 1 To 32) As String
  1718.     Dim in$
  1719.     Dim X1 As Integer
  1720.     Dim Y1 As Integer
  1721.     Dim X2 As Integer
  1722.     Dim Y2 As Integer
  1723.     Dim iChar As Integer
  1724.  
  1725.     ClearArray MyArray(), "."
  1726.     iChar = 64
  1727.  
  1728.     Cls
  1729.     Print "Plot line with Bresenham Algorithm"
  1730.     Print "based on BRESNHAM.BAS by Kurt Kuzba (4/16/96)."
  1731.     Print
  1732.     Print ArrayToStringTest(MyArray())
  1733.     Do
  1734.         Print "Enter coordinate values for "
  1735.         Print "line start point x1, y1 (1-32, 1-32)"
  1736.         Print "line end   point x2, y2 (1-32, 1-32)"
  1737.         Input "ENTER X1,Y1,X2,Y2 OR 0 TO QUIT: "; X1, Y1, X2, Y2
  1738.         If X1 > 0 And Y1 > 0 And X2 > 0 And Y2 > 0 Then
  1739.             iChar = iChar + 1
  1740.             If iChar > 90 Then iChar = 65
  1741.  
  1742.             Print "X1=" + cstr$(X1)
  1743.             Print "Y1=" + cstr$(Y1)
  1744.             Print "X2=" + cstr$(X2)
  1745.             Print "Y2=" + cstr$(Y2)
  1746.  
  1747.             PlotLine X1, Y1, X2, Y2, Chr$(iChar), MyArray()
  1748.  
  1749.             Print "Line plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1750.             Print ArrayToStringTest(MyArray())
  1751.  
  1752.         Else
  1753.             Exit Do
  1754.         End If
  1755.     Loop
  1756. End Sub ' PlotLineTest
  1757.  
  1758. ' /////////////////////////////////////////////////////////////////////////////
  1759. ' 3 shear method testing
  1760.  
  1761. ' _PUT Rotation Help
  1762. ' https://www.qb64.org/forum/index.php?topic=1959.0
  1763.  
  1764. ' 3 Shear Rotation - rotates without any aliasing(holes)
  1765. ' https://www.freebasic.net/forum/viewtopic.php?t=24557
  1766.  
  1767. ' From: leopardpm
  1768. ' Date: Apr 02, 2016 1:21
  1769. ' Last edited by leopardpm on Apr 02, 2016 17:18, edited 1 time in total.
  1770. '
  1771. ' This is just a little 3-shear rotation routine
  1772. ' (I am using 3-shear because it leaves no gaps/aliasing)
  1773. ' that I was wondering if anyone sees how to make it faster.
  1774. ' Obviously, I am just thinking about inside the double loop.
  1775.  
  1776. ' Thanks again to BasicCoder2 for linking me to this little routine, it is wonderful so far!
  1777.  
  1778. '''                      roto-zooming algorithm
  1779. '''                    coded by Michael S. Nissen
  1780. '''                        jernmager@yahoo.dk
  1781. '
  1782. ''' ===============================================================
  1783. ''' Recoded to run on FBC 32/64 bit WIN, Version 1.05.0, 2016, by MrSwiss
  1784. ''' Heavy flickering before going Full-Screen on 64 Bit !!!
  1785. ''' This seems NOT to be the Case on 32 Bit ...
  1786. ''' ===============================================================
  1787. '
  1788. 'Type Pixel
  1789. '  As Single   X, Y
  1790. '  As ULong    C
  1791. 'End Type
  1792. '
  1793. '''  dim vars
  1794. 'Dim shared as Any Ptr Img_Buffer
  1795. '''  write the name of the .bmp image you want to rotozoom here:
  1796. '''  (it has to be sqare ie. 100x100 pixels, 760x760 pixels or whatever)
  1797. 'Dim As String Img_Name = "phobos.bmp"
  1798. 'Dim shared as Integer X_Mid, Y_Mid, scrn_wid, scrn_hgt, P1, P2, P3, P4, C
  1799. 'Dim shared as Short Img_Hgt, Img_Wid, Img_Lft, Img_Rgt, Img_Top, Img_Btm, X, Y
  1800. 'Dim Shared As Single Cos_Ang, Sin_Ang, Rot_Fac_X, Rot_Fac_Y, Angle = 0, Scale = 1
  1801. '
  1802. ''' changed Function to Sub (+ recoded arguments list)
  1803. 'Sub Calc_rotozoom ( ByRef Cos_Ang As Single, _
  1804. '               ByRef Sin_Ang As Single, _
  1805. '               ByVal S_Fact  As Single, _
  1806. '               ByVal NewAng  As Single )
  1807. '  Cos_Ang = Cos(NewAng)*S_Fact
  1808. '  Sin_Ang = Sin(NewAng)*S_Fact
  1809. 'End Sub
  1810. '
  1811. '''  full screen
  1812. 'ScreenInfo scrn_wid, scrn_hgt
  1813. 'screenRes scrn_wid, scrn_hgt, 32,,1
  1814. '
  1815. '''  dim screenpointer (has to be done after screenres)
  1816. 'Dim As ULong Ptr Scrn_Ptr = Screenptr
  1817. '
  1818. '''  place image in center of screen
  1819. 'X_Mid = scrn_wid\2
  1820. 'Y_Mid = scrn_hgt\2
  1821. 'Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1822. '
  1823. '''  find image dimensions
  1824. 'Open Img_Name For Binary As #1
  1825. 'Get #1, 19, Img_Wid
  1826. 'Get #1, 23, Img_Hgt
  1827. 'Close #1
  1828. '
  1829. '''  prepare to dim the array that will hold the image.
  1830. 'Img_Rgt = (Img_Wid-1)\2
  1831. 'Img_Lft = -Img_Rgt
  1832. 'Img_Btm = (Img_Hgt-1)\2
  1833. 'Img_Top = -Img_Btm
  1834. '
  1835. '''  dim array to hold image. Note: pixel (0, 0) is in the center.
  1836. 'Dim As Pixel Pixel(Img_Lft to Img_Rgt, Img_Top to Img_Btm)
  1837. '
  1838. '''  imagecreate sprite and load image to sprite
  1839. 'Img_Buffer = ImageCreate (Img_Wid, Img_Hgt)
  1840. 'Bload (Img_Name, Img_Buffer)
  1841. '
  1842. '''  load image from sprite to array with point command
  1843. 'For Y = Img_Top to Img_Btm
  1844. '  For X = Img_Lft to Img_Rgt
  1845. '    With Pixel(X, Y)
  1846. '      .X = X_Mid+X
  1847. '      .Y = Y_Mid+Y
  1848. '      C = Point (X-Img_Top, Y-Img_Lft, Img_buffer)
  1849. '      If C <> RGB(255, 0, 255) Then
  1850. '        .C = C
  1851. '      Else
  1852. '        .C = RGB(0, 0, 0)
  1853. '      End If
  1854. '    End With
  1855. '  Next X
  1856. 'Next Y
  1857. '
  1858. '''  we don't need the sprite anymore, kill it
  1859. 'ImageDestroy Img_Buffer
  1860. 'Img_Buffer = 0
  1861. '
  1862. '''  main program loop
  1863. 'Do
  1864. '
  1865. '  ''  scale in/out with uparrow/downarrow
  1866. '  If Multikey(80) Then
  1867. '    Scale *= 1.03
  1868. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1869. '  ElseIf Multikey(72) Then
  1870. '    Scale *= 0.97
  1871. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1872. '  End If
  1873. '
  1874. '  ''  rotate left/right with leftarrow/rightarrow
  1875. '  If Multikey(77) Then
  1876. '    Angle -= 0.03
  1877. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1878. '  ElseIf Multikey(75) Then
  1879. '    Angle += 0.03
  1880. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1881. '  End If
  1882. '
  1883. '  ''  lock screen in order to use screen pointers
  1884. '  ScreenLock
  1885. '
  1886. '    ''  draw pixel in center of image
  1887. '    Scrn_Ptr[ X_Mid + Y_Mid * scrn_wid ] = Pixel(0, 0).C
  1888. '    ''  draw all other pixels - 4 at a time
  1889. '    For Y = Img_Top to 0
  1890. '      For X = Img_Lft to -1
  1891. '        ''  find pixel positions
  1892. '        P1 = (X_Mid+X) + (Y_Mid+Y) * scrn_wid
  1893. '        P2 = (X_Mid-X) + (Y_Mid-Y) * scrn_wid
  1894. '        P3 = (X_Mid+Y) + (Y_Mid-X) * scrn_wid
  1895. '        P4 = (X_Mid-Y) + (Y_Mid+X) * scrn_wid
  1896. '        ''  erase old pixels (paint them black)
  1897. '        Scrn_Ptr[P1] = 0
  1898. '        Scrn_Ptr[P2] = 0
  1899. '        Scrn_Ptr[P3] = 0
  1900. '        Scrn_Ptr[P4] = 0
  1901. '        ''  rotate and zoom
  1902. '        Rot_Fac_X = X*Cos_Ang - Y*Sin_Ang
  1903. '        Rot_Fac_Y = X*Sin_Ang + Y*Cos_Ang
  1904. '        If Rot_Fac_X < Img_Lft Or Rot_Fac_X > Img_Rgt Then Continue For
  1905. '        If Rot_Fac_Y < Img_Top Or Rot_Fac_Y > Img_Btm Then Continue For
  1906. '        ''  draw new pixels
  1907. '        Scrn_Ptr[P1] = Pixel(Rot_Fac_X, Rot_Fac_Y).C
  1908. '        Scrn_Ptr[P2] = Pixel(-Rot_Fac_X, -Rot_Fac_Y).C
  1909. '        Scrn_Ptr[P3] = Pixel(Rot_Fac_Y, -Rot_Fac_X).C
  1910. '        Scrn_Ptr[P4] = Pixel(-Rot_Fac_Y, Rot_Fac_X).C
  1911. '      Next X
  1912. '    Next Y
  1913. '
  1914. '  ScreenUnLock
  1915. '
  1916. '  Sleep 10, 1
  1917. 'Loop Until InKey() = Chr(27)
  1918.  
  1919. ' UPDATES:
  1920. ' Fixed bug where values 135, 224, and 314 all resolve to -45 degrees.
  1921. ' Fixed bug where an angle of 46-135 degrees caused the image to be flipped wrong.
  1922.  
  1923. ' TODO:
  1924. ' Fix issue where image looks bad at 30, 60, 120, 150, 210, 240, 300, 330 degrees
  1925.  
  1926. Sub ShearRotate (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  1927.     Const Pi = 4 * Atn(1)
  1928.  
  1929.     Dim angle As Integer
  1930.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  1931.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  1932.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  1933.     Dim x As Integer
  1934.     Dim y As Integer
  1935.     Dim nangle As Integer
  1936.     Dim nx As Integer
  1937.     Dim ny As Integer
  1938.     Dim flipper As Integer
  1939.     Dim rotr As Double
  1940.     Dim shear1 As Double
  1941.     Dim shear2 As Double
  1942.     Dim clr As Integer
  1943.     Dim y1 As _Byte
  1944.     Dim xy1 As _Byte
  1945.     Dim fy As _Byte
  1946.     Dim fx As _Byte
  1947.     Dim in$
  1948.     Dim sLine As String
  1949.  
  1950.     ' initialize new with empty
  1951.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  1952.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1953.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1954.             NewArray(x, y, 0).origx = x
  1955.             NewArray(x, y, 0).origy = y
  1956.             NewArray(x, y, 0).c = iEmpty
  1957.         Next y
  1958.     Next x
  1959.  
  1960.     ' angle is reversed
  1961.     angle = 360 - angle1
  1962.  
  1963.     ' Shearing each element 3 times in one shot
  1964.     nangle = angle
  1965.  
  1966.     ' this pre-processing portion basically rotates by 90 to get
  1967.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  1968.     If angle > 45 And angle < 225 Then
  1969.         If angle < 135 Then
  1970.             nangle = angle - 90
  1971.         Else
  1972.             nangle = angle - 180
  1973.         End If
  1974.     End If
  1975.     If angle > 135 And angle < 315 Then
  1976.         If angle < 225 Then
  1977.             nangle = angle - 180
  1978.         Else
  1979.             nangle = angle - 270
  1980.         End If
  1981.     End If
  1982.     If nangle < 0 Then
  1983.         nangle = nangle + 360
  1984.     End If
  1985.     If nangle > 359 Then
  1986.         nangle = nangle - 360
  1987.     End If
  1988.  
  1989.     rotr = nangle * DtoR
  1990.     shear1 = Tan(rotr / 2) ' correct way
  1991.     shear2 = Sin(rotr)
  1992.  
  1993.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  1994.     ' ***       all resolve to -45 degrees.
  1995.     ' ***       Fixed by changing < to <=
  1996.  
  1997.     'if angle >  45 and angle < 134 then
  1998.     If angle > 45 And angle <= 134 Then
  1999.         flipper = 1
  2000.     ElseIf angle > 134 And angle <= 224 Then
  2001.         flipper = 2
  2002.     ElseIf angle > 224 And angle <= 314 Then
  2003.         ' *** NOTE: this had a bug where this flipper was wrong
  2004.         '           Fixed by adding case 7
  2005.         'flipper = 3
  2006.         flipper = 7
  2007.     Else
  2008.         flipper = 0
  2009.     End If
  2010.  
  2011.     ' Here is where it needs some optimizing possibly... kinda slow...
  2012.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2013.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2014.             Select Case flipper
  2015.                 Case 1:
  2016.                     nx = -y
  2017.                     ny = x
  2018.                 Case 2:
  2019.                     nx = -x
  2020.                     ny = -y
  2021.                 Case 3:
  2022.                     nx = -y
  2023.                     ny = -x
  2024.                 Case 4:
  2025.                     nx = -x
  2026.                     ny = y
  2027.                 Case 5:
  2028.                     nx = x
  2029.                     ny = -y
  2030.                 Case 6:
  2031.                     nx = y
  2032.                     ny = x
  2033.                 Case 7:
  2034.                     nx = y
  2035.                     ny = -x
  2036.                 Case Else:
  2037.                     nx = x
  2038.                     ny = y
  2039.             End Select
  2040.  
  2041.             clr = OldArray(nx, ny, 0).c
  2042.  
  2043.             y1 = y * shear1
  2044.             xy1 = x + y1
  2045.             fy = (y - xy1 * shear2)
  2046.             fx = xy1 + fy * shear1
  2047.  
  2048.             If fx >= -16 And fx <= 16 Then
  2049.                 If fy >= -16 And fy <= 16 Then
  2050.                     NewArray(fx, fy, 0).c = clr
  2051.                     NewArray(fx, fy, 0).origx = fx
  2052.                     NewArray(fx, fy, 0).origy = fy
  2053.                 End If
  2054.             End If
  2055.         Next x
  2056.     Next y
  2057. End Sub ' ShearRotate
  2058.  
  2059. ' /////////////////////////////////////////////////////////////////////////////
  2060. ' Same as ShearRotate, except adds iOverwriteCount parameter,
  2061. ' and counts how many points are overwriting existing points,
  2062. ' and return that value byref in parameter iOverwriteCount.
  2063.  
  2064. Sub ShearRotate1 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iOverwriteCount As Integer)
  2065.     Const Pi = 4 * Atn(1)
  2066.  
  2067.     Dim angle As Integer
  2068.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2069.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2070.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2071.     Dim x As Integer
  2072.     Dim y As Integer
  2073.     Dim nangle As Integer
  2074.     Dim nx As Integer
  2075.     Dim ny As Integer
  2076.     Dim flipper As Integer
  2077.     Dim rotr As Double
  2078.     Dim shear1 As Double
  2079.     Dim shear2 As Double
  2080.     Dim clr As Integer
  2081.     Dim y1 As _Byte
  2082.     Dim xy1 As _Byte
  2083.     Dim fy As _Byte
  2084.     Dim fx As _Byte
  2085.     Dim in$
  2086.     Dim sLine As String
  2087.  
  2088.     ' initialize new with empty
  2089.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2090.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2091.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2092.             NewArray(x, y, 0).origx = x
  2093.             NewArray(x, y, 0).origy = y
  2094.             NewArray(x, y, 0).c = iEmpty
  2095.         Next y
  2096.     Next x
  2097.  
  2098.     ' angle is reversed
  2099.     angle = 360 - angle1
  2100.  
  2101.     ' Shearing each element 3 times in one shot
  2102.     nangle = angle
  2103.  
  2104.     ' this pre-processing portion basically rotates by 90 to get
  2105.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2106.     If angle > 45 And angle < 225 Then
  2107.         If angle < 135 Then
  2108.             nangle = angle - 90
  2109.         Else
  2110.             nangle = angle - 180
  2111.         End If
  2112.     End If
  2113.     If angle > 135 And angle < 315 Then
  2114.         If angle < 225 Then
  2115.             nangle = angle - 180
  2116.         Else
  2117.             nangle = angle - 270
  2118.         End If
  2119.     End If
  2120.     If nangle < 0 Then
  2121.         nangle = nangle + 360
  2122.     End If
  2123.     If nangle > 359 Then
  2124.         nangle = nangle - 360
  2125.     End If
  2126.  
  2127.     rotr = nangle * DtoR
  2128.     shear1 = Tan(rotr / 2) ' correct way
  2129.     shear2 = Sin(rotr)
  2130.  
  2131.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2132.     ' ***       all resolve to -45 degrees.
  2133.     ' ***       Fixed by changing < to <=
  2134.  
  2135.     'if angle >  45 and angle < 134 then
  2136.     If angle > 45 And angle <= 134 Then
  2137.         flipper = 1
  2138.     ElseIf angle > 134 And angle <= 224 Then
  2139.         flipper = 2
  2140.     ElseIf angle > 224 And angle <= 314 Then
  2141.         ' *** NOTE: this had a bug where this flipper was wrong
  2142.         '           Fixed by adding case 7
  2143.         'flipper = 3
  2144.         flipper = 7
  2145.     Else
  2146.         flipper = 0
  2147.     End If
  2148.  
  2149.     ' Here is where it needs some optimizing possibly... kinda slow...
  2150.     iOverwriteCount = 0
  2151.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2152.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2153.             Select Case flipper
  2154.                 Case 1:
  2155.                     nx = -y
  2156.                     ny = x
  2157.                 Case 2:
  2158.                     nx = -x
  2159.                     ny = -y
  2160.                 Case 3:
  2161.                     nx = -y
  2162.                     ny = -x
  2163.                 Case 4:
  2164.                     nx = -x
  2165.                     ny = y
  2166.                 Case 5:
  2167.                     nx = x
  2168.                     ny = -y
  2169.                 Case 6:
  2170.                     nx = y
  2171.                     ny = x
  2172.                 Case 7:
  2173.                     nx = y
  2174.                     ny = -x
  2175.                 Case Else:
  2176.                     nx = x
  2177.                     ny = y
  2178.             End Select
  2179.  
  2180.             clr = OldArray(nx, ny, 0).c
  2181.  
  2182.             y1 = y * shear1
  2183.             xy1 = x + y1
  2184.             fy = (y - xy1 * shear2)
  2185.             fx = xy1 + fy * shear1
  2186.  
  2187.             If fx >= -16 And fx <= 16 Then
  2188.                 If fy >= -16 And fy <= 16 Then
  2189.  
  2190.                     ' count points that will be overwritten
  2191.                     If NewArray(fx, fy, 0).c <> iEmpty Then
  2192.                         iOverwriteCount = iOverwriteCount + 1
  2193.                     End If
  2194.  
  2195.                     NewArray(fx, fy, 0).c = clr
  2196.                     NewArray(fx, fy, 0).origx = fx
  2197.                     NewArray(fx, fy, 0).origy = fy
  2198.                 End If
  2199.             End If
  2200.         Next x
  2201.     Next y
  2202. End Sub ' ShearRotate1
  2203.  
  2204. ' /////////////////////////////////////////////////////////////////////////////
  2205.  
  2206. Sub ShearRotate1Test1
  2207.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2208.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2209.     Dim sMap As String
  2210.     Dim D As Integer
  2211.     Dim in$
  2212.  
  2213.     ' GET A SHAPE TO BE ROTATED
  2214.     Cls
  2215.     Print "3 shear rotation based on code by leopardpm"
  2216.     Print
  2217.  
  2218.     sMap = TestSprite1$
  2219.  
  2220.     ' CONVERT SHAPE TO ARRAY
  2221.     StringToRotationArray RoArray1(), sMap, "."
  2222.     Print "Initial contents of Rotation Array:"
  2223.     Print RotationArrayToStringTest(RoArray1())
  2224.     Print
  2225.  
  2226.     ' ROTATE THE SHAPE
  2227.     Do
  2228.         Print "Type degrees to rotate (0 TO 360) or non-numeric value to quit."
  2229.         Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2230.  
  2231.         Input "Degrees to rotate (q to quit)? "; in$
  2232.         If IsNum%(in$) Then
  2233.             D = Val(in$)
  2234.             If D >= 0 And D <= 360 Then
  2235.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  2236.                 Print
  2237.                 Print "Rotated by " + cstr$(D) + " degrees:"
  2238.                 Print RotationArrayToStringTest(RoArray2())
  2239.                 Print
  2240.             Else
  2241.                 Exit Do
  2242.             End If
  2243.         Else
  2244.             Exit Do
  2245.         End If
  2246.     Loop
  2247. End Sub ' ShearRotate1Test1
  2248.  
  2249. ' /////////////////////////////////////////////////////////////////////////////
  2250. ' Now receives parameter sMap
  2251. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  2252.  
  2253. ' e.g. ShearRotate1Test2 TestSprite1$
  2254.  
  2255. Sub ShearRotate1Test2 (sMap As String)
  2256.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2257.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2258.     'Dim sMap As String
  2259.     Dim D As Integer
  2260.     Dim D1 As Integer
  2261.     Dim in$
  2262.     Dim bFinished As Integer
  2263.     Dim iOverwriteCount As Integer
  2264.  
  2265.     ' GET A SHAPE TO BE ROTATED
  2266.     Cls
  2267.     Print "3 shear rotation based on code by leopardpm"
  2268.     'sMap = TestSprite1$
  2269.  
  2270.     ' CONVERT SHAPE TO ARRAY
  2271.     StringToRotationArray RoArray1(), sMap, "."
  2272.  
  2273.     ' GET START ANGLE
  2274.     D = 0
  2275.     Print
  2276.     Print "Rotated by " + cstr$(D) + " degrees:"
  2277.     Print RotationArrayToStringTest(RoArray1())
  2278.     Print
  2279.     Print "Type an angle (-360 to 360) to rotate to, "
  2280.     Print "or blank to increase by 1 degree, or q to quit."
  2281.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2282.     Print "Hold down <ENTER> to rotate continually."
  2283.     Input "Angle (q to quit)? ", in$
  2284.     If Len(in$) > 0 Then
  2285.         If IsNum%(in$) Then
  2286.             D1 = Val(in$)
  2287.         Else
  2288.             D1 = -500
  2289.         End If
  2290.     Else
  2291.         D1 = 1
  2292.     End If
  2293.  
  2294.     ' ROTATE TO EACH ANGLE
  2295.     If D1 >= -360 And D1 <= 360 Then
  2296.         bFinished = FALSE
  2297.         Do
  2298.             ' ROTATE CLOCKWISE
  2299.             For D = D1 To 360
  2300.                 Cls
  2301.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  2302.                 Print
  2303.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2304.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  2305.  
  2306.                 Print RotationArrayToStringTest(RoArray2())
  2307.                 Print
  2308.  
  2309.                 Print "Type an angle (-360 to 360) to rotate to, "
  2310.                 Print "or blank to increase by 1 degree, or q to quit."
  2311.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2312.                 Print "Hold down <ENTER> to rotate continually."
  2313.                 Input "Angle (q to quit)? ", in$
  2314.                 If Len(in$) > 0 Then
  2315.                     If IsNum%(in$) Then
  2316.                         D = Val(in$)
  2317.                         If D >= 0 And D <= 360 Then
  2318.                             D = D - 1
  2319.                         Else
  2320.                             bFinished = TRUE
  2321.                             Exit For
  2322.                         End If
  2323.                     Else
  2324.                         bFinished = TRUE
  2325.                         Exit For
  2326.                     End If
  2327.                 End If
  2328.             Next D
  2329.             If bFinished = TRUE Then Exit Do
  2330.  
  2331.             ' ROTATE COUNTER-CLOCKWISE
  2332.             For D = 360 To D1 Step -1
  2333.                 Cls
  2334.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  2335.                 Print
  2336.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2337.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  2338.  
  2339.                 Print RotationArrayToStringTest(RoArray2())
  2340.                 Print
  2341.  
  2342.                 Print "Type an angle (0 to 360) to rotate to, "
  2343.                 Print "or blank to increase by 1 degree, or q to quit."
  2344.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2345.                 Print "Hold down <ENTER> to rotate continually."
  2346.                 Input "Angle (q to quit)? ", in$
  2347.                 If Len(in$) > 0 Then
  2348.                     If IsNum%(in$) Then
  2349.                         D = Val(in$)
  2350.                         If D >= 0 And D <= 360 Then
  2351.                             D = D + 1
  2352.                         Else
  2353.                             bFinished = TRUE
  2354.                             Exit For
  2355.                         End If
  2356.                     Else
  2357.                         bFinished = TRUE
  2358.                         Exit For
  2359.                     End If
  2360.                 End If
  2361.             Next D
  2362.             If bFinished = TRUE Then Exit Do
  2363.         Loop
  2364.     End If
  2365. End Sub ' ShearRotate1Test2
  2366.  
  2367. ' /////////////////////////////////////////////////////////////////////////////
  2368. ' ShearRotate v2
  2369. ' Tries to fix the problem of 2 points resolving to the same coordinate
  2370. ' (one overwrites the other, which becomes "lost")
  2371.  
  2372. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  2373.  
  2374. Sub ShearRotate2 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iMissing As Integer)
  2375.     Const Pi = 4 * Atn(1)
  2376.  
  2377.     Dim angle As Integer
  2378.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2379.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2380.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2381.     Dim x As Integer
  2382.     Dim y As Integer
  2383.     Dim nangle As Integer
  2384.     Dim nx As Integer
  2385.     Dim ny As Integer
  2386.     Dim flipper As Integer
  2387.     Dim rotr As Double
  2388.     Dim shear1 As Double
  2389.     Dim shear2 As Double
  2390.     Dim clr As Integer
  2391.     Dim y1 As _Byte
  2392.     Dim xy1 As _Byte
  2393.     Dim fy As _Byte
  2394.     Dim fx As _Byte
  2395.     Dim in$
  2396.     Dim sLine As String
  2397.     ReDim arrLost(-1) As RotationType
  2398.     Dim iLoop As Integer
  2399.     Dim bFound As Integer
  2400.  
  2401.     ' initialize new with empty
  2402.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2403.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2404.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2405.             NewArray(x, y, 0).origx = x
  2406.             NewArray(x, y, 0).origy = y
  2407.             NewArray(x, y, 0).c = iEmpty
  2408.         Next y
  2409.     Next x
  2410.  
  2411.     ' angle is reversed
  2412.     angle = 360 - angle1
  2413.  
  2414.     ' Shearing each element 3 times in one shot
  2415.     nangle = angle
  2416.  
  2417.     ' this pre-processing portion basically rotates by 90 to get
  2418.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2419.     If angle > 45 And angle < 225 Then
  2420.         If angle < 135 Then
  2421.             nangle = angle - 90
  2422.         Else
  2423.             nangle = angle - 180
  2424.         End If
  2425.     End If
  2426.     If angle > 135 And angle < 315 Then
  2427.         If angle < 225 Then
  2428.             nangle = angle - 180
  2429.         Else
  2430.             nangle = angle - 270
  2431.         End If
  2432.     End If
  2433.     If nangle < 0 Then
  2434.         nangle = nangle + 360
  2435.     End If
  2436.     If nangle > 359 Then
  2437.         nangle = nangle - 360
  2438.     End If
  2439.  
  2440.     rotr = nangle * DtoR
  2441.     shear1 = Tan(rotr / 2) ' correct way
  2442.     shear2 = Sin(rotr)
  2443.  
  2444.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2445.     ' ***       all resolve to -45 degrees.
  2446.     ' ***       Fixed by changing < to <=
  2447.  
  2448.     'if angle >  45 and angle < 134 then
  2449.     If angle > 45 And angle <= 134 Then
  2450.         flipper = 1
  2451.     ElseIf angle > 134 And angle <= 224 Then
  2452.         flipper = 2
  2453.     ElseIf angle > 224 And angle <= 314 Then
  2454.         ' *** NOTE: this had a bug where this flipper was wrong
  2455.         '           Fixed by adding case 7
  2456.         'flipper = 3
  2457.         flipper = 7
  2458.     Else
  2459.         flipper = 0
  2460.     End If
  2461.  
  2462.     ' Here is where it needs some optimizing possibly... kinda slow...
  2463.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2464.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2465.             Select Case flipper
  2466.                 Case 1:
  2467.                     nx = -y
  2468.                     ny = x
  2469.                 Case 2:
  2470.                     nx = -x
  2471.                     ny = -y
  2472.                 Case 3:
  2473.                     nx = -y
  2474.                     ny = -x
  2475.                 Case 4:
  2476.                     nx = -x
  2477.                     ny = y
  2478.                 Case 5:
  2479.                     nx = x
  2480.                     ny = -y
  2481.                 Case 6:
  2482.                     nx = y
  2483.                     ny = x
  2484.                 Case 7:
  2485.                     nx = y
  2486.                     ny = -x
  2487.                 Case Else:
  2488.                     nx = x
  2489.                     ny = y
  2490.             End Select
  2491.  
  2492.             clr = OldArray(nx, ny, 0).c
  2493.  
  2494.             y1 = y * shear1
  2495.             xy1 = x + y1
  2496.             fy = (y - xy1 * shear2)
  2497.             fx = xy1 + fy * shear1
  2498.  
  2499.             If fx >= -16 And fx <= 16 Then
  2500.                 If fy >= -16 And fy <= 16 Then
  2501.                     ' only draw here if this spot is empty
  2502.                     If NewArray(fx, fy, 0).c = iEmpty Then
  2503.                         NewArray(fx, fy, 0).c = clr
  2504.                         NewArray(fx, fy, 0).origx = fx
  2505.                         NewArray(fx, fy, 0).origy = fy
  2506.                     Else
  2507.                         ' don't draw, but save it to a list to handle later
  2508.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  2509.                         arrLost(UBound(arrLost)).c = clr
  2510.                         arrLost(UBound(arrLost)).origx = fx
  2511.                         arrLost(UBound(arrLost)).origy = fy
  2512.                     End If
  2513.                 End If
  2514.             End If
  2515.         Next x
  2516.     Next y
  2517.  
  2518.     ' try to place any points that would have overwritten to a spot nearby
  2519.     ' can nearby be determined by the angle of rotation?
  2520.     ' perhaps if we divide the screen up into 4 zones:
  2521.     '
  2522.     ' --------------------------------------
  2523.     '|                   |                  |
  2524.     '| zone 4            | zone 1           |
  2525.     '| 271-359 degrees)  | (1-89 degrees)   |
  2526.     '|--------------------------------------|
  2527.     '|                   |                  |
  2528.     '| zone 3            | zone 2           |
  2529.     '| (181-269 degrees) | (91-179 degrees) |
  2530.     '|                   |                  |
  2531.     ' --------------------------------------
  2532.  
  2533.     ' in zone   search direction (y,x)
  2534.     ' -------   ----------------------
  2535.     ' 1         up   + right
  2536.     ' 2         down + right
  2537.     ' 3         down + left
  2538.     ' 4         up   + left
  2539.  
  2540.     iMissing = 0
  2541.     For iLoop = 0 To UBound(arrLost)
  2542.         bFound = FindEmptyShearRotationPoint2%(arrLost(iLoop), angle1, iEmpty, x, y, NewArray())
  2543.         If bFound = TRUE Then
  2544.             If m_bDebug = TRUE Then
  2545.                 _Echo "Plotted  missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  2546.             End If
  2547.         Else
  2548.             iMissing = iMissing + 1
  2549.             If m_bDebug = TRUE Then
  2550.                 _Echo "Detected missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  2551.             End If
  2552.         End If
  2553.     Next iLoop
  2554.  
  2555. End Sub ' ShearRotate2
  2556.  
  2557. ' /////////////////////////////////////////////////////////////////////////////
  2558. ' Receives
  2559. ' FindMe (RotationType) = contains the starting location (.origx, .origy) to start looking from, and the value (.c) to write
  2560. ' angle1 (Integer) = angle we were rotating to, to determine direction to look in
  2561. ' iEmpty (Integer) = value to test against for empty
  2562. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  2563. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  2564. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  2565.  
  2566. ' Returns
  2567. ' FALSE if no empty spot was found
  2568. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  2569.  
  2570. Function FindEmptyShearRotationPoint2% (FindMe As RotationType, angle1 As Integer, iEmpty As Integer, destX As Integer, destY As Integer, NewArray() As RotationType)
  2571.     Dim bResult As Integer: bResult = FALSE
  2572.     Dim x As Integer
  2573.     Dim y As Integer
  2574.     Dim dirX As Integer
  2575.     Dim dirY As Integer
  2576.  
  2577.     destX = 0
  2578.     destY = 0
  2579.  
  2580.     ' Choose search direction depending on the angle
  2581.     If angle1 > 0 And angle1 < 90 Then
  2582.         dirX = 1
  2583.         dirY = -1
  2584.     ElseIf angle1 > 90 And angle1 < 180 Then
  2585.         dirX = 1
  2586.         dirY = 1
  2587.     ElseIf angle1 > 180 And angle1 < 270 Then
  2588.         dirX = -1
  2589.         dirY = 1
  2590.     ElseIf angle1 > 270 And angle1 < 360 Then
  2591.         dirX = -1
  2592.         dirY = -1
  2593.     Else
  2594.         dirX = 0
  2595.         dirY = 0
  2596.     End If
  2597.  
  2598.     If dirX <> 0 Then
  2599.         x = FindMe.origx
  2600.         y = FindMe.origy
  2601.         Do
  2602.             ' quit if we're out of bounds
  2603.             If x < LBound(NewArray, 1) Then Exit Do
  2604.             If x > UBound(NewArray, 1) Then Exit Do
  2605.             If y < LBound(NewArray, 2) Then Exit Do
  2606.             If y > UBound(NewArray, 2) Then Exit Do
  2607.  
  2608.             ' =============================================================================
  2609.             ' BEGIN SEARCH
  2610.             ' =============================================================================
  2611.             ' look along y axis for a blank spot
  2612.             destX = x
  2613.             destY = y + dirY
  2614.             If destX >= LBound(NewArray, 1) Then
  2615.                 If destX <= UBound(NewArray, 1) Then
  2616.                     If destY >= LBound(NewArray, 2) Then
  2617.                         If destY <= UBound(NewArray, 2) Then
  2618.                             If NewArray(destX, destY, 0).c = iEmpty Then
  2619.                                 NewArray(destX, destY, 0).c = FindMe.c
  2620.                                 bResult = TRUE
  2621.                                 Exit Do
  2622.                             End If
  2623.                         End If
  2624.                     End If
  2625.                 End If
  2626.             End If
  2627.  
  2628.             ' look along x axis for a blank spot
  2629.             destX = x + dirX
  2630.             destY = y
  2631.             If destX >= LBound(NewArray, 1) Then
  2632.                 If destX <= UBound(NewArray, 1) Then
  2633.                     If destY >= LBound(NewArray, 2) Then
  2634.                         If destY <= UBound(NewArray, 2) Then
  2635.                             If NewArray(x + dirX, y, 0).c = iEmpty Then
  2636.                                 NewArray(destX, destY, 0).c = FindMe.c
  2637.                                 bResult = TRUE
  2638.                                 Exit Do
  2639.                             End If
  2640.                         End If
  2641.                     End If
  2642.                 End If
  2643.             End If
  2644.  
  2645.             ' look diagonally for a blank spot
  2646.             destX = x + dirX
  2647.             destY = y + dirY
  2648.             If destX >= LBound(NewArray, 1) Then
  2649.                 If destX <= UBound(NewArray, 1) Then
  2650.                     If destY >= LBound(NewArray, 2) Then
  2651.                         If destY <= UBound(NewArray, 2) Then
  2652.                             If NewArray(x + dirX, y + dirY, 0).c = iEmpty Then
  2653.                                 NewArray(destX, destY, 0).c = FindMe.c
  2654.                                 bResult = TRUE
  2655.                                 Exit Do
  2656.                             End If
  2657.                         End If
  2658.                     End If
  2659.                 End If
  2660.             End If
  2661.             ' =============================================================================
  2662.             ' END SEARCH
  2663.             ' =============================================================================
  2664.  
  2665.             ' Keep looking
  2666.             x = x + dirX
  2667.             y = y + dirY
  2668.         Loop
  2669.     End If
  2670.  
  2671.     ' Return result
  2672.     FindEmptyShearRotationPoint2% = bResult
  2673. End Function ' FindEmptyShearRotationPoint2%
  2674.  
  2675. ' /////////////////////////////////////////////////////////////////////////////
  2676. ' Tries to correct for missing points.
  2677.  
  2678. ' Receives parameter sMap
  2679. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  2680.  
  2681. ' e.g. ShearRotate2Test1 TestSprite1$
  2682.  
  2683. Sub ShearRotate2Test1 (sMap As String)
  2684.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2685.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2686.     'Dim sMap As String
  2687.     Dim D As Integer
  2688.     Dim D1 As Integer
  2689.     Dim in$
  2690.     Dim bFinished As Integer
  2691.     Dim iMissing As Integer
  2692.  
  2693.     ' GET A SHAPE TO BE ROTATED
  2694.     Cls
  2695.     Print "3 shear rotation based on code by leopardpm"
  2696.     'sMap = TestSprite1$
  2697.  
  2698.     ' CONVERT SHAPE TO ARRAY
  2699.     StringToRotationArray RoArray1(), sMap, "."
  2700.  
  2701.     ' GET START ANGLE
  2702.     D = 0
  2703.     Print
  2704.     Print "Rotated by " + cstr$(D) + " degrees:"
  2705.     Print RotationArrayToStringTest(RoArray1())
  2706.     Print
  2707.     Print "Type an angle (-360 to 360) to rotate to, "
  2708.     Print "or blank to increase by 1 degree, or q to quit."
  2709.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2710.     Print "Hold down <ENTER> to rotate continually."
  2711.     Input "Angle (q to quit)? ", in$
  2712.     If Len(in$) > 0 Then
  2713.         If IsNum%(in$) Then
  2714.             D1 = Val(in$)
  2715.         Else
  2716.             D1 = -500
  2717.         End If
  2718.     Else
  2719.         D1 = 1
  2720.     End If
  2721.  
  2722.     ' ROTATE TO EACH ANGLE
  2723.     If D1 >= -360 And D1 <= 360 Then
  2724.         bFinished = FALSE
  2725.         Do
  2726.             ' ROTATE CLOCKWISE
  2727.             For D = D1 To 360
  2728.                 Cls
  2729.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  2730.                 Print
  2731.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2732.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  2733.  
  2734.                 Print RotationArrayToStringTest(RoArray2())
  2735.                 Print
  2736.  
  2737.                 Print "Type an angle (-360 to 360) to rotate to, "
  2738.                 Print "or blank to increase by 1 degree, or q to quit."
  2739.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2740.                 Print "Hold down <ENTER> to rotate continually."
  2741.                 Input "Angle (q to quit)? ", in$
  2742.                 If Len(in$) > 0 Then
  2743.                     If IsNum%(in$) Then
  2744.                         D = Val(in$)
  2745.                         If D >= 0 And D <= 360 Then
  2746.                             D = D - 1
  2747.                         Else
  2748.                             bFinished = TRUE
  2749.                             Exit For
  2750.                         End If
  2751.                     Else
  2752.                         bFinished = TRUE
  2753.                         Exit For
  2754.                     End If
  2755.                 End If
  2756.             Next D
  2757.             If bFinished = TRUE Then Exit Do
  2758.  
  2759.             ' ROTATE COUNTER-CLOCKWISE
  2760.             For D = 360 To D1 Step -1
  2761.                 Cls
  2762.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  2763.                 Print
  2764.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2765.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  2766.  
  2767.                 Print RotationArrayToStringTest(RoArray2())
  2768.                 Print
  2769.  
  2770.                 Print "Type an angle (0 to 360) to rotate to, "
  2771.                 Print "or blank to increase by 1 degree, or q to quit."
  2772.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2773.                 Print "Hold down <ENTER> to rotate continually."
  2774.                 Input "Angle (q to quit)? ", in$
  2775.                 If Len(in$) > 0 Then
  2776.                     If IsNum%(in$) Then
  2777.                         D = Val(in$)
  2778.                         If D >= 0 And D <= 360 Then
  2779.                             D = D + 1
  2780.                         Else
  2781.                             bFinished = TRUE
  2782.                             Exit For
  2783.                         End If
  2784.                     Else
  2785.                         bFinished = TRUE
  2786.                         Exit For
  2787.                     End If
  2788.                 End If
  2789.             Next D
  2790.             If bFinished = TRUE Then Exit Do
  2791.         Loop
  2792.     End If
  2793. End Sub ' ShearRotate2Test1
  2794.  
  2795. ' /////////////////////////////////////////////////////////////////////////////
  2796. ' ShearRotate v3
  2797.  
  2798. ' Tries to fix the problem of 2 points resolving to the same coordinate
  2799. ' (one overwrites the other, which becomes "lost")
  2800. ' a little more accurately, using iDirection parameter
  2801. ' (which can be cClockwise or cCounterClockwise)
  2802. ' together with which quarter of the screen the point is in,
  2803.  
  2804. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  2805.  
  2806. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  2807.  
  2808. Sub ShearRotate3 ( _
  2809.     OldArray() As RotationType, _
  2810.     NewArray() As RotationType, _
  2811.     angle1 As Integer, _
  2812.     iDirection As Integer, _
  2813.     iEmpty As Integer, _
  2814.     iMissing As Integer)
  2815.  
  2816.     Const Pi = 4 * Atn(1)
  2817.  
  2818.     Dim angle As Integer
  2819.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2820.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2821.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2822.     Dim x As Integer
  2823.     Dim y As Integer
  2824.     Dim nangle As Integer
  2825.     Dim nx As Integer
  2826.     Dim ny As Integer
  2827.     Dim flipper As Integer
  2828.     Dim rotr As Double
  2829.     Dim shear1 As Double
  2830.     Dim shear2 As Double
  2831.     Dim clr As Integer
  2832.     Dim y1 As _Byte
  2833.     Dim xy1 As _Byte
  2834.     Dim fy As _Byte
  2835.     Dim fx As _Byte
  2836.     Dim in$
  2837.     Dim sLine As String
  2838.     ReDim arrLost(-1) As RotationType
  2839.     Dim iLoop As Integer
  2840.     Dim bFound As Integer
  2841.     Dim iScreenZone As Integer
  2842.     Dim iMidX As Integer
  2843.     Dim iMidY As Integer
  2844.  
  2845.     ' initialize new with empty
  2846.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2847.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2848.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2849.             NewArray(x, y, 0).origx = x
  2850.             NewArray(x, y, 0).origy = y
  2851.             NewArray(x, y, 0).c = iEmpty
  2852.         Next y
  2853.     Next x
  2854.  
  2855.     ' find midpoints
  2856.     iMidX = (UBound(OldArray, 1) - LBound(OldArray, 1)) / 2
  2857.     iMidY = (UBound(OldArray, 2) - LBound(OldArray, 2)) / 2
  2858.  
  2859.     ' angle is reversed
  2860.     angle = 360 - angle1
  2861.  
  2862.     ' Shearing each element 3 times in one shot
  2863.     nangle = angle
  2864.  
  2865.     ' this pre-processing portion basically rotates by 90 to get
  2866.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2867.     If angle > 45 And angle < 225 Then
  2868.         If angle < 135 Then
  2869.             nangle = angle - 90
  2870.         Else
  2871.             nangle = angle - 180
  2872.         End If
  2873.     End If
  2874.     If angle > 135 And angle < 315 Then
  2875.         If angle < 225 Then
  2876.             nangle = angle - 180
  2877.         Else
  2878.             nangle = angle - 270
  2879.         End If
  2880.     End If
  2881.     If nangle < 0 Then
  2882.         nangle = nangle + 360
  2883.     End If
  2884.     If nangle > 359 Then
  2885.         nangle = nangle - 360
  2886.     End If
  2887.  
  2888.     rotr = nangle * DtoR
  2889.     shear1 = Tan(rotr / 2) ' correct way
  2890.     shear2 = Sin(rotr)
  2891.  
  2892.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2893.     ' ***       all resolve to -45 degrees.
  2894.     ' ***       Fixed by changing < to <=
  2895.  
  2896.     'if angle >  45 and angle < 134 then
  2897.     If angle > 45 And angle <= 134 Then
  2898.         flipper = 1
  2899.     ElseIf angle > 134 And angle <= 224 Then
  2900.         flipper = 2
  2901.     ElseIf angle > 224 And angle <= 314 Then
  2902.         ' *** NOTE: this had a bug where this flipper was wrong
  2903.         '           Fixed by adding case 7
  2904.         'flipper = 3
  2905.         flipper = 7
  2906.     Else
  2907.         flipper = 0
  2908.     End If
  2909.  
  2910.     ' Here is where it needs some optimizing possibly... kinda slow...
  2911.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2912.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2913.  
  2914.             ' find which part of screen the current point is in
  2915.             If y > iMidY Then
  2916.                 ' bottom half of screen
  2917.                 If x > iMidX Then
  2918.                     ' right half of screen
  2919.                     iScreenZone = 2
  2920.                 Else
  2921.                     ' left half of screen
  2922.                     iScreenZone = 3
  2923.                 End If
  2924.             Else
  2925.                 ' top half of screen
  2926.                 If x > iMidX Then
  2927.                     ' right half of screen
  2928.                     iScreenZone = 1
  2929.                 Else
  2930.                     ' left half of screen
  2931.                     iScreenZone = 4
  2932.                 End If
  2933.             End If
  2934.  
  2935.             ' calculate directions
  2936.             Select Case flipper
  2937.                 Case 1:
  2938.                     nx = -y
  2939.                     ny = x
  2940.                 Case 2:
  2941.                     nx = -x
  2942.                     ny = -y
  2943.                 Case 3:
  2944.                     nx = -y
  2945.                     ny = -x
  2946.                 Case 4:
  2947.                     nx = -x
  2948.                     ny = y
  2949.                 Case 5:
  2950.                     nx = x
  2951.                     ny = -y
  2952.                 Case 6:
  2953.                     nx = y
  2954.                     ny = x
  2955.                 Case 7:
  2956.                     nx = y
  2957.                     ny = -x
  2958.                 Case Else:
  2959.                     nx = x
  2960.                     ny = y
  2961.             End Select
  2962.  
  2963.             clr = OldArray(nx, ny, 0).c
  2964.  
  2965.             y1 = y * shear1
  2966.             xy1 = x + y1
  2967.             fy = (y - xy1 * shear2)
  2968.             fx = xy1 + fy * shear1
  2969.  
  2970.             If fx >= -16 And fx <= 16 Then
  2971.                 If fy >= -16 And fy <= 16 Then
  2972.                     ' only draw here if this spot is empty
  2973.                     If NewArray(fx, fy, 0).c = iEmpty Then
  2974.                         NewArray(fx, fy, 0).c = clr
  2975.                         NewArray(fx, fy, 0).origx = fx
  2976.                         NewArray(fx, fy, 0).origy = fy
  2977.                     Else
  2978.                         ' don't draw, but save it to a list to handle later
  2979.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  2980.                         arrLost(UBound(arrLost)).c = clr
  2981.                         arrLost(UBound(arrLost)).origx = fx
  2982.                         arrLost(UBound(arrLost)).origy = fy
  2983.  
  2984.                         ' preserve which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  2985.                         arrLost(UBound(arrLost)).z = iScreenZone
  2986.                     End If
  2987.                 End If
  2988.             End If
  2989.         Next x
  2990.     Next y
  2991.  
  2992.     ' try to place any points that would have overwritten to a spot nearby
  2993.     ' can nearby be determined by the direction of rotation  (iDirection)
  2994.     ' together with which quarter of the screen the point is in (iScreenZone)
  2995.     ' where we divide the screen up into 4 zones:
  2996.  
  2997.     ' --------------------------------------
  2998.     '|                   |                  |
  2999.     '| zone 4            | zone 1           |
  3000.     '|                   |                  |
  3001.     '|--------------------------------------|
  3002.     '|                   |                  |
  3003.     '| zone 3            | zone 2           |
  3004.     '|                   |                  |
  3005.     '|                   |                  |
  3006.     ' --------------------------------------
  3007.  
  3008.     ' in zone   rotation direction   search direction (y,x)
  3009.     ' -------   ------------------   ----------------------
  3010.     ' 1         clockwise            down + right
  3011.     ' 1         counter-clockwise    up   + left
  3012.     ' 2         clockwise            down + left
  3013.     ' 2         counter-clockwise    up   + right
  3014.     ' 3         clockwise            up   + left
  3015.     ' 3         counter-clockwise    down + right
  3016.     ' 4         clockwise            up   + right
  3017.     ' 4         counter-clockwise    down + left
  3018.  
  3019.     iMissing = 0
  3020.     For iLoop = 0 To UBound(arrLost)
  3021.         bFound = FindEmptyShearRotationPoint3%(arrLost(iLoop), iDirection, iEmpty, x, y, NewArray())
  3022.         If bFound = TRUE Then
  3023.             If m_bDebug = TRUE Then
  3024.                 _Echo "Plotted  missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3025.             End If
  3026.         Else
  3027.             iMissing = iMissing + 1
  3028.             If m_bDebug = TRUE Then
  3029.                 _Echo "Detected missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3030.             End If
  3031.         End If
  3032.     Next iLoop
  3033.  
  3034. End Sub ' ShearRotate3
  3035.  
  3036. ' /////////////////////////////////////////////////////////////////////////////
  3037. ' Looks for a new point
  3038. ' a little more accurately, using iDirection parameter
  3039. ' which can be cClockwise or cCounterClockwise.
  3040.  
  3041. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3042.  
  3043. ' Receives
  3044. ' FindMe (RotationType) = contains
  3045. '                         .origx, .origy = the starting location to start looking from,
  3046. '                         .z = which area of the screen the point is in
  3047. '                              (1=top right, 2=bottom right, 3=bottom left, 4=top left)
  3048. '                              to determine direction to look in
  3049. '                         .c = the value to write
  3050. ' iDirection (Integer) = direction of rotation, can be cClockwise or cCounterClockwise (constants must be declared globally)
  3051. ' iEmpty (Integer) = value to test against for empty
  3052. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  3053. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  3054. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  3055.  
  3056. ' Returns
  3057. ' FALSE if no empty spot was found
  3058. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  3059.  
  3060. Function FindEmptyShearRotationPoint3% (FindMe As RotationType, iDirection As Integer, iEmpty As Integer, destX As Integer, destY As Integer, NewArray() As RotationType)
  3061.     Dim bResult As Integer: bResult = FALSE
  3062.     Dim x As Integer
  3063.     Dim y As Integer
  3064.     Dim dirX As Integer
  3065.     Dim dirY As Integer
  3066.     Dim bContinue As Integer
  3067.  
  3068.     ' Initialize
  3069.     destX = 0
  3070.     destY = 0
  3071.     bContinue = TRUE
  3072.  
  3073.     ' Choose search direction based on the quadrant of the screen
  3074.     ' and the direction of rotation:
  3075.  
  3076.     ' iScreenZone   iDirection           search direction (y,x)
  3077.     ' -----------   ------------------   ----------------------
  3078.     ' 1             cClockwise           down + right ( 1, 1)
  3079.     ' 1             cCounterClockwise    up   + left  (-1,-1)
  3080.     ' 2             cClockwise           down + left  ( 1,-1)
  3081.     ' 2             cCounterClockwise    up   + right (-1, 1)
  3082.     ' 3             cClockwise           up   + left  (-1,-1)
  3083.     ' 3             cCounterClockwise    down + right ( 1, 1)
  3084.     ' 4             cClockwise           up   + right (-1, 1)
  3085.     ' 4             cCounterClockwise    down + left  ( 1,-1)
  3086.  
  3087.     If FindMe.z = 1 And iDirection = cClockwise Then
  3088.         dirY = 1
  3089.         dirX = 1
  3090.     ElseIf FindMe.z = 1 And iDirection = cCounterClockwise Then
  3091.         dirY = -1
  3092.         dirX = -1
  3093.     ElseIf FindMe.z = 2 And iDirection = cClockwise Then
  3094.         dirY = 1
  3095.         dirX = -1
  3096.     ElseIf FindMe.z = 2 And iDirection = cCounterClockwise Then
  3097.         dirY = -1
  3098.         dirX = 1
  3099.     ElseIf FindMe.z = 3 And iDirection = cClockwise Then
  3100.         dirY = -1
  3101.         dirX = -1
  3102.     ElseIf FindMe.z = 3 And iDirection = cCounterClockwise Then
  3103.         dirY = 1
  3104.         dirX = 1
  3105.     ElseIf FindMe.z = 4 And iDirection = cClockwise Then
  3106.         dirY = -1
  3107.         dirX = 1
  3108.     ElseIf FindMe.z = 4 And iDirection = cCounterClockwise Then
  3109.         dirY = 1
  3110.         dirX = -1
  3111.     Else
  3112.         bContinue = FALSE
  3113.     End If
  3114.  
  3115.     ' Quit if we're out of bounds
  3116.     If bContinue = TRUE Then
  3117.         bContinue = FALSE
  3118.         x = FindMe.origx
  3119.         y = FindMe.origy
  3120.         If x >= LBound(NewArray, 1) Then
  3121.             If x <= UBound(NewArray, 1) Then
  3122.                 If y >= LBound(NewArray, 2) Then
  3123.                     If y <= UBound(NewArray, 2) Then
  3124.                         bContinue = TRUE
  3125.                     End If
  3126.                 End If
  3127.             End If
  3128.         End If
  3129.     End If
  3130.  
  3131.     ' look along y axis for an available adjacent point
  3132.     If bContinue = TRUE Then
  3133.         destX = x
  3134.         destY = y + dirY
  3135.         If destX >= LBound(NewArray, 1) Then
  3136.             If destX <= UBound(NewArray, 1) Then
  3137.                 If destY >= LBound(NewArray, 2) Then
  3138.                     If destY <= UBound(NewArray, 2) Then
  3139.                         If NewArray(destX, destY, 0).c = iEmpty Then
  3140.                             NewArray(destX, destY, 0).c = FindMe.c
  3141.                             bResult = TRUE
  3142.                             bContinue = FALSE
  3143.                         End If
  3144.                     End If
  3145.                 End If
  3146.             End If
  3147.         End If
  3148.     End If
  3149.  
  3150.     ' look along x axis for an available adjacent point
  3151.     If bContinue = TRUE Then
  3152.         destX = x + dirX
  3153.         destY = y
  3154.         If destX >= LBound(NewArray, 1) Then
  3155.             If destX <= UBound(NewArray, 1) Then
  3156.                 If destY >= LBound(NewArray, 2) Then
  3157.                     If destY <= UBound(NewArray, 2) Then
  3158.                         If NewArray(x + dirX, y, 0).c = iEmpty Then
  3159.                             NewArray(destX, destY, 0).c = FindMe.c
  3160.                             bResult = TRUE
  3161.                             bContinue = FALSE
  3162.                         End If
  3163.                     End If
  3164.                 End If
  3165.             End If
  3166.         End If
  3167.     End If
  3168.  
  3169.     ' look diagonally for an available adjacent point
  3170.     If bContinue = TRUE Then
  3171.         destX = x + dirX
  3172.         destY = y + dirY
  3173.         If destX >= LBound(NewArray, 1) Then
  3174.             If destX <= UBound(NewArray, 1) Then
  3175.                 If destY >= LBound(NewArray, 2) Then
  3176.                     If destY <= UBound(NewArray, 2) Then
  3177.                         If NewArray(x + dirX, y + dirY, 0).c = iEmpty Then
  3178.                             NewArray(destX, destY, 0).c = FindMe.c
  3179.                             bResult = TRUE
  3180.                             bContinue = FALSE
  3181.                         End If
  3182.                     End If
  3183.                 End If
  3184.             End If
  3185.         End If
  3186.     End If
  3187.  
  3188.     ' Return result
  3189.     FindEmptyShearRotationPoint3% = bResult
  3190. End Function ' FindEmptyShearRotationPoint3%
  3191.  
  3192. ' /////////////////////////////////////////////////////////////////////////////
  3193. ' Receives parameter sMap
  3194. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3195.  
  3196. ' e.g. ShearRotate3Test1 TestSprite1$
  3197.  
  3198. Sub ShearRotate3Test1 (sMap As String)
  3199.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3200.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3201.     'Dim sMap As String
  3202.     Dim D As Integer
  3203.     Dim D1 As Integer
  3204.     Dim in$
  3205.     Dim bFinished As Integer
  3206.     Dim iMissing As Integer
  3207.  
  3208.     ' GET A SHAPE TO BE ROTATED
  3209.     Cls
  3210.     Print "3 shear rotation based on code by leopardpm"
  3211.     'sMap = TestSprite1$
  3212.  
  3213.     ' CONVERT SHAPE TO ARRAY
  3214.     StringToRotationArray RoArray1(), sMap, "."
  3215.  
  3216.     ' GET START ANGLE
  3217.     D = 0
  3218.     Print
  3219.     Print "Rotated by " + cstr$(D) + " degrees:"
  3220.     Print RotationArrayToStringTest(RoArray1())
  3221.     Print
  3222.     Print "Type an angle (-360 to 360) to rotate to, "
  3223.     Print "or blank to increase by 1 degree, or q to quit."
  3224.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3225.     Print "Hold down <ENTER> to rotate continually."
  3226.     Input "Angle (q to quit)? ", in$
  3227.     If Len(in$) > 0 Then
  3228.         If IsNum%(in$) Then
  3229.             D1 = Val(in$)
  3230.         Else
  3231.             D1 = -500
  3232.         End If
  3233.     Else
  3234.         D1 = 1
  3235.     End If
  3236.  
  3237.     ' ROTATE TO EACH ANGLE
  3238.     If D1 >= -360 And D1 <= 360 Then
  3239.         bFinished = FALSE
  3240.         Do
  3241.             ' ROTATE CLOCKWISE
  3242.             For D = D1 To 360
  3243.                 Cls
  3244.  
  3245.                 ShearRotate3 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  3246.                 Print
  3247.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3248.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3249.  
  3250.                 Print RotationArrayToStringTest(RoArray2())
  3251.                 Print
  3252.  
  3253.                 Print "Type an angle (-360 to 360) to rotate to, "
  3254.                 Print "or blank to increase by 1 degree, or q to quit."
  3255.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3256.                 Print "Hold down <ENTER> to rotate continually."
  3257.                 Input "Angle (q to quit)? ", in$
  3258.                 If Len(in$) > 0 Then
  3259.                     If IsNum%(in$) Then
  3260.                         D = Val(in$)
  3261.                         If D >= 0 And D <= 360 Then
  3262.                             D = D - 1
  3263.                         Else
  3264.                             bFinished = TRUE
  3265.                             Exit For
  3266.                         End If
  3267.                     Else
  3268.                         bFinished = TRUE
  3269.                         Exit For
  3270.                     End If
  3271.                 End If
  3272.             Next D
  3273.             If bFinished = TRUE Then Exit Do
  3274.  
  3275.             ' ROTATE COUNTER-CLOCKWISE
  3276.             For D = 360 To D1 Step -1
  3277.                 Cls
  3278.                 ShearRotate3 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  3279.                 Print
  3280.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3281.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3282.  
  3283.                 Print RotationArrayToStringTest(RoArray2())
  3284.                 Print
  3285.  
  3286.                 Print "Type an angle (0 to 360) to rotate to, "
  3287.                 Print "or blank to increase by 1 degree, or q to quit."
  3288.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3289.                 Print "Hold down <ENTER> to rotate continually."
  3290.                 Input "Angle (q to quit)? ", in$
  3291.                 If Len(in$) > 0 Then
  3292.                     If IsNum%(in$) Then
  3293.                         D = Val(in$)
  3294.                         If D >= 0 And D <= 360 Then
  3295.                             D = D + 1
  3296.                         Else
  3297.                             bFinished = TRUE
  3298.                             Exit For
  3299.                         End If
  3300.                     Else
  3301.                         bFinished = TRUE
  3302.                         Exit For
  3303.                     End If
  3304.                 End If
  3305.             Next D
  3306.             If bFinished = TRUE Then Exit Do
  3307.         Loop
  3308.     End If
  3309. End Sub ' ShearRotate3Test1
  3310.  
  3311. ' /////////////////////////////////////////////////////////////////////////////
  3312. ' ShearRotate v4
  3313.  
  3314. ' Tries to fix the problem of 2 points resolving to the same coordinate
  3315. ' (one overwrites the other, which becomes "lost")
  3316. ' using a different approach, by just looking at the problem angles:
  3317. ' 30, 60, 120, 150, 210, 240, 300, 330 degrees
  3318.  
  3319. ' (which can be cClockwise or cCounterClockwise)
  3320. ' together with which quarter of the screen the point is in,
  3321.  
  3322. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3323.  
  3324. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  3325.  
  3326. Sub ShearRotate4 ( _
  3327.     OldArray() As RotationType, _
  3328.     NewArray() As RotationType, _
  3329.     angle1 As Integer, _
  3330.     iDirection As Integer, _
  3331.     iEmpty As Integer, _
  3332.     iMissing As Integer)
  3333.  
  3334.     Const Pi = 4 * Atn(1)
  3335.  
  3336.     Dim angle As Integer
  3337.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  3338.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  3339.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  3340.     Dim x As Integer
  3341.     Dim y As Integer
  3342.     Dim nangle As Integer
  3343.     Dim nx As Integer
  3344.     Dim ny As Integer
  3345.     Dim flipper As Integer
  3346.     Dim rotr As Double
  3347.     Dim shear1 As Double
  3348.     Dim shear2 As Double
  3349.     Dim clr As Integer
  3350.     Dim y1 As _Byte
  3351.     Dim xy1 As _Byte
  3352.     Dim fy As _Byte
  3353.     Dim fx As _Byte
  3354.     Dim in$
  3355.     Dim sLine As String
  3356.     ReDim arrLost(-1) As RotationType
  3357.     Dim iLoop As Integer
  3358.     Dim bFound As Integer
  3359.     Dim iScreenZone As Integer
  3360.     Dim iMidX As Integer
  3361.     Dim iMidY As Integer
  3362.  
  3363.     ' initialize new with empty
  3364.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3365.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3366.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3367.             NewArray(x, y, 0).origx = x
  3368.             NewArray(x, y, 0).origy = y
  3369.             NewArray(x, y, 0).c = iEmpty
  3370.         Next y
  3371.     Next x
  3372.  
  3373.     ' find midpoints
  3374.     iMidX = (UBound(OldArray, 1) - LBound(OldArray, 1)) / 2
  3375.     iMidY = (UBound(OldArray, 2) - LBound(OldArray, 2)) / 2
  3376.  
  3377.     ' angle is reversed
  3378.     angle = 360 - angle1
  3379.  
  3380.     ' Shearing each element 3 times in one shot
  3381.     nangle = angle
  3382.  
  3383.     ' this pre-processing portion basically rotates by 90 to get
  3384.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  3385.     If angle > 45 And angle < 225 Then
  3386.         If angle < 135 Then
  3387.             nangle = angle - 90
  3388.         Else
  3389.             nangle = angle - 180
  3390.         End If
  3391.     End If
  3392.     If angle > 135 And angle < 315 Then
  3393.         If angle < 225 Then
  3394.             nangle = angle - 180
  3395.         Else
  3396.             nangle = angle - 270
  3397.         End If
  3398.     End If
  3399.     If nangle < 0 Then
  3400.         nangle = nangle + 360
  3401.     End If
  3402.     If nangle > 359 Then
  3403.         nangle = nangle - 360
  3404.     End If
  3405.  
  3406.     rotr = nangle * DtoR
  3407.     shear1 = Tan(rotr / 2) ' correct way
  3408.     shear2 = Sin(rotr)
  3409.  
  3410.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  3411.     ' ***       all resolve to -45 degrees.
  3412.     ' ***       Fixed by changing < to <=
  3413.  
  3414.     'if angle >  45 and angle < 134 then
  3415.     If angle > 45 And angle <= 134 Then
  3416.         flipper = 1
  3417.     ElseIf angle > 134 And angle <= 224 Then
  3418.         flipper = 2
  3419.     ElseIf angle > 224 And angle <= 314 Then
  3420.         ' *** NOTE: this had a bug where this flipper was wrong
  3421.         '           Fixed by adding case 7
  3422.         'flipper = 3
  3423.         flipper = 7
  3424.     Else
  3425.         flipper = 0
  3426.     End If
  3427.  
  3428.     ' Here is where it needs some optimizing possibly... kinda slow...
  3429.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3430.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3431.  
  3432.             ' find which part of screen the current point is in
  3433.             If y > iMidY Then
  3434.                 ' bottom half of screen
  3435.                 If x > iMidX Then
  3436.                     ' right half of screen
  3437.                     iScreenZone = 2
  3438.                 Else
  3439.                     ' left half of screen
  3440.                     iScreenZone = 3
  3441.                 End If
  3442.             Else
  3443.                 ' top half of screen
  3444.                 If x > iMidX Then
  3445.                     ' right half of screen
  3446.                     iScreenZone = 1
  3447.                 Else
  3448.                     ' left half of screen
  3449.                     iScreenZone = 4
  3450.                 End If
  3451.             End If
  3452.  
  3453.             ' calculate directions
  3454.             Select Case flipper
  3455.                 Case 1:
  3456.                     nx = -y
  3457.                     ny = x
  3458.                 Case 2:
  3459.                     nx = -x
  3460.                     ny = -y
  3461.                 Case 3:
  3462.                     nx = -y
  3463.                     ny = -x
  3464.                 Case 4:
  3465.                     nx = -x
  3466.                     ny = y
  3467.                 Case 5:
  3468.                     nx = x
  3469.                     ny = -y
  3470.                 Case 6:
  3471.                     nx = y
  3472.                     ny = x
  3473.                 Case 7:
  3474.                     nx = y
  3475.                     ny = -x
  3476.                 Case Else:
  3477.                     nx = x
  3478.                     ny = y
  3479.             End Select
  3480.  
  3481.             clr = OldArray(nx, ny, 0).c
  3482.  
  3483.             y1 = y * shear1
  3484.             xy1 = x + y1
  3485.             fy = (y - xy1 * shear2)
  3486.             fx = xy1 + fy * shear1
  3487.  
  3488.             If fx >= -16 And fx <= 16 Then
  3489.                 If fy >= -16 And fy <= 16 Then
  3490.                     ' only draw here if this spot is empty
  3491.                     If NewArray(fx, fy, 0).c = iEmpty Then
  3492.                         NewArray(fx, fy, 0).c = clr
  3493.                         NewArray(fx, fy, 0).origx = fx
  3494.                         NewArray(fx, fy, 0).origy = fy
  3495.                     Else
  3496.                         ' don't draw, but save it to a list to handle later
  3497.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  3498.                         arrLost(UBound(arrLost)).c = clr
  3499.                         arrLost(UBound(arrLost)).origx = fx
  3500.                         arrLost(UBound(arrLost)).origy = fy
  3501.  
  3502.                         ' preserve which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  3503.                         arrLost(UBound(arrLost)).z = iScreenZone
  3504.                     End If
  3505.                 End If
  3506.             End If
  3507.         Next x
  3508.     Next y
  3509.  
  3510.     ' try to place any points that would have overwritten to a spot nearby
  3511.     ' can nearby be determined by the direction of rotation  (iDirection)
  3512.     ' together with which quarter of the screen the point is in (iScreenZone)
  3513.     ' where we divide the screen up into 4 zones:
  3514.  
  3515.     ' --------------------------------------
  3516.     '|                   |                  |
  3517.     '| zone 4            | zone 1           |
  3518.     '|                   |                  |
  3519.     '|--------------------------------------|
  3520.     '|                   |                  |
  3521.     '| zone 3            | zone 2           |
  3522.     '|                   |                  |
  3523.     '|                   |                  |
  3524.     ' --------------------------------------
  3525.  
  3526.     ' in zone   rotation direction   search direction (y,x)
  3527.     ' -------   ------------------   ----------------------
  3528.     ' 1         clockwise            down + right
  3529.     ' 1         counter-clockwise    up   + left
  3530.     ' 2         clockwise            down + left
  3531.     ' 2         counter-clockwise    up   + right
  3532.     ' 3         clockwise            up   + left
  3533.     ' 3         counter-clockwise    down + right
  3534.     ' 4         clockwise            up   + right
  3535.     ' 4         counter-clockwise    down + left
  3536.  
  3537.     If IsProblemAngle%(angle1) Then
  3538.         iMissing = 0
  3539.         For iLoop = 0 To UBound(arrLost)
  3540.             bFound = FindEmptyShearRotationPoint4%(arrLost(iLoop), iDirection, iEmpty, x, y, NewArray())
  3541.             If bFound = TRUE Then
  3542.                 If m_bDebug = TRUE Then
  3543.                     _Echo "Plotted  missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3544.                 End If
  3545.             Else
  3546.                 iMissing = iMissing + 1
  3547.                 If m_bDebug = TRUE Then
  3548.                     _Echo "Detected missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3549.                 End If
  3550.             End If
  3551.         Next iLoop
  3552.     End If
  3553. End Sub ' ShearRotate4
  3554.  
  3555. ' /////////////////////////////////////////////////////////////////////////////
  3556. ' Returns TRUE if angle is any of
  3557. ' 30, 60, 120, 150, 210, 240, 300, 330
  3558.  
  3559. ' div: int1% = num1% \ den1%
  3560. ' mod: rem1% = num1% MOD den1%
  3561.  
  3562. Function IsProblemAngle% (angle As Integer)
  3563.     Dim bResult As Integer: bResult = FALSE
  3564.     Dim i%
  3565.     For i% = 0 To 360 Step 30
  3566.         If i% Mod 90 <> 0 Then
  3567.             If angle = i% Then
  3568.                 bResult = TRUE
  3569.                 Exit For
  3570.             End If
  3571.         End If
  3572.     Next i%
  3573.     IsProblemAngle% = bResult
  3574. End Function ' IsProblemAngle%
  3575.  
  3576. ' /////////////////////////////////////////////////////////////////////////////
  3577. ' Looks for a new point
  3578. ' a little more accurately, using iDirection parameter
  3579. ' which can be cClockwise or cCounterClockwise.
  3580.  
  3581. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3582.  
  3583. ' Receives
  3584. ' FindMe (RotationType) = contains
  3585. '                         .origx, .origy = the starting location to start looking from,
  3586. '                         .z = which area of the screen the point is in
  3587. '                              (1=top right, 2=bottom right, 3=bottom left, 4=top left)
  3588. '                              to determine direction to look in
  3589. '                         .c = the value to write
  3590. ' iDirection (Integer) = direction of rotation, can be cClockwise or cCounterClockwise (constants must be declared globally)
  3591. ' iEmpty (Integer) = value to test against for empty
  3592. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  3593. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  3594. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  3595.  
  3596. ' Returns
  3597. ' FALSE if no empty spot was found
  3598. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  3599.  
  3600. Function FindEmptyShearRotationPoint4% (FindMe As RotationType, iDirection As Integer, iEmpty As Integer, destX As Integer, destY As Integer, NewArray() As RotationType)
  3601.     Dim bResult As Integer: bResult = FALSE
  3602.     Dim x As Integer
  3603.     Dim y As Integer
  3604.     Dim dirX As Integer
  3605.     Dim dirY As Integer
  3606.     Dim bContinue As Integer
  3607.  
  3608.     ' Initialize
  3609.     destX = 0
  3610.     destY = 0
  3611.     bContinue = TRUE
  3612.  
  3613.     ' Choose search direction based on the quadrant of the screen
  3614.     ' and the direction of rotation:
  3615.  
  3616.     ' iScreenZone   iDirection           search direction (y,x)
  3617.     ' -----------   ------------------   ----------------------
  3618.     ' 1             cClockwise           down + right ( 1, 1)
  3619.     ' 1             cCounterClockwise    up   + left  (-1,-1)
  3620.     ' 2             cClockwise           down + left  ( 1,-1)
  3621.     ' 2             cCounterClockwise    up   + right (-1, 1)
  3622.     ' 3             cClockwise           up   + left  (-1,-1)
  3623.     ' 3             cCounterClockwise    down + right ( 1, 1)
  3624.     ' 4             cClockwise           up   + right (-1, 1)
  3625.     ' 4             cCounterClockwise    down + left  ( 1,-1)
  3626.  
  3627.     If FindMe.z = 1 And iDirection = cClockwise Then
  3628.         dirY = 1
  3629.         dirX = 1
  3630.     ElseIf FindMe.z = 1 And iDirection = cCounterClockwise Then
  3631.         dirY = -1
  3632.         dirX = -1
  3633.     ElseIf FindMe.z = 2 And iDirection = cClockwise Then
  3634.         dirY = 1
  3635.         dirX = -1
  3636.     ElseIf FindMe.z = 2 And iDirection = cCounterClockwise Then
  3637.         dirY = -1
  3638.         dirX = 1
  3639.     ElseIf FindMe.z = 3 And iDirection = cClockwise Then
  3640.         dirY = -1
  3641.         dirX = -1
  3642.     ElseIf FindMe.z = 3 And iDirection = cCounterClockwise Then
  3643.         dirY = 1
  3644.         dirX = 1
  3645.     ElseIf FindMe.z = 4 And iDirection = cClockwise Then
  3646.         dirY = -1
  3647.         dirX = 1
  3648.     ElseIf FindMe.z = 4 And iDirection = cCounterClockwise Then
  3649.         dirY = 1
  3650.         dirX = -1
  3651.     Else
  3652.         bContinue = FALSE
  3653.     End If
  3654.  
  3655.     ' Quit if we're out of bounds
  3656.     If bContinue = TRUE Then
  3657.         bContinue = FALSE
  3658.         x = FindMe.origx
  3659.         y = FindMe.origy
  3660.         If x >= LBound(NewArray, 1) Then
  3661.             If x <= UBound(NewArray, 1) Then
  3662.                 If y >= LBound(NewArray, 2) Then
  3663.                     If y <= UBound(NewArray, 2) Then
  3664.                         bContinue = TRUE
  3665.                     End If
  3666.                 End If
  3667.             End If
  3668.         End If
  3669.     End If
  3670.  
  3671.     ' look along y axis for an available adjacent point
  3672.     If bContinue = TRUE Then
  3673.         destX = x
  3674.         destY = y + dirY
  3675.         If destX >= LBound(NewArray, 1) Then
  3676.             If destX <= UBound(NewArray, 1) Then
  3677.                 If destY >= LBound(NewArray, 2) Then
  3678.                     If destY <= UBound(NewArray, 2) Then
  3679.                         If NewArray(destX, destY, 0).c = iEmpty Then
  3680.                             NewArray(destX, destY, 0).c = FindMe.c
  3681.                             bResult = TRUE
  3682.                             bContinue = FALSE
  3683.                         End If
  3684.                     End If
  3685.                 End If
  3686.             End If
  3687.         End If
  3688.     End If
  3689.  
  3690.     ' look along x axis for an available adjacent point
  3691.     If bContinue = TRUE Then
  3692.         destX = x + dirX
  3693.         destY = y
  3694.         If destX >= LBound(NewArray, 1) Then
  3695.             If destX <= UBound(NewArray, 1) Then
  3696.                 If destY >= LBound(NewArray, 2) Then
  3697.                     If destY <= UBound(NewArray, 2) Then
  3698.                         If NewArray(x + dirX, y, 0).c = iEmpty Then
  3699.                             NewArray(destX, destY, 0).c = FindMe.c
  3700.                             bResult = TRUE
  3701.                             bContinue = FALSE
  3702.                         End If
  3703.                     End If
  3704.                 End If
  3705.             End If
  3706.         End If
  3707.     End If
  3708.  
  3709.     ' look diagonally for an available adjacent point
  3710.     If bContinue = TRUE Then
  3711.         destX = x + dirX
  3712.         destY = y + dirY
  3713.         If destX >= LBound(NewArray, 1) Then
  3714.             If destX <= UBound(NewArray, 1) Then
  3715.                 If destY >= LBound(NewArray, 2) Then
  3716.                     If destY <= UBound(NewArray, 2) Then
  3717.                         If NewArray(x + dirX, y + dirY, 0).c = iEmpty Then
  3718.                             NewArray(destX, destY, 0).c = FindMe.c
  3719.                             bResult = TRUE
  3720.                             bContinue = FALSE
  3721.                         End If
  3722.                     End If
  3723.                 End If
  3724.             End If
  3725.         End If
  3726.     End If
  3727.  
  3728.     '   ' look (in the opposite direction) along y axis for an available adjacent point
  3729.     '   If bContinue = TRUE Then
  3730.     '       destX = x
  3731.     '       destY = y - dirY
  3732.     '       if destX >= LBound(NewArray, 1) then
  3733.     '           if destX <= UBound(NewArray, 1) then
  3734.     '               if destY >= LBound(NewArray, 2) then
  3735.     '                   if destY <= UBound(NewArray, 2) then
  3736.     '                       if NewArray(destX, destY, 0).c = iEmpty then
  3737.     '                           NewArray(destX, destY, 0).c = FindMe.c
  3738.     '                           bResult = TRUE
  3739.     '                           bContinue = FALSE
  3740.     '                       end if
  3741.     '                   end if
  3742.     '               end if
  3743.     '           end if
  3744.     '       end if
  3745.     '   end if
  3746.     '
  3747.     '   ' look (in the opposite direction) along x axis for an available adjacent point
  3748.     '   If bContinue = TRUE Then
  3749.     '       destX = x - dirX
  3750.     '       destY = y
  3751.     '       if destX >= LBound(NewArray, 1) then
  3752.     '           if destX <= UBound(NewArray, 1) then
  3753.     '               if destY >= LBound(NewArray, 2) then
  3754.     '                   if destY <= UBound(NewArray, 2) then
  3755.     '                       if NewArray(x + dirX, y, 0).c = iEmpty then
  3756.     '                           NewArray(destX, destY, 0).c = FindMe.c
  3757.     '                           bResult = TRUE
  3758.     '                           bContinue = FALSE
  3759.     '                       end if
  3760.     '                   end if
  3761.     '               end if
  3762.     '           end if
  3763.     '       end if
  3764.     '   end if
  3765.     '
  3766.     '   ' look (in the opposite direction) diagonally for an available adjacent point
  3767.     '   If bContinue = TRUE Then
  3768.     '       destX = x - dirX
  3769.     '       destY = y - dirY
  3770.     '       if destX >= LBound(NewArray, 1) then
  3771.     '           if destX <= UBound(NewArray, 1) then
  3772.     '               if destY >= LBound(NewArray, 2) then
  3773.     '                   if destY <= UBound(NewArray, 2) then
  3774.     '                       if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  3775.     '                           NewArray(destX, destY, 0).c = FindMe.c
  3776.     '                           bResult = TRUE
  3777.     '                           bContinue = FALSE
  3778.     '                       end if
  3779.     '                   end if
  3780.     '               end if
  3781.     '           end if
  3782.     '       end if
  3783.     '    End If
  3784.  
  3785.     ' Return result
  3786.     FindEmptyShearRotationPoint4% = bResult
  3787. End Function ' FindEmptyShearRotationPoint4%
  3788.  
  3789. ' /////////////////////////////////////////////////////////////////////////////
  3790. ' Tries to correct for missing points with improved logic v3
  3791.  
  3792. ' Receives parameter sMap
  3793. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3794.  
  3795. ' e.g. ShearRotate4Test1 TestSprite1$
  3796.  
  3797. Sub ShearRotate4Test1 (sMap As String)
  3798.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3799.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3800.     'Dim sMap As String
  3801.     Dim D As Integer
  3802.     Dim D1 As Integer
  3803.     Dim in$
  3804.     Dim bFinished As Integer
  3805.     Dim iMissing As Integer
  3806.  
  3807.     ' GET A SHAPE TO BE ROTATED
  3808.     Cls
  3809.     Print "3 shear rotation based on code by leopardpm"
  3810.     'sMap = TestSprite1$
  3811.  
  3812.     ' CONVERT SHAPE TO ARRAY
  3813.     StringToRotationArray RoArray1(), sMap, "."
  3814.  
  3815.     ' GET START ANGLE
  3816.     D = 0
  3817.     Print
  3818.     Print "Rotated by " + cstr$(D) + " degrees:"
  3819.     Print RotationArrayToStringTest(RoArray1())
  3820.     Print
  3821.     Print "Type an angle (-360 to 360) to rotate to, "
  3822.     Print "or blank to increase by 1 degree, or q to quit."
  3823.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3824.     Print "Hold down <ENTER> to rotate continually."
  3825.     Input "Angle (q to quit)? ", in$
  3826.     If Len(in$) > 0 Then
  3827.         If IsNum%(in$) Then
  3828.             D1 = Val(in$)
  3829.         Else
  3830.             D1 = -500
  3831.         End If
  3832.     Else
  3833.         D1 = 1
  3834.     End If
  3835.  
  3836.     ' ROTATE TO EACH ANGLE
  3837.     If D1 >= -360 And D1 <= 360 Then
  3838.         bFinished = FALSE
  3839.         Do
  3840.             ' ROTATE CLOCKWISE
  3841.             For D = D1 To 360
  3842.                 Cls
  3843.  
  3844.                 ShearRotate4 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  3845.                 Print
  3846.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3847.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3848.  
  3849.                 Print RotationArrayToStringTest(RoArray2())
  3850.                 Print
  3851.  
  3852.                 Print "Type an angle (-360 to 360) to rotate to, "
  3853.                 Print "or blank to increase by 1 degree, or q to quit."
  3854.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3855.                 Print "Hold down <ENTER> to rotate continually."
  3856.                 Input "Angle (q to quit)? ", in$
  3857.                 If Len(in$) > 0 Then
  3858.                     If IsNum%(in$) Then
  3859.                         D = Val(in$)
  3860.                         If D >= 0 And D <= 360 Then
  3861.                             D = D - 1
  3862.                         Else
  3863.                             bFinished = TRUE
  3864.                             Exit For
  3865.                         End If
  3866.                     Else
  3867.                         bFinished = TRUE
  3868.                         Exit For
  3869.                     End If
  3870.                 End If
  3871.             Next D
  3872.             If bFinished = TRUE Then Exit Do
  3873.  
  3874.             ' ROTATE COUNTER-CLOCKWISE
  3875.             For D = 360 To D1 Step -1
  3876.                 Cls
  3877.                 ShearRotate4 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  3878.                 Print
  3879.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3880.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3881.  
  3882.                 Print RotationArrayToStringTest(RoArray2())
  3883.                 Print
  3884.  
  3885.                 Print "Type an angle (0 to 360) to rotate to, "
  3886.                 Print "or blank to increase by 1 degree, or q to quit."
  3887.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3888.                 Print "Hold down <ENTER> to rotate continually."
  3889.                 Input "Angle (q to quit)? ", in$
  3890.                 If Len(in$) > 0 Then
  3891.                     If IsNum%(in$) Then
  3892.                         D = Val(in$)
  3893.                         If D >= 0 And D <= 360 Then
  3894.                             D = D + 1
  3895.                         Else
  3896.                             bFinished = TRUE
  3897.                             Exit For
  3898.                         End If
  3899.                     Else
  3900.                         bFinished = TRUE
  3901.                         Exit For
  3902.                     End If
  3903.                 End If
  3904.             Next D
  3905.             If bFinished = TRUE Then Exit Do
  3906.         Loop
  3907.     End If
  3908. End Sub ' ShearRotate4Test1
  3909.  
  3910. ' /////////////////////////////////////////////////////////////////////////////
  3911. ' Correct for overwriting points issue
  3912. ' (happens at 30, 60, 120, 150, 210, 240, 300, 330 degrees)
  3913. ' using STxAxTIC's method of merging array rotated to angle-1 and angle+1
  3914.  
  3915. Sub ShearRotate5 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  3916.     ReDim arrCW(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3917.     ReDim arrCCW(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3918.  
  3919.     ' If rotation is 30, 60, 120, 150, 210, 240, 300, 330 degrees
  3920.     ' then try correcting for overwriting.
  3921.     If IsProblemAngle%(angle1) Then
  3922.         ' get array rotated to angle-1
  3923.         ShearRotate OldArray(), arrCW(), angle1 - 1, iEmpty
  3924.  
  3925.         ' get array rotated to angle
  3926.         ShearRotate OldArray(), NewArray(), angle1 - 1, iEmpty
  3927.  
  3928.         ' get array rotated to angle=1
  3929.         ShearRotate OldArray(), arrCCW(), angle1 + 1, iEmpty
  3930.  
  3931.         ' merge the results
  3932.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3933.             For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3934.                 ' is point empty?
  3935.                 If NewArray(x, y, 0).c = iEmpty Then
  3936.                     ' see if point is occupied 1 deg. counter-clockwise
  3937.                     If arrCCW(x, y, 0).c <> iEmpty Then
  3938.                         NewArray(x, y, 0).c = arrCCW(x, y, 0).c
  3939.                         ' see if point is occupied 1 deg. clockwise
  3940.                     ElseIf arrCW(x, y, 0).c <> iEmpty Then
  3941.                         NewArray(x, y, 0).c = arrCW(x, y, 0).c
  3942.                     End If
  3943.                 End If
  3944.             Next y
  3945.         Next x
  3946.         ' Otherwise rotate without correcting.
  3947.     Else
  3948.         ShearRotate OldArray(), NewArray(), angle1, iEmpty
  3949.     End If
  3950. End Sub ' ShearRotate5
  3951.  
  3952. ' /////////////////////////////////////////////////////////////////////////////
  3953. ' Tries to correct for missing (overwritten) points
  3954. ' using STxAxTIC's method to correct for overwritten points
  3955.  
  3956. ' Receives parameter sMap
  3957. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3958.  
  3959. ' e.g. ShearRotate5Test1 TestSprite1$
  3960.  
  3961. Sub ShearRotate5Test1 (sMap As String)
  3962.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3963.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3964.     'Dim sMap As String
  3965.     Dim D As Integer
  3966.     Dim D1 As Integer
  3967.     Dim in$
  3968.     Dim bFinished As Integer
  3969.     'Dim iMissing As Integer
  3970.  
  3971.     ' GET A SHAPE TO BE ROTATED
  3972.     Cls
  3973.     Print "3 shear rotation based on code by leopardpm"
  3974.     Print "using STxAxTIC's method to correct for overwritten points"
  3975.     'sMap = TestSprite1$
  3976.  
  3977.     ' CONVERT SHAPE TO ARRAY
  3978.     StringToRotationArray RoArray1(), sMap, "."
  3979.  
  3980.     ' GET START ANGLE
  3981.     D = 0
  3982.     Print
  3983.     Print "Rotated by " + cstr$(D) + " degrees:"
  3984.     Print RotationArrayToStringTest(RoArray1())
  3985.     Print
  3986.     Print "Type an angle (-360 to 360) to rotate to, "
  3987.     Print "or blank to increase by 1 degree, or q to quit."
  3988.     Print "Note: Tries to fix for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3989.     Print "Hold down <ENTER> to rotate continually."
  3990.     Input "Angle (q to quit)? ", in$
  3991.     If Len(in$) > 0 Then
  3992.         If IsNum%(in$) Then
  3993.             D1 = Val(in$)
  3994.         Else
  3995.             D1 = -500
  3996.         End If
  3997.     Else
  3998.         D1 = 1
  3999.     End If
  4000.  
  4001.     ' ROTATE TO EACH ANGLE
  4002.     If D1 >= -360 And D1 <= 360 Then
  4003.         bFinished = FALSE
  4004.         Do
  4005.             ' ROTATE CLOCKWISE
  4006.             For D = D1 To 360
  4007.                 Cls
  4008.  
  4009.                 'ShearRotate4 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  4010.                 ShearRotate5 RoArray1(), RoArray2(), D, Asc(".")
  4011.                 Print
  4012.                 Print "Rotated by " + cstr$(D) + " degrees:"
  4013.                 'Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  4014.  
  4015.                 Print RotationArrayToStringTest(RoArray2())
  4016.                 Print
  4017.  
  4018.                 Print "Type an angle (-360 to 360) to rotate to, "
  4019.                 Print "or blank to increase by 1 degree, or q to quit."
  4020.                 Print "Note: Tries to fix for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4021.                 Print "Hold down <ENTER> to rotate continually."
  4022.                 Input "Angle (q to quit)? ", in$
  4023.                 If Len(in$) > 0 Then
  4024.                     If IsNum%(in$) Then
  4025.                         D = Val(in$)
  4026.                         If D >= 0 And D <= 360 Then
  4027.                             D = D - 1
  4028.                         Else
  4029.                             bFinished = TRUE
  4030.                             Exit For
  4031.                         End If
  4032.                     Else
  4033.                         bFinished = TRUE
  4034.                         Exit For
  4035.                     End If
  4036.                 End If
  4037.             Next D
  4038.             If bFinished = TRUE Then Exit Do
  4039.  
  4040.             ' ROTATE COUNTER-CLOCKWISE
  4041.             For D = 360 To D1 Step -1
  4042.                 Cls
  4043.                 'ShearRotate4 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  4044.                 ShearRotate5 RoArray1(), RoArray2(), D, Asc(".")
  4045.                 Print
  4046.                 Print "Rotated by " + cstr$(D) + " degrees:"
  4047.                 'Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  4048.  
  4049.                 Print RotationArrayToStringTest(RoArray2())
  4050.                 Print
  4051.  
  4052.                 Print "Type an angle (0 to 360) to rotate to, "
  4053.                 Print "or blank to increase by 1 degree, or q to quit."
  4054.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4055.                 Print "Hold down <ENTER> to rotate continually."
  4056.                 Input "Angle (q to quit)? ", in$
  4057.                 If Len(in$) > 0 Then
  4058.                     If IsNum%(in$) Then
  4059.                         D = Val(in$)
  4060.                         If D >= 0 And D <= 360 Then
  4061.                             D = D + 1
  4062.                         Else
  4063.                             bFinished = TRUE
  4064.                             Exit For
  4065.                         End If
  4066.                     Else
  4067.                         bFinished = TRUE
  4068.                         Exit For
  4069.                     End If
  4070.                 End If
  4071.             Next D
  4072.             If bFinished = TRUE Then Exit Do
  4073.         Loop
  4074.     End If
  4075. End Sub ' ShearRotate5Test1
  4076.  
  4077. ' /////////////////////////////////////////////////////////////////////////////
  4078.  
  4079. Sub GetRotationMaskTest
  4080.     Dim RoutineName As String: RoutineName = "GetRotationMaskTest"
  4081.     ReDim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  4082.     'ReDim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  4083.     ReDim arrMaskIndex(-1) As Integer
  4084.     ReDim arrMasks(-1, -1, -1) As RotationType
  4085.     Dim iLoop%
  4086.     Dim x As Integer
  4087.     Dim y As Integer
  4088.     Dim sLine As String
  4089.     Dim iIndex%
  4090.     Dim in$
  4091.  
  4092.     Width 180, 100
  4093.  
  4094.     ' Get index
  4095.     GetMaskIndex arrMaskIndex()
  4096.  
  4097.     Cls
  4098.     Print "Contents of arrMaskIndex:"
  4099.     For iLoop% = LBound(arrMaskIndex) To UBound(arrMaskIndex)
  4100.         If arrMaskIndex(iLoop%) > 0 Then
  4101.             Print "arrMaskIndex(" + cstr$(iLoop%) + ") = " + cstr$(arrMaskIndex(iLoop%))
  4102.         End If
  4103.     Next iLoop%
  4104.     Print
  4105.     Input "PRESS <ENTER> TO CONTINUE OR q TO QUIT"; in$
  4106.     If in$ = "q" Then GoTo CleanupAndExit
  4107.  
  4108.     ' Get rotation masks
  4109.     GetRotationMasks RoArray1(), arrMasks()
  4110.  
  4111.     ' Show unrotated mask
  4112.     Cls
  4113.     Print "Unrotated mask:"
  4114.     iIndex% = 0
  4115.     For y = LBound(arrMasks, 3) To UBound(arrMasks, 3)
  4116.         sLine = ""
  4117.         For x = LBound(arrMasks, 2) To UBound(arrMasks, 2)
  4118.             sLine = sLine + IIFSTR$(Len(sLine) = 0, "", ",") + Right$("    " + cstr$(arrMasks(iIndex%, x, y).c), 4)
  4119.         Next x
  4120.         Print sLine
  4121.     Next y
  4122.     Print
  4123.     Input "PRESS <ENTER> TO CONTINUE OR q TO QUIT"; in$
  4124.     If in$ = "q" Then GoTo CleanupAndExit
  4125.  
  4126.     ' Show what we have
  4127.     For iLoop% = 0 To 360
  4128.         iIndex% = arrMaskIndex(iLoop%)
  4129.         'print "arrMaskIndex(" + cstr$(iLoop%) + ") = " + cstr$(iIndex%)
  4130.         If iIndex% > 0 Then
  4131.             Cls
  4132.             Print "arrMaskIndex(" + cstr$(iLoop%) + ") = " + cstr$(iIndex%)
  4133.             For y = LBound(arrMasks, 3) To UBound(arrMasks, 3)
  4134.                 sLine = ""
  4135.                 For x = LBound(arrMasks, 2) To UBound(arrMasks, 2)
  4136.                     sLine = sLine + IIFSTR$(Len(sLine) = 0, "", ",") + Right$("    " + cstr$(arrMasks(iIndex%, x, y).c), 4)
  4137.                 Next x
  4138.                 Print sLine
  4139.             Next y
  4140.             Print
  4141.             Input "PRESS <ENTER> TO CONTINUE OR q TO QUIT"; in$
  4142.             If in$ = "q" Then GoTo CleanupAndExit
  4143.         End If
  4144.     Next iLoop%
  4145.  
  4146.     Print
  4147.     Print RoutineName + " finished."
  4148.     Input "PRESS <ENTER> TO CONTINUE"; in$
  4149.  
  4150.     CleanupAndExit:
  4151.     'Screen 0
  4152.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  4153. End Sub ' GetRotationMaskTest
  4154.  
  4155. ' /////////////////////////////////////////////////////////////////////////////
  4156. ' Returns array with rotation masks
  4157. ' NewArray(index, x, y) of RotationType
  4158.  
  4159. Sub GetRotationMasks (OldArray() As RotationType, NewArray() As RotationType)
  4160.     ReDim arrMask(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  4161.     ReDim arrNext(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  4162.     ReDim arrMaskIndex(-1) As Integer
  4163.     Dim x As Integer
  4164.     Dim y As Integer
  4165.     Dim iValue As Integer
  4166.     Dim angle As Integer
  4167.     Dim iIndex As Integer
  4168.  
  4169.     ' Get index
  4170.     GetMaskIndex arrMaskIndex()
  4171.  
  4172.     ' Size array
  4173.     ReDim NewArray(0 To UBound(arrMaskIndex), LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2)) As RotationType
  4174.  
  4175.     ' create the original mask
  4176.     iValue = 0
  4177.     For y = LBound(OldArray, 2) To UBound(OldArray, 2)
  4178.         For x = LBound(OldArray, 1) To UBound(OldArray, 1)
  4179.             iValue = iValue + 1
  4180.             arrMask(x, y, 0).c = iValue
  4181.             arrMask(x, y, 0).origx = x
  4182.             arrMask(x, y, 0).origy = y
  4183.  
  4184.             NewArray(0, x, y).c = iValue
  4185.             NewArray(0, x, y).origx = x
  4186.             NewArray(0, x, y).origy = y
  4187.         Next x
  4188.     Next y
  4189.  
  4190.     ' create rotated masks
  4191.     For angle = 30 To 330
  4192.         ' If angle is 30, 60, 120, 150, 210, 240, 300, 330 degrees
  4193.         ' then precalculate rotation masks for angle-1, angle, angle+1
  4194.         ' and store in NewArray
  4195.         If IsProblemAngle%(angle) Then
  4196.             ' get array rotated to angle-1
  4197.             ShearRotate arrMask(), arrNext(), angle - 1, iEmpty
  4198.  
  4199.             ' copy to mask array
  4200.             iIndex = arrMaskIndex(angle - 1)
  4201.             For x = LBound(arrNext, 1) To UBound(arrNext, 1)
  4202.                 For y = LBound(arrNext, 2) To UBound(arrNext, 2)
  4203.                     NewArray(iIndex, x, y).c = arrNext(x, y, 0).c
  4204.                     NewArray(iIndex, x, y).origx = arrNext(x, y, 0).origx
  4205.                     NewArray(iIndex, x, y).origy = arrNext(x, y, 0).origy
  4206.                 Next y
  4207.             Next x
  4208.  
  4209.             ' get array rotated to angle
  4210.             ShearRotate arrMask(), arrNext(), angle, iEmpty
  4211.  
  4212.             ' copy to mask array
  4213.             iIndex = arrMaskIndex(angle)
  4214.             For x = LBound(arrNext, 1) To UBound(arrNext, 1)
  4215.                 For y = LBound(arrNext, 2) To UBound(arrNext, 2)
  4216.                     NewArray(iIndex, x, y).c = arrNext(x, y, 0).c
  4217.                     NewArray(iIndex, x, y).origx = arrNext(x, y, 0).origx
  4218.                     NewArray(iIndex, x, y).origy = arrNext(x, y, 0).origy
  4219.                 Next y
  4220.             Next x
  4221.  
  4222.             ' get array rotated to angle+1
  4223.             ShearRotate arrMask(), arrNext(), angle + 1, iEmpty
  4224.  
  4225.             ' copy to mask array
  4226.             iIndex = arrMaskIndex(angle + 1)
  4227.             For x = LBound(arrNext, 1) To UBound(arrNext, 1)
  4228.                 For y = LBound(arrNext, 2) To UBound(arrNext, 2)
  4229.                     NewArray(iIndex, x, y).c = arrNext(x, y, 0).c
  4230.                     NewArray(iIndex, x, y).origx = arrNext(x, y, 0).origx
  4231.                     NewArray(iIndex, x, y).origy = arrNext(x, y, 0).origy
  4232.                 Next y
  4233.             Next x
  4234.  
  4235.         End If
  4236.     Next angle
  4237.  
  4238. End Sub ' GetRotationMasks
  4239.  
  4240. ' /////////////////////////////////////////////////////////////////////////////
  4241. ' Returns an array 0 to 360
  4242. ' that returns the index of the mask array for the given angle
  4243. ' for looking up the mask for a given angle in the mask array
  4244. ' (a value 0 means no entry exists in the mask array)
  4245.  
  4246. ' The values that matter are:
  4247. ' arrMaskIndex( 29) = 1
  4248. ' arrMaskIndex( 30) = 2
  4249. ' arrMaskIndex( 31) = 3
  4250. ' arrMaskIndex( 59) = 4
  4251. ' arrMaskIndex( 60) = 5
  4252. ' arrMaskIndex( 61) = 6
  4253. ' arrMaskIndex(119) = 7
  4254. ' arrMaskIndex(120) = 8
  4255. ' arrMaskIndex(121) = 9
  4256. ' arrMaskIndex(149) = 10
  4257. ' arrMaskIndex(150) = 11
  4258. ' arrMaskIndex(151) = 12
  4259. ' arrMaskIndex(209) = 13
  4260. ' arrMaskIndex(210) = 14
  4261. ' arrMaskIndex(211) = 15
  4262. ' arrMaskIndex(239) = 16
  4263. ' arrMaskIndex(240) = 17
  4264. ' arrMaskIndex(241) = 18
  4265. ' arrMaskIndex(299) = 19
  4266. ' arrMaskIndex(300) = 20
  4267. ' arrMaskIndex(301) = 21
  4268. ' arrMaskIndex(329) = 22
  4269. ' arrMaskIndex(330) = 23
  4270. ' arrMaskIndex(331) = 24
  4271.  
  4272. Sub GetMaskIndex (arrMaskIndex() As Integer)
  4273.     Dim iLoop%
  4274.     Dim iCount%
  4275.     ReDim arrMaskIndex(0 To 360) As Integer
  4276.  
  4277.     iCount% = -1
  4278.  
  4279.     For iLoop% = 0 To 360
  4280.         arrMaskIndex(iLoop%) = 0
  4281.     Next iLoop%
  4282.  
  4283.     For iLoop% = 0 To 359 Step 30
  4284.         If iLoop% Mod 90 <> 0 Then
  4285.             iCount% = iCount% + 3
  4286.             arrMaskIndex(iLoop% - 1) = iCount% - 1
  4287.             arrMaskIndex(iLoop% + 0) = iCount% + 0
  4288.             arrMaskIndex(iLoop% + 1) = iCount% + 1
  4289.         End If
  4290.     Next iLoop%
  4291. End Sub ' GetMaskIndex
  4292.  
  4293. ' /////////////////////////////////////////////////////////////////////////////
  4294.  
  4295. Sub GetMaskIndexTest
  4296.     Dim in$
  4297.     Dim iLoop%
  4298.     ReDim arrMaskIndex(-1) As Integer
  4299.  
  4300.     'Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  4301.     'Width 80, 80
  4302.  
  4303.     Print "Testing GetMaskIndex"
  4304.     GetMaskIndex arrMaskIndex()
  4305.     Print
  4306.     Print "GetMaskIndex arrMaskIndex()"
  4307.     Print "    LBound(arrMaskIndex) = " + cstr$(LBound(arrmaskindex))
  4308.     Print "    UBound(arrMaskIndex) = " + cstr$(UBound(arrmaskindex))
  4309.     Print
  4310.  
  4311.     Print "Testing problem angles:"
  4312.  
  4313.     For iLoop% = 0 To 360
  4314.         If IsProblemAngle%(iLoop%) Then
  4315.             If iLoop% - 1 >= LBound(arrmaskindex) And iLoop% + 1 <= UBound(arrmaskindex) Then
  4316.                 Print "   angle-1, arrMaskIndex(" + cstr$(iLoop% - 1) + ") = " + cstr$(arrMaskIndex(iLoop% - 1))
  4317.                 Print "   angle  , arrMaskIndex(" + cstr$(iLoop% + 0) + ") = " + cstr$(arrMaskIndex(iLoop% + 0))
  4318.                 Print "   angle+1, arrMaskIndex(" + cstr$(iLoop% + 1) + ") = " + cstr$(arrMaskIndex(iLoop% + 1))
  4319.                 Print
  4320.             Else
  4321.                 Print "   angle " + cstr$(iLoop%) + "is  out of range."
  4322.                 Print
  4323.             End If
  4324.         End If
  4325.     Next iLoop%
  4326.  
  4327.     Input "PRESS <ENTER> TO CONTINUE"; in$
  4328. End Sub ' GetMaskIndexTest
  4329.  
  4330. ' /////////////////////////////////////////////////////////////////////////////
  4331.  
  4332. Function TestSprite1$
  4333.     Dim m$
  4334.     m$ = ""
  4335.     '                   11111111112222222222333
  4336.     '          12345678901234567890123456789012
  4337.     m$ = m$ + "11111111111111111111111111111111" + Chr$(13) ' 1
  4338.     m$ = m$ + "4..............................2" + Chr$(13) ' 2
  4339.     m$ = m$ + "4....##.....#######.....####...2" + Chr$(13) ' 3
  4340.     m$ = m$ + "4...####....##...###...######..2" + Chr$(13) ' 4
  4341.     m$ = m$ + "4..##..##...##...###..##....##.2" + Chr$(13) ' 5
  4342.     m$ = m$ + "4.##....##..#######...##.......2" + Chr$(13) ' 6
  4343.     m$ = m$ + "4.########..#######...##.......2" + Chr$(13) ' 7
  4344.     m$ = m$ + "4.########..##...###..##....##.2" + Chr$(13) ' 8
  4345.     m$ = m$ + "4.##....##..##...###...######..2" + Chr$(13) ' 9
  4346.     m$ = m$ + "4.##....##..#######.....####...2" + Chr$(13) ' 10
  4347.     m$ = m$ + "4..............................2" + Chr$(13) ' 11
  4348.     m$ = m$ + "4..............................2" + Chr$(13) ' 12
  4349.     m$ = m$ + "4..ABBBBBBBBBBBBBBBBBBBBBBBBC..2" + Chr$(13) ' 13
  4350.     m$ = m$ + "4..A...........EE...........C..2" + Chr$(13) ' 14
  4351.     m$ = m$ + "4..A..........FFFF..........C..2" + Chr$(13) ' 15
  4352.     m$ = m$ + "4..A.........GGGGGG.........C..2" + Chr$(13) ' 16
  4353.     m$ = m$ + "4..A........HHHHHHHH........C..2" + Chr$(13) ' 17
  4354.     m$ = m$ + "4..A.......IIIIIIIIII.......C..2" + Chr$(13) ' 18
  4355.     m$ = m$ + "4..A......JJJJJJJJJJJJ......C..2" + Chr$(13) ' 19
  4356.     m$ = m$ + "4..DDDDDDDDDDDDDDDDDDDDDDDDDC..2" + Chr$(13) ' 20
  4357.     m$ = m$ + "4..............................2" + Chr$(13) ' 21
  4358.     m$ = m$ + "4..............................2" + Chr$(13) ' 22
  4359.     m$ = m$ + "4.######....########..########.2" + Chr$(13) ' 23
  4360.     m$ = m$ + "4.#######...########..########.2" + Chr$(13) ' 24
  4361.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 25
  4362.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 26
  4363.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 27
  4364.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 28
  4365.     m$ = m$ + "4.#######...##........##.......2" + Chr$(13) ' 29
  4366.     m$ = m$ + "4.######....########..##.......2" + Chr$(13) ' 30
  4367.     m$ = m$ + "4..............................2" + Chr$(13) ' 31
  4368.     m$ = m$ + "33333333333333333333333333333332" + Chr$(13) ' 32
  4369.     TestSprite1$ = m$
  4370. End Function ' TestSprite1$
  4371.  
  4372. ' /////////////////////////////////////////////////////////////////////////////
  4373.  
  4374. Function TestSprite2$
  4375.     Dim m$
  4376.     m$ = ""
  4377.     '                   11111111112222222222333
  4378.     '          12345678901234567890123456789012
  4379.     m$ = m$ + "...............AA..............." + Chr$(13) ' 1
  4380.     m$ = m$ + "..............//BB.............." + Chr$(13) ' 2
  4381.     m$ = m$ + ".............??..CC............." + Chr$(13) ' 3
  4382.     m$ = m$ + "............==....DD............" + Chr$(13) ' 4
  4383.     m$ = m$ + "...........++......EE..........." + Chr$(13) ' 5
  4384.     m$ = m$ + "..........&&........FF.........." + Chr$(13) ' 6
  4385.     m$ = m$ + ".........zz..........GG........." + Chr$(13) ' 7
  4386.     m$ = m$ + "........yy............HH........" + Chr$(13) ' 8
  4387.     m$ = m$ + ".......xx..............II......." + Chr$(13) ' 9
  4388.     m$ = m$ + "......ww................JJ......" + Chr$(13) ' 10
  4389.     m$ = m$ + ".....vv..................KK....." + Chr$(13) ' 11
  4390.     m$ = m$ + "....uu....................LL...." + Chr$(13) ' 12
  4391.     m$ = m$ + "...tt......DDAAAAAAA.......MM..." + Chr$(13) ' 13
  4392.     m$ = m$ + "..ss.......DDAAAAAAA........NN.." + Chr$(13) ' 14
  4393.     m$ = m$ + ".rr........DD.....BB.........OO." + Chr$(13) ' 15
  4394.     m$ = m$ + "qq.........DD.....BB..........PP" + Chr$(13) ' 16
  4395.     m$ = m$ + "pp.........DD.....BB..........QQ" + Chr$(13) ' 17
  4396.     m$ = m$ + ".oo........DD.....BB.........RR." + Chr$(13) ' 18
  4397.     m$ = m$ + "..nn.......CCCCCCCBB........SS.." + Chr$(13) ' 19
  4398.     m$ = m$ + "...mm......CCCCCCCBB.......TT..." + Chr$(13) ' 20
  4399.     m$ = m$ + "....ll....................UU...." + Chr$(13) ' 21
  4400.     m$ = m$ + ".....kk..................VV....." + Chr$(13) ' 22
  4401.     m$ = m$ + "......jj................WW......" + Chr$(13) ' 23
  4402.     m$ = m$ + ".......ii..............XX......." + Chr$(13) ' 24
  4403.     m$ = m$ + "........hh............YY........" + Chr$(13) ' 25
  4404.     m$ = m$ + ".........gg..........ZZ........." + Chr$(13) ' 26
  4405.     m$ = m$ + "..........ff........@@.........." + Chr$(13) ' 27
  4406.     m$ = m$ + "...........ee......##..........." + Chr$(13) ' 28
  4407.     m$ = m$ + "............dd....$$............" + Chr$(13) ' 29
  4408.     m$ = m$ + ".............cc..%%............." + Chr$(13) ' 30
  4409.     m$ = m$ + "..............bb\\.............." + Chr$(13) ' 31
  4410.     m$ = m$ + "...............aa..............." + Chr$(13) ' 32
  4411.     TestSprite2$ = m$
  4412. End Function ' TestSprite2$
  4413.  
  4414. ' /////////////////////////////////////////////////////////////////////////////
  4415.  
  4416. Function PetrText1$
  4417.     Dim m$
  4418.     m$ = ""
  4419.     '                   11111111112222222222333
  4420.     '          12345678901234567890123456789012
  4421.     m$ = m$ + "................................" + Chr$(13) ' 1
  4422.     m$ = m$ + "................................" + Chr$(13) ' 2
  4423.     m$ = m$ + "................................" + Chr$(13) ' 3
  4424.     m$ = m$ + "................................" + Chr$(13) ' 4
  4425.     m$ = m$ + "................................" + Chr$(13) ' 5
  4426.     m$ = m$ + "................................" + Chr$(13) ' 6
  4427.     m$ = m$ + "................................" + Chr$(13) ' 7
  4428.     m$ = m$ + "................................" + Chr$(13) ' 8
  4429.     m$ = m$ + "................................" + Chr$(13) ' 9
  4430.     m$ = m$ + "................................" + Chr$(13) ' 10
  4431.     m$ = m$ + "................................" + Chr$(13) ' 11
  4432.     m$ = m$ + "................................" + Chr$(13) ' 12
  4433.     m$ = m$ + "................................" + Chr$(13) ' 13
  4434.     m$ = m$ + "................................" + Chr$(13) ' 14
  4435.     m$ = m$ + "....It's a SCREEN resolution?..." + Chr$(13) ' 15
  4436.     m$ = m$ + "................................" + Chr$(13) ' 16
  4437.     m$ = m$ + "................................" + Chr$(13) ' 17
  4438.     m$ = m$ + "................................" + Chr$(13) ' 18
  4439.     m$ = m$ + "................................" + Chr$(13) ' 19
  4440.     m$ = m$ + "................................" + Chr$(13) ' 20
  4441.     m$ = m$ + "................................" + Chr$(13) ' 21
  4442.     m$ = m$ + "................................" + Chr$(13) ' 22
  4443.     m$ = m$ + "................................" + Chr$(13) ' 23
  4444.     m$ = m$ + "................................" + Chr$(13) ' 24
  4445.     m$ = m$ + "................................" + Chr$(13) ' 25
  4446.     m$ = m$ + "................................" + Chr$(13) ' 26
  4447.     m$ = m$ + "................................" + Chr$(13) ' 27
  4448.     m$ = m$ + "................................" + Chr$(13) ' 28
  4449.     m$ = m$ + "................................" + Chr$(13) ' 29
  4450.     m$ = m$ + "................................" + Chr$(13) ' 30
  4451.     m$ = m$ + "................................" + Chr$(13) ' 31
  4452.     m$ = m$ + "................................" + Chr$(13) ' 32
  4453.     PetrText1$ = m$
  4454. End Function ' PetrText1$
  4455.  
  4456. ' /////////////////////////////////////////////////////////////////////////////
  4457.  
  4458. Function ArrayToString$ (MyArray( 1 To 32 , 1 To 32) As String)
  4459.     Dim MyString As String
  4460.     Dim iY As Integer
  4461.     Dim iX As Integer
  4462.     Dim sLine As String
  4463.     MyString = ""
  4464.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  4465.         sLine = ""
  4466.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  4467.             sLine = sLine + MyArray(iY, iX)
  4468.         Next iX
  4469.         MyString = MyString + sLine + Chr$(13)
  4470.     Next iY
  4471.     ArrayToString$ = MyString
  4472. End Function ' ArrayToString$
  4473.  
  4474. ' /////////////////////////////////////////////////////////////////////////////
  4475.  
  4476. Function ArrayToStringTest$ (MyArray() As String)
  4477.     Dim MyString As String
  4478.     Dim iY As Integer
  4479.     Dim iX As Integer
  4480.     Dim sLine As String
  4481.     MyString = ""
  4482.  
  4483.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  4484.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  4485.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  4486.         sLine = ""
  4487.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  4488.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  4489.             sLine = sLine + MyArray(iY, iX)
  4490.         Next iX
  4491.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  4492.         MyString = MyString + sLine + Chr$(13)
  4493.     Next iY
  4494.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  4495.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  4496.     ArrayToStringTest$ = MyString
  4497. End Function ' ArrayToStringTest$
  4498.  
  4499. ' /////////////////////////////////////////////////////////////////////////////
  4500.  
  4501. Function RotationArrayToStringTest$ (RoArray() As RotationType)
  4502.     Dim MyString As String
  4503.     Dim iY As Integer
  4504.     Dim iX As Integer
  4505.     Dim sLine As String
  4506.     MyString = ""
  4507.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  4508.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  4509.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  4510.     For iY = LBound(RoArray, 1) To UBound(RoArray, 1)
  4511.         sLine = ""
  4512.         sLine = sLine + Right$("    " + cstr$(iY), 3)
  4513.         For iX = LBound(RoArray, 2) To UBound(RoArray, 2)
  4514.             sLine = sLine + Chr$(RoArray(iX, iY, 0).c)
  4515.         Next iX
  4516.         sLine = sLine + Right$("   " + cstr$(iY), 3)
  4517.         MyString = MyString + sLine + Chr$(13)
  4518.     Next iY
  4519.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  4520.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  4521.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  4522.     RotationArrayToStringTest$ = MyString
  4523. End Function ' RotationArrayToStringTest$
  4524.  
  4525. ' /////////////////////////////////////////////////////////////////////////////
  4526. ' 1. split string by line breaks CHR$(13)
  4527. ' 2. split lines up to 1 column per char
  4528. ' 3. count rows, columns
  4529. ' 4. DIM array, making sure array has
  4530. '    a) an _ODD_ number of rows/columns, with a center point
  4531. '    b) index is in cartesian format, where center is (0,0)
  4532. ' 5. populate array with contents of string
  4533.  
  4534. ' dimension #1 = columns
  4535. ' dimension #2 = rows
  4536.  
  4537. Sub StringToRotationArray (RoArray() As RotationType, MyString As String, EmptyChar As String)
  4538.     Dim RoutineName As String: RoutineName = "StringToRotationArray"
  4539.     ReDim arrLines$(0)
  4540.     Dim delim$
  4541.     Dim iRow%
  4542.     Dim iCol%
  4543.     Dim sChar$
  4544.     Dim iColCount As Integer
  4545.     Dim iRowCount As Integer
  4546.     Dim iCount As Integer
  4547.     Dim bAddedRow As Integer: bAddedRow = FALSE
  4548.     Dim bAddedColumn As Integer: bAddedColumn = FALSE
  4549.     Dim iHalf1 As Integer
  4550.     Dim iHalf2 As Integer
  4551.     Dim iFrom1 As Integer
  4552.     Dim iFrom2 As Integer
  4553.     Dim iTo1 As Integer
  4554.     Dim iTo2 As Integer
  4555.     Dim iEmpty As Integer
  4556.     Dim iX As Integer
  4557.     Dim iY As Integer
  4558.  
  4559.     delim$ = Chr$(13)
  4560.     split MyString, delim$, arrLines$()
  4561.  
  4562.     iRowCount = UBound(arrLines$) + 1
  4563.  
  4564.     ' look at all the rows and find the max # of columns used
  4565.     iColCount = 0
  4566.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4567.  
  4568.         ' count the columns for this row
  4569.         iCount = 0
  4570.         For iCol% = 1 To Len(arrLines$(iRow%))
  4571.             iCount = iCount + 1
  4572.         Next iCol%
  4573.  
  4574.         ' if this row has the most so far, then set that to the max
  4575.         If iCount > iColCount Then
  4576.             iColCount = iCount
  4577.         End If
  4578.     Next iRow%
  4579.  
  4580.     ' adjust columns to be odd
  4581.     If IsEven%(iColCount) Then
  4582.         iColCount = iColCount + 1
  4583.         bAddedColumn = TRUE
  4584.     End If
  4585.  
  4586.     ' calculate array bounds for columns
  4587.     iHalf1 = (iColCount - 1) / 2
  4588.     iFrom1 = 0 - iHalf1
  4589.     iTo1 = iHalf1
  4590.  
  4591.     ' adjust rows to be odd
  4592.     If IsEven%(iRowCount) Then
  4593.         iRowCount = iRowCount + 1
  4594.         bAddedRow = TRUE
  4595.     End If
  4596.  
  4597.     ' calculate array bounds for rows
  4598.     iHalf2 = (iRowCount - 1) / 2
  4599.     iFrom2 = 0 - iHalf2
  4600.     iTo2 = iHalf2
  4601.  
  4602.     ' size array to new bounds
  4603.     ReDim RoArray(iFrom1 To iTo1, iFrom2 To iTo2, 127) As RotationType
  4604.  
  4605.     ' get value for empty
  4606.     If Len(EmptyChar) > 0 Then
  4607.         iEmpty = Asc(EmptyChar)
  4608.     Else
  4609.         iEmpty = 32 ' (use space as default)
  4610.     End If
  4611.  
  4612.     ' clear array
  4613.     For iY = LBound(RoArray, 2) To UBound(RoArray, 2)
  4614.         For iX = LBound(RoArray, 1) To UBound(RoArray, 1)
  4615.             RoArray(iX, iY, 0).c = iEmpty
  4616.             RoArray(iX, iY, 0).origx = iX
  4617.             RoArray(iX, iY, 0).origy = iY
  4618.         Next iX
  4619.     Next iY
  4620.  
  4621.     ' fill array
  4622.     iY = LBound(RoArray, 2) - 1
  4623.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4624.         iY = iY + 1
  4625.         iX = LBound(RoArray, 1) - 1
  4626.         For iCol% = 1 To Len(arrLines$(iRow%))
  4627.             iX = iX + 1
  4628.             sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  4629.             RoArray(iX, iY, 0).c = Asc(sChar$)
  4630.         Next iCol%
  4631.     Next iRow%
  4632.  
  4633. End Sub ' StringToRotationArray
  4634.  
  4635. ' /////////////////////////////////////////////////////////////////////////////
  4636.  
  4637. Sub StringToArray (MyArray() As String, MyString As String)
  4638.     Dim delim$
  4639.     ReDim arrLines$(0)
  4640.     Dim iRow%
  4641.     Dim iCol%
  4642.     Dim sChar$
  4643.     Dim iDim1 As Integer
  4644.     Dim iDim2 As Integer
  4645.     iDim1 = LBound(MyArray, 1)
  4646.     iDim2 = LBound(MyArray, 2)
  4647.     delim$ = Chr$(13)
  4648.     split MyString, delim$, arrLines$()
  4649.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4650.         If iRow% <= UBound(MyArray, 2) Then
  4651.             For iCol% = 1 To Len(arrLines$(iRow%))
  4652.                 If iCol% <= UBound(MyArray, 1) Then
  4653.                     sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  4654.  
  4655.                     If Len(sChar$) > 1 Then
  4656.                         sChar$ = Left$(sChar$, 1)
  4657.                     Else
  4658.                         If Len(sChar$) = 0 Then
  4659.                             sChar$ = "."
  4660.                         End If
  4661.                     End If
  4662.                     MyArray(iRow% + iDim1, (iCol% - 1) + iDim2) = sChar$
  4663.                 Else
  4664.                     ' Exit if out of bounds
  4665.                     Exit For
  4666.                 End If
  4667.             Next iCol%
  4668.         Else
  4669.             ' Exit if out of bounds
  4670.             Exit For
  4671.         End If
  4672.     Next iRow%
  4673. End Sub ' StringToArray
  4674.  
  4675. ' /////////////////////////////////////////////////////////////////////////////
  4676.  
  4677. 'SUB ClearArray (MyArray(1 To 32, 1 To 32) AS STRING, MyString As String)
  4678. Sub ClearArray (MyArray() As String, MyString As String)
  4679.     Dim iRow As Integer
  4680.     Dim iCol As Integer
  4681.     Dim sChar$
  4682.     If Len(MyString) = 1 Then
  4683.         sChar$ = MyString
  4684.     Else
  4685.         If Len(MyString) = 0 Then
  4686.             sChar$ = " "
  4687.         Else
  4688.             sChar$ = Left$(MyString, 1)
  4689.         End If
  4690.     End If
  4691.     For iRow = LBound(MyArray, 1) To UBound(MyArray, 1)
  4692.         For iCol = LBound(MyArray, 2) To UBound(MyArray, 2)
  4693.             MyArray(iRow, iCol) = sChar$
  4694.         Next iCol
  4695.     Next iRow
  4696. End Sub ' ClearArray
  4697.  
  4698. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4699. ' BEGIN GENERAL PURPOSE ROUTINES
  4700. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4701.  
  4702. ' /////////////////////////////////////////////////////////////////////////////
  4703.  
  4704. Function cstr$ (myValue)
  4705.     'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
  4706.     cstr$ = _Trim$(Str$(myValue))
  4707. End Function ' cstr$
  4708.  
  4709. Function cstrl$ (myValue As Long)
  4710.     cstrl$ = _Trim$(Str$(myValue))
  4711. End Function ' cstrl$
  4712.  
  4713. ' /////////////////////////////////////////////////////////////////////////////
  4714.  
  4715. Function IIF (Condition, IfTrue, IfFalse)
  4716.     If Condition Then IIF = IfTrue Else IIF = IfFalse
  4717.  
  4718. ' /////////////////////////////////////////////////////////////////////////////
  4719.  
  4720. Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
  4721.     If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
  4722.  
  4723. ' /////////////////////////////////////////////////////////////////////////////
  4724. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  4725.  
  4726. Function IsEven% (n)
  4727.     If n Mod 2 = 0 Then
  4728.         IsEven% = TRUE
  4729.     Else
  4730.         IsEven% = FALSE
  4731.     End If
  4732. End Function ' IsEven%
  4733.  
  4734. ' /////////////////////////////////////////////////////////////////////////////
  4735. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  4736.  
  4737. Function IsOdd% (n)
  4738.     If n Mod 2 = 1 Then
  4739.         IsOdd% = TRUE
  4740.     Else
  4741.         IsOdd% = FALSE
  4742.     End If
  4743. End Function ' IsOdd%
  4744.  
  4745. ' /////////////////////////////////////////////////////////////////////////////
  4746. ' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0
  4747.  
  4748. Function IsNum% (text$)
  4749.     Dim a$
  4750.     Dim b$
  4751.     a$ = _Trim$(text$)
  4752.     b$ = _Trim$(Str$(Val(text$)))
  4753.     If a$ = b$ Then
  4754.         IsNum% = TRUE
  4755.     Else
  4756.         IsNum% = FALSE
  4757.     End If
  4758. End Function ' IsNum%
  4759.  
  4760. ' /////////////////////////////////////////////////////////////////////////////
  4761. ' Split and join strings
  4762. ' https://www.qb64.org/forum/index.php?topic=1073.0
  4763.  
  4764. 'Combine all elements of in$() into a single string with delimiter$ separating the elements.
  4765.  
  4766. Function join$ (in$(), delimiter$)
  4767.     result$ = in$(LBound(in$))
  4768.     For i = LBound(in$) + 1 To UBound(in$)
  4769.         result$ = result$ + delimiter$ + in$(i)
  4770.     Next i
  4771.     join$ = result$
  4772. End Function ' join$
  4773.  
  4774. ' /////////////////////////////////////////////////////////////////////////////
  4775. ' FROM: String Manipulation
  4776. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index_topic_5964-0/
  4777. '
  4778. 'SUMMARY:
  4779. '   Purpose:  A library of custom functions that transform strings.
  4780. '   Author:   Dustinian Camburides (dustinian@gmail.com)
  4781. '   Platform: QB64 (www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there])
  4782. '   Revision: 1.6
  4783. '   Updated:  5/28/2012
  4784.  
  4785. 'SUMMARY:
  4786. '[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
  4787. 'INPUT:
  4788. 'Text: The input string; the text that's being manipulated.
  4789. 'Find: The specified sub-string; the string sought within the [Text] string.
  4790. 'Add: The sub-string that's being added to the [Text] string.
  4791.  
  4792. Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
  4793.     ' VARIABLES:
  4794.     Dim Text2 As String
  4795.     Dim Find2 As String
  4796.     Dim Add2 As String
  4797.     Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
  4798.     Dim strBefore As String ' The characters before the string to be replaced.
  4799.     Dim strAfter As String ' The characters after the string to be replaced.
  4800.  
  4801.     ' INITIALIZE:
  4802.     ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
  4803.     Text2 = Text1
  4804.     Find2 = Find1
  4805.     Add2 = Add1
  4806.  
  4807.     lngLocation = InStr(1, Text2, Find2)
  4808.  
  4809.     ' PROCESSING:
  4810.     ' While [Find2] appears in [Text2]...
  4811.     While lngLocation
  4812.         ' Extract all Text2 before the [Find2] substring:
  4813.         strBefore = Left$(Text2, lngLocation - 1)
  4814.  
  4815.         ' Extract all text after the [Find2] substring:
  4816.         strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
  4817.  
  4818.         ' Return the substring:
  4819.         Text2 = strBefore + Add2 + strAfter
  4820.  
  4821.         ' Locate the next instance of [Find2]:
  4822.         lngLocation = InStr(1, Text2, Find2)
  4823.  
  4824.         ' Next instance of [Find2]...
  4825.     Wend
  4826.  
  4827.     ' OUTPUT:
  4828.     Replace$ = Text2
  4829. End Function ' Replace$
  4830.  
  4831. ' /////////////////////////////////////////////////////////////////////////////
  4832. ' Split and join strings
  4833. ' https://www.qb64.org/forum/index.php?topic=1073.0
  4834. '
  4835. ' FROM luke, QB64 Developer
  4836. ' Date: February 15, 2019, 04:11:07 AM
  4837. '
  4838. ' Given a string of words separated by spaces (or any other character),
  4839. ' splits it into an array of the words. I've no doubt many people have
  4840. ' written a version of this over the years and no doubt there's a million
  4841. ' ways to do it, but I thought I'd put mine here so we have at least one
  4842. ' version. There's also a join function that does the opposite
  4843. ' array -> single string.
  4844. '
  4845. ' Code is hopefully reasonably self explanatory with comments and a little demo.
  4846. ' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.
  4847.  
  4848. 'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
  4849. 'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
  4850. '
  4851. 'delimiter$ must be one character long.
  4852. 'result$() must have been REDIMmed previously.
  4853.  
  4854. Sub split (in$, delimiter$, result$())
  4855.     ReDim result$(-1)
  4856.     start = 1
  4857.     Do
  4858.         While Mid$(in$, start, 1) = delimiter$
  4859.             start = start + 1
  4860.             If start > Len(in$) Then Exit Sub
  4861.         Wend
  4862.         finish = InStr(start, in$, delimiter$)
  4863.         If finish = 0 Then finish = Len(in$) + 1
  4864.         ReDim _Preserve result$(0 To UBound(result$) + 1)
  4865.         result$(UBound(result$)) = Mid$(in$, start, finish - start)
  4866.         start = finish + 1
  4867.     Loop While start <= Len(in$)
  4868. End Sub ' split
  4869.  
  4870. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4871. ' END GENERAL PURPOSE ROUTINES
  4872. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4873.  
  4874. ' #END
  4875. ' ################################################################################################################################################################
  4876.  
« Last Edit: December 29, 2021, 02:09:44 pm by madscijr »

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
So I have to do a bunch of reading to catch up to where the discussion is,
but I never mentioned how a certain experiment went the other day so I recreated it just now.
This is quick and dirty, not a solution, but maybe it'll inspire.

Final update for today, this adds ShearRotate6 (options 24 + 25 on the menu),
which uses precalculated matrices with a unique value for each point,
rotated to each problem angle (eg 30, 60, 120, etc.)
as well as the adjacent angles 29, 31, 59, 61, etc.)

If the rotation angle is the a problem angle,
it verifies for each unique point in the unrotated
matrix is found in the prerotated matrix for the desired angle.

If a point is NOT found,
it looks for it in the prerotated matrix
for angle-1 (if rotating counter-clockwise)
or angle +1 (if clockwise),
and if found, uses that coordinate to copy the point to in the destination.

If not found, it looks in the other direction (if clockwise, angle-1, etc.)
and uses that location if found.

If not found at all, it adds 1 to the count of total points not found.

It appears to work without errors, but the interesting thing is,
the results look worse than the earlier logic (SheerRotate4)
and it counts a lot more missing points (160 missing for SheerRotate6
vs 3 missing for SheerRotate4).

I'm not 100% sure there aren't errors in it somewhere,
or that the total is even correct, but the way it looks now,
the simpler dumber logic seems to work better...

Here is the code if you want to give it a try...

Code: QB64: [Select]
  1. ' ################################################################################################################################################################
  2. ' #TOP
  3.  
  4. ' Basic 2D plotting functions
  5. ' Version 1.00 by madscijr
  6. ' with help from various (sources cited below).
  7. ' ################################################################################################################################################################
  8.  
  9. ' =============================================================================
  10. ' GLOBAL DECLARATIONS
  11. ' =============================================================================
  12.  
  13. ' boolean constants
  14. Const FALSE = 0
  15. Const TRUE = Not FALSE
  16.  
  17. ' rotational constants
  18. Const cCounterClockwise = -1
  19. Const cClockwise = 1
  20.  
  21. ' -----------------------------------------------------------------------------
  22. ' USER DEFINED TYPES
  23. ' -----------------------------------------------------------------------------
  24. Type RotationType
  25.     origx As Integer
  26.     origy As Integer
  27.     c As Integer
  28.     z As Integer ' which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  29. End Type ' RotationType
  30.  
  31. ' -----------------------------------------------------------------------------
  32. ' GLOBAL VARIABLES
  33. ' -----------------------------------------------------------------------------
  34. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  35. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  36. Dim Shared m_bDebug: m_bDebug = TRUE
  37.  
  38. ' =============================================================================
  39. ' BEGIN MAIN PROGRAM
  40. ' =============================================================================
  41. Dim in$
  42.  
  43. ' ****************************************************************************************************************************************************************
  44. ' ACTIVATE DEBUGGING WINDOW
  45. If m_bDebug = TRUE Then
  46.     $Console
  47.     _Delay 4
  48.     _Console On
  49.     _Echo "Started " + m_ProgramName$
  50.     _Echo "Debugging on..."
  51. ' ****************************************************************************************************************************************************************
  52.  
  53. ' -----------------------------------------------------------------------------
  54. ' START THE MENU
  55. main
  56.  
  57. ' -----------------------------------------------------------------------------
  58. ' DONE
  59. Print m_ProgramName$ + " finished."
  60. 'Screen 0
  61. Input "Press <ENTER> to continue", in$
  62.  
  63. ' ****************************************************************************************************************************************************************
  64. ' DEACTIVATE DEBUGGING WINDOW
  65. If m_bDebug = TRUE Then
  66. ' ****************************************************************************************************************************************************************
  67.  
  68. ' -----------------------------------------------------------------------------
  69. ' EXIT
  70. System ' return control to the operating system
  71.  
  72. ' =============================================================================
  73. ' END MAIN PROGRAM
  74. ' =============================================================================
  75.  
  76. ' /////////////////////////////////////////////////////////////////////////////
  77. ' MAIN MENU
  78.  
  79. Sub main
  80.     Dim RoutineName As String: RoutineName = "main"
  81.     Dim in$
  82.  
  83.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  84.     Do
  85.         Cls
  86.         Print m_ProgramName$
  87.         Print
  88.         Print "Some basic 2D plotting"
  89.         Print
  90.         Print " 1. PlotPointTest"
  91.         Print " 2. PlotSquareTest"
  92.         Print " 3. PlotCircleTest"
  93.         Print " 4. PlotCircleTopLeftTest"
  94.         Print " 5. PlotSemicircleTest"
  95.         Print " 6. CircleFillTest"
  96.         Print " 7. CircleFillTopLeftTest"
  97.         Print " 8. SemiCircleFillTest"
  98.         Print " 9. EllipseTest"
  99.         Print "10. EllipseFillTest"
  100.         Print "11. PlotLineTest"
  101.         Print "12. ShearRotate1Test1"
  102.         Print "13. ShearRotate1Test2 (auto advances 0-360 degrees)"
  103.         Print "14. ShearRotate1Test2 (auto advances 0-360 degrees) (uses Petr's text)"
  104.         Print "15. ShearRotate2Test1 (correct for missing points logic v1)"
  105.         Print "16. ShearRotate2Test1 (correct for missing points logic v1) (uses Petr's text)"
  106.         Print "17. ShearRotate3Test1 (correct for missing points logic v2)"
  107.         Print "18. ShearRotate3Test1 (correct for missing points logic v2) (uses Petr's text)"
  108.         Print "19. ShearRotate4Test1 (correct for missing points logic v3)"
  109.         Print "20. ShearRotate4Test1 (correct for missing points logic v3) (uses Petr's text)"
  110.         Print "21. ShearRotate5Test1 (correct for missing points, STxAxTIC logic)"
  111.         Print "22. ShearRotate5Test1 (correct for missing points, STxAxTIC logic) (uses Petr's text)"
  112.         Print "23. GetRotationMaskTest"
  113.         Print "24. ShearRotate6Test1 (corrects for missing points using precalculated v1)"
  114.         Print "25. ShearRotate6Test1 (corrects for missing points using precalculated v1) (uses Petr's text)"
  115.  
  116.         Print "What to do? ('q' to exit)"
  117.  
  118.         Input in$: in$ = LCase$(_Trim$(in$))
  119.  
  120.         If in$ = "1" Then
  121.             PlotPointTest
  122.         ElseIf in$ = "2" Then
  123.             PlotSquareTest
  124.         ElseIf in$ = "3" Then
  125.             PlotCircleTest
  126.         ElseIf in$ = "4" Then
  127.             PlotCircleTopLeftTest
  128.         ElseIf in$ = "5" Then
  129.             PlotSemicircleTest
  130.         ElseIf in$ = "6" Then
  131.             CircleFillTest
  132.         ElseIf in$ = "7" Then
  133.             CircleFillTopLeftTest
  134.         ElseIf in$ = "8" Then
  135.             SemiCircleFillTest
  136.         ElseIf in$ = "9" Then
  137.             EllipseTest
  138.         ElseIf in$ = "10" Then
  139.             EllipseFillTest
  140.         ElseIf in$ = "11" Then
  141.             PlotLineTest
  142.         ElseIf in$ = "12" Then
  143.             ShearRotate1Test1
  144.         ElseIf in$ = "13" Then
  145.             ShearRotate1Test2 TestSprite1$
  146.         ElseIf in$ = "14" Then
  147.             ShearRotate1Test2 PetrText1$
  148.         ElseIf in$ = "15" Then
  149.             ShearRotate2Test1 TestSprite1$
  150.         ElseIf in$ = "16" Then
  151.             ShearRotate2Test1 PetrText1$
  152.         ElseIf in$ = "17" Then
  153.             ShearRotate3Test1 TestSprite1$
  154.         ElseIf in$ = "18" Then
  155.             ShearRotate3Test1 PetrText1$
  156.         ElseIf in$ = "19" Then
  157.             ShearRotate4Test1 TestSprite1$
  158.         ElseIf in$ = "20" Then
  159.             ShearRotate4Test1 PetrText1$
  160.         ElseIf in$ = "21" Then
  161.             ShearRotate5Test1 TestSprite1$
  162.         ElseIf in$ = "22" Then
  163.             ShearRotate5Test1 PetrText1$
  164.         ElseIf in$ = "23" Then
  165.             GetRotationMaskTest
  166.         ElseIf in$ = "24" Then
  167.             ShearRotate6Test1 TestSprite1$
  168.         ElseIf in$ = "25" Then
  169.             ShearRotate6Test1 PetrText1$
  170.         End If
  171.     Loop Until in$ = "q"
  172. End Sub ' main
  173.  
  174.  
  175.  
  176.  
  177.  
  178.  
  179.  
  180.  
  181.  
  182.  
  183.  
  184. ' /////////////////////////////////////////////////////////////////////////////
  185. ' MyArray(1 To 32, 1 To 32) AS STRING
  186. ' where index is MyArray(Y, X)
  187.  
  188. Sub PlotPoint (X As Integer, Y As Integer, S As String, MyArray() As String)
  189.     _Echo "PlotPoint X=" + cstr$(X) + ", Y=" + cstr$(Y) + ", S=" + Chr$(34) + S + Chr$(34) + ", MyArray()"
  190.     If (X >= LBound(MyArray, 2)) Then
  191.         If (X <= UBound(MyArray, 2)) Then
  192.             If (Y >= LBound(MyArray, 1)) Then
  193.                 If (Y <= UBound(MyArray, 1)) Then
  194.                     If Len(S) = 1 Then
  195.                         MyArray(Y, X) = S
  196.                     Else
  197.                         If Len(S) > 1 Then
  198.                             MyArray(Y, X) = Left$(S, 1)
  199.                         End If
  200.                     End If
  201.                 End If
  202.             End If
  203.         End If
  204.     End If
  205. End Sub ' PlotPoint
  206.  
  207. ' /////////////////////////////////////////////////////////////////////////////
  208.  
  209. Sub PlotPointTest
  210.     Dim MyArray(1 To 32, 1 To 32) As String
  211.     Dim iX As Integer
  212.     Dim iY As Integer
  213.     Dim in$
  214.     Dim X As Integer
  215.     Dim Y As Integer
  216.     Dim L As Integer
  217.     Dim iChar As Integer
  218.  
  219.     ClearArray MyArray(), "."
  220.     iChar = 64
  221.  
  222.     Cls
  223.     Print "Plot a point."
  224.     Print ArrayToStringTest(MyArray())
  225.     Print
  226.  
  227.     Do
  228.         Print "Type x,y (1-32, 1-32) coordinate to plot point at."
  229.         Input "X,Y OR 0 TO QUIT? "; X, Y
  230.         If X > 0 And Y > 0 Then
  231.             iChar = iChar + 1
  232.             If iChar > 90 Then iChar = 65
  233.  
  234.             Print "X=" + cstr$(X) + ", Y=" + cstr$(Y)
  235.             PlotPoint X, Y, Chr$(iChar), MyArray()
  236.  
  237.             Print "Current point plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  238.             Print ArrayToStringTest(MyArray())
  239.             Print
  240.  
  241.         Else
  242.             Exit Do
  243.         End If
  244.     Loop
  245. End Sub ' PlotPointTest
  246.  
  247. ' /////////////////////////////////////////////////////////////////////////////
  248.  
  249. Sub PlotSquare (X1 As Integer, Y1 As Integer, L As Integer, S As String, MyArray() As String)
  250.     Dim X As Integer
  251.     Dim X2 As Integer
  252.     Dim Y As Integer
  253.     Dim Y2 As Integer
  254.     Dim sChar$
  255.  
  256.     If Len(S) = 1 Then
  257.         sChar$ = S
  258.     Else
  259.         If Len(S) = 0 Then
  260.             sChar$ = " "
  261.         Else
  262.             sChar$ = Left$(S, 1)
  263.         End If
  264.     End If
  265.  
  266.     X2 = (X1 + L) - 1
  267.     Y2 = (Y1 + L) - 1
  268.     For X = X1 To X2
  269.         For Y = Y1 To Y2
  270.             PlotPoint X, Y, sChar$, MyArray()
  271.         Next Y
  272.     Next X
  273. End Sub ' PlotSquare
  274.  
  275. ' /////////////////////////////////////////////////////////////////////////////
  276.  
  277. Sub PlotSquareTest
  278.     Dim MyArray(1 To 32, 1 To 32) As String
  279.     Dim iX As Integer
  280.     Dim iY As Integer
  281.     Dim in$
  282.     Dim X As Integer
  283.     Dim Y As Integer
  284.     Dim L As Integer
  285.     Dim iChar As Integer
  286.  
  287.     ClearArray MyArray(), "."
  288.     iChar = 64
  289.  
  290.     Cls
  291.     Print "Enter parameters to draw a square."
  292.     Print ArrayToStringTest(MyArray())
  293.     Print
  294.     Do
  295.         Print "Type top left x,y (1-32, 1-32) coordinate to plot square,"
  296.         Print "and size (1-32) of square."
  297.         Input "X,Y,L OR 0 TO QUIT? "; X, Y, L
  298.         If X > 0 And Y > 0 And L > 0 Then
  299.             iChar = iChar + 1
  300.             If iChar > 90 Then iChar = 65
  301.  
  302.             Print
  303.             Print "X=" + cstr$(X)
  304.             Print "Y=" + cstr$(Y)
  305.             Print "L=" + cstr$(L)
  306.             Print
  307.             PlotSquare X, Y, L, Chr$(iChar), MyArray()
  308.  
  309.             Print "Square plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  310.             Print ArrayToStringTest(MyArray())
  311.             Print
  312.         Else
  313.             Exit Do
  314.         End If
  315.     Loop
  316. End Sub ' PlotSquareTest
  317.  
  318. ' /////////////////////////////////////////////////////////////////////////////
  319. ' Fast circle drawing in pure Atari BASIC#
  320. ' https://atariwiki.org/wiki/Wiki.jsp?page=Super%20fast%20circle%20routine
  321.  
  322. ' * Magazine: Moj Mikro, 1989/3
  323. ' * Author : Zlatko Bleha
  324. ' * Page : 27 - 31
  325. ' * Atari BASIC listing on disk (tokenized): M8903282.BAS
  326. ' * Atari BASIC listing (listed): M8903282.LST
  327.  
  328. ' Next example is demonstration of implementing mentioned circle algorithm
  329. ' in pure Atari BASIC. This program shows how much faster it is compared to
  330. ' classic program using sine and cosine functions from Atari BASIC
  331. ' (shown in last example).
  332.  
  333. ' Basic Listing M8903282.LST#
  334. '1 REM *******************************
  335. '2 REM PROGRAM  : FAST CIRCLE DRAWING
  336. '3 REM AUTHOR   : ZLATKO BLEHA
  337. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  338. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  339. '6 REM *******************************
  340. '7 REM
  341. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  342. '20 PRINT "ENTER X, Y AND R"
  343. '30 INPUT X,Y,R
  344. '40 IF R=0 THEN PLOT X,Y:END
  345. '50 B=R:C=0:A=R-1
  346. '60 PLOT X+C,Y+B
  347. '70 PLOT X+C,Y-B
  348. '80 PLOT X-C,Y-B
  349. '90 PLOT X-C,Y+B
  350. '100 PLOT X+B,Y+C
  351. '110 PLOT X+B,Y-C
  352. '120 PLOT X-B,Y-C
  353. '130 PLOT X-B,Y+C
  354. '140 C=C+1
  355. '150 A=A+1-C-C
  356. '160 IF A>=0 THEN 190
  357. '170 B=B-1
  358. '180 A=A+B+B
  359. '190 IF B>=C THEN 60
  360.  
  361. ' Use some valid values for coordinates and radius, for example:
  362. ' X=40, Y=40, R=30
  363. ' X=130, Y=90, R=60
  364. ' Slow circle drawing in Atari BASIC#
  365. ' * Magazine: Moj Mikro, 1989/3
  366. ' * Author : Zlatko Bleha
  367. ' * Page : 27 - 31
  368. ' * Atari BASIC listing on disk (tokenized): M8903281.BAS
  369. ' * Atari BASIC listing (listed): M8903281.LST
  370.  
  371. ' This is classic example for drawing circles from Atari BASIC
  372. ' using sine and cosine functions. Unfortunatelly, this is very slow
  373. ' way of doing it and not recommended.
  374. ' Just use routine shown above and everybody will be happy
  375.  
  376. ' Basic Listing M8903281.LST#
  377. '1 REM *******************************
  378. '2 REM PROGRAM  : SLOW CIRCLE DRAWING
  379. '3 REM AUTHOR   : ZLATKO BLEHA
  380. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  381. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  382. '6 REM *******************************
  383. '7 REM
  384. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  385. '20 FOR A=0 TO 6.28 STEP 0.02
  386. '30 X=SIN(A)*50+150
  387. '40 Y=COS(A)*50+80
  388. '50 PLOT X,Y
  389. '60 NEXT A
  390.  
  391. ' Conclusion#
  392. ' Returning back to first program with the fastest way of drawing circles...
  393. ' There is one more thing to note. In case you want to use PLOT subroutine,
  394. ' which is part of the main circle routine, then read following explanation.
  395. ' PLOT routine is written so it can be used easily from Atari BASIC program
  396. ' independently from main circle routine, by using like this:
  397. ' A=USR(30179,POK,X,Y)
  398. '
  399. ' POK   1 (drawing a pixel), 0 (erasing a pixel)
  400. ' X     X coordinate of the pixel
  401. ' Y     Y coordinate of the pixel
  402. '
  403. ' The routine alone is not any faster than normal PLOT command
  404. ' from Atari BASIC, because USR command takes approximately 75%
  405. ' of whole execution. But, used as part of the main circle routine
  406. ' it does not matter anymore, because it is integrated in one larger
  407. ' entity. There the execution is very fast, with no overhead.
  408. ' PLOT routine is here for you to examine anyway.
  409. ' You never know if you will maybe need it in the future.
  410.  
  411. ' More on plotting circles:
  412. '     Drawing a circle in BASIC - fast
  413. '     https://www.cpcwiki.eu/forum/programming/drawing-a-circle-in-basic-fast/
  414.  
  415. ' X,Y     = center point of circle
  416. ' R       = radius
  417. ' S       = char to draw
  418. ' MyArray = 2D string array to plot circle in
  419.  
  420. Sub PlotCircle (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  421.     Dim A As Integer
  422.     Dim B As Integer
  423.     Dim C As Integer
  424.     Dim S2 As String
  425.  
  426.     If Len(S) = 1 Then
  427.         S2 = S
  428.     Else
  429.         If Len(S) = 0 Then
  430.             S2 = " "
  431.         Else
  432.             S2 = Left$(S, 1)
  433.         End If
  434.     End If
  435.  
  436.     If R > 0 Then
  437.         B = R
  438.         C = 0
  439.         A = R - 1
  440.         Do
  441.             PlotPoint X + C, Y + B, S2, MyArray()
  442.             PlotPoint X + C, Y - B, S2, MyArray()
  443.             PlotPoint X - C, Y - B, S2, MyArray()
  444.             PlotPoint X - C, Y + B, S2, MyArray()
  445.             PlotPoint X + B, Y + C, S2, MyArray()
  446.             PlotPoint X + B, Y - C, S2, MyArray()
  447.             PlotPoint X - B, Y - C, S2, MyArray()
  448.             PlotPoint X - B, Y + C, S2, MyArray()
  449.             C = C + 1
  450.             A = A + 1 - C - C
  451.             If A < 0 Then ' IF A>=0 THEN 190
  452.                 B = B - 1
  453.                 A = A + B + B
  454.             End If
  455.             If B < C Then Exit Do ' 190 IF B>=C THEN 60
  456.         Loop
  457.     End If
  458. End Sub ' PlotCircle
  459.  
  460. ' /////////////////////////////////////////////////////////////////////////////
  461.  
  462. Sub PlotCircleTest
  463.     Dim MyArray(1 To 32, 1 To 32) As String
  464.     Dim iX As Integer
  465.     Dim iY As Integer
  466.     Dim in$
  467.     Dim X As Integer
  468.     Dim Y As Integer
  469.     Dim R As Integer
  470.     Dim iChar As Integer
  471.  
  472.     ClearArray MyArray(), "."
  473.     iChar = 64
  474.  
  475.     Cls
  476.     Print "Plot a raster circle"
  477.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  478.     Print
  479.     Print "Enter parameters to draw a circle."
  480.     Print ArrayToStringTest(MyArray())
  481.     Print
  482.  
  483.     Do
  484.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  485.         Print "and radius (1-32) of circle."
  486.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  487.         If X > 0 And Y > 0 And R > 0 Then
  488.             iChar = iChar + 1
  489.             If iChar > 90 Then iChar = 65
  490.  
  491.             Print "X=" + cstr$(X)
  492.             Print "Y=" + cstr$(Y)
  493.             Print "R=" + cstr$(R)
  494.  
  495.             PlotCircle X, Y, R, Chr$(iChar), MyArray()
  496.  
  497.             Print "Circle plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  498.             Print ArrayToStringTest(MyArray())
  499.             Print
  500.         Else
  501.             Exit Do
  502.         End If
  503.     Loop
  504.  
  505. End Sub ' PlotCircleTest
  506.  
  507. ' /////////////////////////////////////////////////////////////////////////////
  508. ' X,Y     = top left point of circle
  509. ' R       = radius
  510. ' S       = char to draw
  511. ' MyArray = 2D string array to plot circle in
  512.  
  513. Sub PlotCircleTopLeft (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  514.     Dim RoutineName As String: RoutineName = "PlotCircleTopLeft"
  515.     Dim A As Integer
  516.     Dim B As Integer
  517.     Dim C As Integer
  518.     Dim S2 As String
  519.     Dim W As Integer
  520.     ReDim arrTemp(0, 0) As String
  521.     Dim DY As Integer
  522.     Dim DX As Integer
  523.     Dim TX As Integer
  524.     Dim TY As Integer
  525.     Dim MinY As Integer
  526.     Dim MaxY As Integer
  527.     Dim MinX As Integer
  528.     Dim MaxX As Integer
  529.  
  530.     ' Get total width
  531.     W = (R * 2) + 1
  532.  
  533.     ' Define a temp array
  534.     ReDim arrTemp(0 To W, 0 To W) As String
  535.  
  536.     ' Get minimum X, Y of target array
  537.     MinY = LBound(MyArray, 1)
  538.     MaxY = UBound(MyArray, 1)
  539.     MinX = LBound(MyArray, 2)
  540.     MaxX = UBound(MyArray, 2)
  541.  
  542.     If Len(S) = 1 Then
  543.         S2 = S
  544.     Else
  545.         If Len(S) = 0 Then
  546.             S2 = " "
  547.         Else
  548.             S2 = Left$(S, 1)
  549.         End If
  550.     End If
  551.  
  552.     If R > 0 Then
  553.         ' Draw circle to temporary array
  554.         B = R
  555.         C = 0
  556.         A = R - 1
  557.         Do
  558.             ' PORTIONS OF CIRCLE:
  559.             ' .......3333222.......
  560.             ' .....33.......22.....
  561.             ' ....3...........2....
  562.             ' ...7.............6...
  563.             ' ..7...............6..
  564.             ' .7.................6.
  565.             ' .7.................6.
  566.             ' 7...................6
  567.             ' 7...................6
  568.             ' 7...................6
  569.             ' 8...................6
  570.             ' 8...................5
  571.             ' 8...................5
  572.             ' 8...................5
  573.             ' .8.................5.
  574.             ' .8.................5.
  575.             ' ..8...............5..
  576.             ' ...8.............5...
  577.             ' ....4...........1....
  578.             ' .....44.......11.....
  579.             ' .......4444111.......
  580.             PlotPoint R + C, R + B, S2, arrTemp() ' 1
  581.             PlotPoint R + C, R - B, S2, arrTemp() ' 2
  582.             PlotPoint R - C, R - B, S2, arrTemp() ' 3
  583.             PlotPoint R - C, R + B, S2, arrTemp() ' 4
  584.             PlotPoint R + B, R + C, S2, arrTemp() ' 5
  585.             PlotPoint R + B, R - C, S2, arrTemp() ' 6
  586.             PlotPoint R - B, R - C, S2, arrTemp() ' 7
  587.             PlotPoint R - B, R + C, S2, arrTemp() ' 8
  588.             C = C + 1
  589.             A = A + 1 - C - C
  590.             If A < 0 Then
  591.                 B = B - 1
  592.                 A = A + B + B
  593.             End If
  594.             If B < C Then Exit Do
  595.         Loop
  596.  
  597.         ' Copy circle to destination Y,X
  598.         For DY = LBound(arrTemp, 1) To UBound(arrTemp, 1)
  599.             For DX = LBound(arrTemp, 2) To UBound(arrTemp, 2)
  600.                 If Len(arrTemp(DY, DX)) > 0 Then
  601.                     TY = Y + DY
  602.                     If TY >= MinY Then
  603.                         If TY <= MaxY Then
  604.                             TX = X + DX
  605.                             If TX >= MinX Then
  606.                                 If TX <= MaxX Then
  607.                                     MyArray(TY, TX) = arrTemp(DY, DX)
  608.                                 End If
  609.                             End If
  610.                         End If
  611.                     End If
  612.  
  613.                 End If
  614.             Next DX
  615.         Next DY
  616.     End If
  617. End Sub ' PlotCircleTopLeft
  618.  
  619. ' /////////////////////////////////////////////////////////////////////////////
  620.  
  621. Sub PlotCircleTopLeftTest
  622.     Dim MyArray(1 To 32, 1 To 32) As String
  623.     Dim iX As Integer
  624.     Dim iY As Integer
  625.     Dim in$
  626.     Dim X As Integer
  627.     Dim Y As Integer
  628.     Dim R As Integer
  629.     Dim iChar As Integer
  630.  
  631.     ClearArray MyArray(), "."
  632.     iChar = 64
  633.  
  634.     Cls
  635.     Print "Plot a raster circle, specifying top left x,y position"
  636.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  637.     Print
  638.     Print "Enter parameters to draw a circle."
  639.     Print ArrayToStringTest(MyArray())
  640.     Print
  641.  
  642.     Do
  643.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot circle,"
  644.         Print "and radius (1-32) of circle."
  645.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  646.         If X > 0 And Y > 0 And R > 0 Then
  647.             iChar = iChar + 1
  648.             If iChar > 90 Then iChar = 65
  649.  
  650.             Print "X=" + cstr$(X)
  651.             Print "Y=" + cstr$(Y)
  652.             Print "R=" + cstr$(R)
  653.  
  654.             PlotCircleTopLeft X, Y, R, Chr$(iChar), MyArray()
  655.  
  656.             Print "Circle plotted (from top left), drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  657.             Print ArrayToStringTest(MyArray())
  658.             Print
  659.         Else
  660.             Exit Do
  661.         End If
  662.     Loop
  663.  
  664. End Sub ' PlotCircleTopLeftTest
  665.  
  666. ' /////////////////////////////////////////////////////////////////////////////
  667. ' Based on PlotCircleTopLeft.
  668.  
  669. ' X,Y     = top left point of circle
  670. ' R       = radius
  671. ' Q       = which quarter of the circle to return
  672. '           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
  673. '           like this:
  674. ' .......4444111.......
  675. ' .....44.......11.....
  676. ' ....4...........1....
  677. ' ...4.............1...
  678. ' ..4...............1..
  679. ' .4.................1.
  680. ' .4.................1.
  681. ' 4...................1
  682. ' 4...................1
  683. ' 4...................1
  684. ' 3...................1
  685. ' 3...................2
  686. ' 3...................2
  687. ' 3...................2
  688. ' .3.................2.
  689. ' .3.................2.
  690. ' ..3...............2..
  691. ' ...3.............2...
  692. ' ....3...........2....
  693. ' .....33.......22.....
  694. ' .......3333222.......
  695. ' S       = char to draw
  696. ' MyArray = 2D string array to plot circle in
  697.  
  698. Sub PlotSemicircle (X As Integer, Y As Integer, R As Integer, Q As Integer, S As String, MyArray() As String)
  699.     Dim RoutineName As String: RoutineName = "PlotCircleTopLeft"
  700.     Dim A As Integer
  701.     Dim B As Integer
  702.     Dim C As Integer
  703.     Dim S2 As String
  704.     Dim W As Integer
  705.     ReDim arrTemp(0, 0) As String
  706.     Dim DY As Integer
  707.     Dim DX As Integer
  708.     Dim TX As Integer
  709.     Dim TY As Integer
  710.     Dim MinY As Integer
  711.     Dim MaxY As Integer
  712.     Dim MinX As Integer
  713.     Dim MaxX As Integer
  714.  
  715.     ' Get total width
  716.     W = (R * 2) + 1
  717.  
  718.     ' Define a temp array
  719.     ReDim arrTemp(0 To W, 0 To W) As String
  720.  
  721.     ' Get minimum X, Y of target array
  722.     MinY = LBound(MyArray, 1)
  723.     MaxY = UBound(MyArray, 1)
  724.     MinX = LBound(MyArray, 2)
  725.     MaxX = UBound(MyArray, 2)
  726.  
  727.     If Len(S) = 1 Then
  728.         S2 = S
  729.     Else
  730.         If Len(S) = 0 Then
  731.             S2 = " "
  732.         Else
  733.             S2 = Left$(S, 1)
  734.         End If
  735.     End If
  736.  
  737.     If R > 0 Then
  738.         ' Draw circle to temporary array
  739.         B = R
  740.         C = 0
  741.         A = R - 1
  742.         Do
  743.             ' PORTIONS OF CIRCLE:
  744.             ' .......3333222.......
  745.             ' .....33.......22.....
  746.             ' ....3...........2....
  747.             ' ...7.............6...
  748.             ' ..7...............6..
  749.             ' .7.................6.
  750.             ' .7.................6.
  751.             ' 7...................6
  752.             ' 7...................6
  753.             ' 7...................6
  754.             ' 8...................6
  755.             ' 8...................5
  756.             ' 8...................5
  757.             ' 8...................5
  758.             ' .8.................5.
  759.             ' .8.................5.
  760.             ' ..8...............5..
  761.             ' ...8.............5...
  762.             ' ....4...........1....
  763.             ' .....44.......11.....
  764.             ' .......4444111.......
  765.  
  766.             ' JUST PLOT SELECTED QUADRANT:
  767.             Select Case Q
  768.                 Case 1:
  769.                     ' quadrant #1
  770.                     PlotPoint C, R - B, S2, arrTemp() ' 2
  771.                     PlotPoint B, R - C, S2, arrTemp() ' 6
  772.                 Case 2:
  773.                     ' quadrant #2
  774.                     PlotPoint B, C, S2, arrTemp() ' 5
  775.                     PlotPoint C, B, S2, arrTemp() ' 1
  776.                 Case 3:
  777.                     ' quadrant #3
  778.                     PlotPoint R - C, B, S2, arrTemp() ' 4
  779.                     PlotPoint R - B, C, S2, arrTemp() ' 8
  780.                 Case 4:
  781.                     ' quadrant #4
  782.                     PlotPoint R - B, R - C, S2, arrTemp() ' 7
  783.                     PlotPoint R - C, R - B, S2, arrTemp() ' 3
  784.                 Case Else:
  785.                     ' (DO NOTHING)
  786.             End Select
  787.  
  788.             '' PLOT CIRCLE:
  789.             '' quadrant #1
  790.             'PlotPoint R + C, R - B, S2, arrTemp() ' 2
  791.             'PlotPoint R + B, R - C, S2, arrTemp() ' 6
  792.             '
  793.             '' quadrant #2
  794.             'PlotPoint R + B, R + C, S2, arrTemp() ' 5
  795.             'PlotPoint R + C, R + B, S2, arrTemp() ' 1
  796.             '
  797.             '' quadrant #3
  798.             'PlotPoint R - C, R + B, S2, arrTemp() ' 4
  799.             'PlotPoint R - B, R + C, S2, arrTemp() ' 8
  800.             '
  801.             '' quadrant #4
  802.             'PlotPoint R - B, R - C, S2, arrTemp() ' 7
  803.             'PlotPoint R - C, R - B, S2, arrTemp() ' 3
  804.  
  805.             C = C + 1
  806.             A = A + 1 - C - C
  807.             If A < 0 Then
  808.                 B = B - 1
  809.                 A = A + B + B
  810.             End If
  811.             If B < C Then Exit Do
  812.         Loop
  813.  
  814.         ' Copy semicircle to destination Y,X
  815.         For DY = LBound(arrTemp, 1) To UBound(arrTemp, 1)
  816.             For DX = LBound(arrTemp, 2) To UBound(arrTemp, 2)
  817.                 If Len(arrTemp(DY, DX)) > 0 Then
  818.                     TY = Y + DY
  819.                     If TY >= MinY Then
  820.                         If TY <= MaxY Then
  821.                             TX = X + DX
  822.                             If TX >= MinX Then
  823.                                 If TX <= MaxX Then
  824.                                     MyArray(TY, TX) = arrTemp(DY, DX)
  825.                                 End If
  826.                             End If
  827.                         End If
  828.                     End If
  829.                 End If
  830.             Next DX
  831.         Next DY
  832.     End If
  833. End Sub ' PlotSemicircle
  834.  
  835. ' /////////////////////////////////////////////////////////////////////////////
  836.  
  837. Sub PlotSemicircleTest
  838.     Dim MyArray(1 To 32, 1 To 32) As String
  839.     Dim iX As Integer
  840.     Dim iY As Integer
  841.     Dim in$
  842.     Dim X As Integer
  843.     Dim Y As Integer
  844.     Dim R As Integer
  845.     Dim Q As Integer
  846.     Dim iChar As Integer
  847.  
  848.     ClearArray MyArray(), "."
  849.     iChar = 64
  850.  
  851.     Cls
  852.     Print "Plot a semicircle"
  853.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  854.     Print
  855.     Print "Enter parameters to draw a semicircle."
  856.     Print ArrayToStringTest(MyArray())
  857.     Print
  858.  
  859.     Do
  860.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot semicircle,"
  861.         Print "radius (1-32) of semicircle, and quadrant of circle to use:"
  862.         Print "41"
  863.         Print "32"
  864.         Input "X,Y,R,Q OR 0 TO QUIT: "; X, Y, R, Q
  865.         If X > 0 And Y > 0 And R > 0 Then
  866.             iChar = iChar + 1
  867.             If iChar > 90 Then iChar = 65
  868.  
  869.             Print "X=" + cstr$(X)
  870.             Print "Y=" + cstr$(Y)
  871.             Print "R=" + cstr$(R)
  872.  
  873.             PlotSemicircle X, Y, R, Q, Chr$(iChar), MyArray()
  874.  
  875.             Print "Semicircle plotted (from top left), drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  876.             Print ArrayToStringTest(MyArray())
  877.             Print
  878.         Else
  879.             Exit Do
  880.         End If
  881.     Loop
  882.  
  883. End Sub ' PlotSemicircleTest
  884.  
  885. ' /////////////////////////////////////////////////////////////////////////////
  886. ' Re: Is this fast enough as general circle fill?
  887. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg1913#msg1913
  888.  
  889. ' From: SMcNeill
  890. ' Date: « Reply #30 on: June 26, 2018, 03:34:18 pm »
  891. '
  892. ' Sometimes, computers do things that are completely counter-intuitive to us, and
  893. ' we find ourselves having to step back as programmers and simply say, "WOW!!"
  894. ' Here's a perfect example of that:
  895. ' Here we look at two different circle fill routines -- one, which I'd assume to
  896. ' be faster, which precalculates the offset needed to find the endpoints for each
  897. ' line which composes a circle, and another, which is the same old CircleFill
  898. ' program which I've shared countless times over the years with people on various
  899. ' QB64 forums.
  900. '
  901. ' When all is said and done though, CircleFill is STILL even faster than
  902. ' CircleFillFast, which pregenerates those end-points for us!
  903.  
  904. ' CX,CY     = center point of circle
  905. ' R         = radius
  906. ' S         = char to draw
  907. ' MyArray = 2D string array to plot circle in
  908.  
  909. Sub CircleFill (CX As Integer, CY As Integer, R As Integer, S As String, MyArray() As String)
  910.     Dim Radius As Integer
  911.     Dim RadiusError As Integer
  912.     Dim X As Integer
  913.     Dim Y As Integer
  914.     Dim iLoopX As Integer
  915.     Dim iLoopY As Integer
  916.  
  917.     Radius = Abs(R)
  918.     RadiusError = -Radius
  919.     X = Radius
  920.     Y = 0
  921.  
  922.     If Radius = 0 Then
  923.         'PSET (CX, CY), C
  924.         'PlotPoint CX, CY, S, MyArray()
  925.         Exit Sub
  926.     End If
  927.  
  928.     ' Draw the middle span here so we don't draw it twice in the main loop,
  929.     ' which would be a problem with blending turned on.
  930.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  931.     For iLoopX = CX - X To CX + X
  932.         PlotPoint iLoopX, CY, S, MyArray()
  933.     Next iLoopX
  934.  
  935.     While X > Y
  936.         RadiusError = RadiusError + Y * 2 + 1
  937.         If RadiusError >= 0 Then
  938.             If X <> Y + 1 Then
  939.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  940.                 iLoopY = CY - X
  941.                 For iLoopX = CX - Y To CX + Y
  942.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  943.                 Next iLoopX
  944.  
  945.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  946.                 iLoopY = CY + X
  947.                 For iLoopX = CX - Y To CX + Y
  948.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  949.                 Next iLoopX
  950.             End If
  951.             X = X - 1
  952.             RadiusError = RadiusError - X * 2
  953.         End If
  954.         Y = Y + 1
  955.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  956.         iLoopY = CY - Y
  957.         For iLoopX = CX - X To CX + X
  958.             PlotPoint iLoopX, iLoopY, S, MyArray()
  959.         Next iLoopX
  960.  
  961.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  962.         iLoopY = CY + Y
  963.         For iLoopX = CX - X To CX + X
  964.             PlotPoint iLoopX, iLoopY, S, MyArray()
  965.         Next iLoopX
  966.     Wend
  967. End Sub ' CircleFill
  968.  
  969. ' /////////////////////////////////////////////////////////////////////////////
  970.  
  971. Sub CircleFillTest
  972.     Dim MyArray(1 To 32, 1 To 32) As String
  973.     Dim iX As Integer
  974.     Dim iY As Integer
  975.     Dim in$
  976.     Dim X As Integer
  977.     Dim Y As Integer
  978.     Dim R As Integer
  979.     Dim iChar As Integer
  980.  
  981.     ClearArray MyArray(), "."
  982.     iChar = 64
  983.  
  984.     Cls
  985.     Print "Plot a filled circle"
  986.     Print "Based on CircleFill by SMcNeill."
  987.     Print
  988.     Print "Enter parameters to draw a circle."
  989.     Print ArrayToStringTest(MyArray())
  990.     Print
  991.  
  992.     Do
  993.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  994.         Print "and radius (1-32) of circle."
  995.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  996.         If X > 0 And Y > 0 And R > 0 Then
  997.             iChar = iChar + 1
  998.             If iChar > 90 Then iChar = 65
  999.  
  1000.             Print "X=" + cstr$(X)
  1001.             Print "Y=" + cstr$(Y)
  1002.             Print "R=" + cstr$(R)
  1003.  
  1004.             'PlotCircle X, Y, R, Chr$(iChar), MyArray()
  1005.             CircleFill X, Y, R, Chr$(iChar), MyArray()
  1006.  
  1007.             Print "Circle plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1008.             Print ArrayToStringTest(MyArray())
  1009.             Print
  1010.         Else
  1011.             Exit Do
  1012.         End If
  1013.     Loop
  1014.  
  1015. End Sub ' CircleFillTest
  1016.  
  1017. ' /////////////////////////////////////////////////////////////////////////////
  1018. ' Based on CircleFill and PlotCircleTopLeft.
  1019. ' CX,CY     = top left point of circle
  1020. ' R         = radius
  1021. ' S         = char to draw
  1022. ' MyArray = 2D string array to plot circle in
  1023.  
  1024. Sub CircleFillTopLeft (CX As Integer, CY As Integer, R As Integer, S As String, MyArray() As String)
  1025.     Dim Radius As Integer
  1026.     Dim RadiusError As Integer
  1027.     Dim X As Integer
  1028.     Dim Y As Integer
  1029.     Dim iLoopX As Integer
  1030.     Dim iLoopY As Integer
  1031.     ReDim arrTemp(0, 0) As String
  1032.     Dim DY As Integer
  1033.     Dim DX As Integer
  1034.     Dim W As Integer
  1035.     Dim TX As Integer
  1036.     Dim TY As Integer
  1037.     Dim MinY As Integer
  1038.     Dim MaxY As Integer
  1039.     Dim MinX As Integer
  1040.     Dim MaxX As Integer
  1041.  
  1042.     Radius = Abs(R)
  1043.     RadiusError = -Radius
  1044.     X = Radius
  1045.     Y = 0
  1046.  
  1047.     If Radius = 0 Then
  1048.         'PSET (CX, CY), C
  1049.         'PlotPoint CX, CY, S, MyArray()
  1050.         Exit Sub
  1051.     End If
  1052.  
  1053.     ' Get total width
  1054.     W = (Radius * 2) + 1
  1055.  
  1056.     ' Define a temp array
  1057.     ReDim arrTemp(0 To W, 0 To W) As String
  1058.  
  1059.     ' Get minimum X, Y of target array
  1060.     MinY = LBound(MyArray, 1)
  1061.     MaxY = UBound(MyArray, 1)
  1062.     MinX = LBound(MyArray, 2)
  1063.     MaxX = UBound(MyArray, 2)
  1064.  
  1065.     ' Draw the middle span here so we don't draw it twice in the main loop,
  1066.     ' which would be a problem with blending turned on.
  1067.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  1068.     'FOR iLoopX = CX - X TO CX + X
  1069.     For iLoopX = R - X To R + X
  1070.         'PlotPoint iLoopX, CY, S, MyArray()
  1071.         'PlotPoint iLoopX, CY, S, arrTemp()
  1072.         PlotPoint iLoopX, R, S, arrTemp()
  1073.     Next iLoopX
  1074.  
  1075.     While X > Y
  1076.         RadiusError = RadiusError + Y * 2 + 1
  1077.         If RadiusError >= 0 Then
  1078.             If X <> Y + 1 Then
  1079.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1080.                 'iLoopY = CY - X
  1081.                 iLoopY = R - X
  1082.                 'FOR iLoopX = CX - Y TO CX + Y
  1083.                 For iLoopX = R - Y To R + Y
  1084.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1085.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1086.                 Next iLoopX
  1087.  
  1088.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1089.                 'iLoopY = CY + X
  1090.                 iLoopY = R + X
  1091.                 'FOR iLoopX = CX - Y TO CX + Y
  1092.                 For iLoopX = R - Y To R + Y
  1093.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1094.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1095.                 Next iLoopX
  1096.             End If
  1097.             X = X - 1
  1098.             RadiusError = RadiusError - X * 2
  1099.         End If
  1100.         Y = Y + 1
  1101.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1102.         'iLoopY = CY - Y
  1103.         iLoopY = R - Y
  1104.         'FOR iLoopX = CX - X TO CX + X
  1105.         For iLoopX = R - X To R + X
  1106.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1107.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1108.         Next iLoopX
  1109.  
  1110.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1111.         'iLoopY = CY + Y
  1112.         iLoopY = R + Y
  1113.         'FOR iLoopX = CX - X TO CX + X
  1114.         For iLoopX = R - X To R + X
  1115.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1116.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1117.         Next iLoopX
  1118.     Wend
  1119.  
  1120.     ' Copy circle to destination Y,X
  1121.     For DY = LBound(arrTemp, 1) To UBound(arrTemp, 1)
  1122.         For DX = LBound(arrTemp, 2) To UBound(arrTemp, 2)
  1123.             If Len(arrTemp(DY, DX)) > 0 Then
  1124.                 TY = DY + CY
  1125.                 If TY >= MinY Then
  1126.                     If TY <= MaxY Then
  1127.                         TX = DX + CX
  1128.                         If TX >= MinX Then
  1129.                             If TX <= MaxX Then
  1130.                                 MyArray(TY, TX) = arrTemp(DY, DX)
  1131.                             End If
  1132.                         End If
  1133.                     End If
  1134.                 End If
  1135.             End If
  1136.         Next DX
  1137.     Next DY
  1138.  
  1139. End Sub ' CircleFillTopLeft
  1140.  
  1141. ' /////////////////////////////////////////////////////////////////////////////
  1142.  
  1143. Sub CircleFillTopLeftTest
  1144.     Dim MyArray(1 To 32, 1 To 32) As String
  1145.     Dim iX As Integer
  1146.     Dim iY As Integer
  1147.     Dim in$
  1148.     Dim X As Integer
  1149.     Dim Y As Integer
  1150.     Dim R As Integer
  1151.     Dim iChar As Integer
  1152.  
  1153.     ClearArray MyArray(), "."
  1154.     iChar = 64
  1155.  
  1156.     Cls
  1157.     Print "Plot a solid circle, specifying top left x,y position"
  1158.     Print "Based on CircleFill by SMcNeill."
  1159.     Print
  1160.     Print "Enter parameters to draw a circle."
  1161.     Print ArrayToStringTest(MyArray())
  1162.     Print
  1163.  
  1164.     Do
  1165.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot circle,"
  1166.         Print "and radius (1-32) of circle."
  1167.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  1168.         If X > 0 And Y > 0 And R > 0 Then
  1169.             iChar = iChar + 1
  1170.             If iChar > 90 Then iChar = 65
  1171.  
  1172.             Print "X=" + cstr$(X)
  1173.             Print "Y=" + cstr$(Y)
  1174.             Print "R=" + cstr$(R)
  1175.  
  1176.             CircleFillTopLeft X, Y, R, Chr$(iChar), MyArray()
  1177.  
  1178.             Print "Circle plotted (from top left), drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1179.             Print ArrayToStringTest(MyArray())
  1180.             Print
  1181.         Else
  1182.             Exit Do
  1183.         End If
  1184.     Loop
  1185.  
  1186. End Sub ' CircleFillTopLeftTest
  1187.  
  1188. ' /////////////////////////////////////////////////////////////////////////////
  1189. ' Based on CircleFill and PlotSemiCircle
  1190.  
  1191. ' CX,CY   = top left point of circle
  1192. ' R       = radius
  1193. ' Q       = which quarter of the circle to return semicircle from
  1194. '           where 1=top right, 2=bottom right, 3=bottom left, 4=top left
  1195. '           like this:
  1196. ' .......4444111.......
  1197. ' .....44444411111.....
  1198. ' ....4444444111111....
  1199. ' ...444444441111111...
  1200. ' ..44444444411111111..
  1201. ' .4444444444111111111.
  1202. ' .4444444444111111111.
  1203. ' 444444444441111111111
  1204. ' 444444444441111111111
  1205. ' 444444444441111111111
  1206. ' 333333333331111111111
  1207. ' 333333333332222222222
  1208. ' 333333333332222222222
  1209. ' 333333333332222222222
  1210. ' .3333333333222222222.
  1211. ' .3333333333222222222.
  1212. ' ..33333333322222222..
  1213. ' ...333333332222222...
  1214. ' ....3333333222222....
  1215. ' .....33333322222.....
  1216. ' .......3333222.......
  1217. ' S       = char to draw
  1218. ' MyArray = 2D string array to plot semicircle in
  1219.  
  1220. Sub SemiCircleFill (CX As Integer, CY As Integer, R As Integer, Q As Integer, S As String, MyArray() As String)
  1221.     Dim Radius As Integer
  1222.     Dim RadiusError As Integer
  1223.     Dim X As Integer
  1224.     Dim Y As Integer
  1225.     Dim iLoopX As Integer
  1226.     Dim iLoopY As Integer
  1227.     ReDim arrTemp(0, 0) As String
  1228.     Dim DY As Integer
  1229.     Dim DX As Integer
  1230.     Dim W As Integer
  1231.     Dim AX As Integer
  1232.     Dim AY As Integer
  1233.     Dim TX As Integer
  1234.     Dim TY As Integer
  1235.     Dim MinY As Integer
  1236.     Dim MaxY As Integer
  1237.     Dim MinX As Integer
  1238.     Dim MaxX As Integer
  1239.  
  1240.     Radius = Abs(R)
  1241.     RadiusError = -Radius
  1242.     X = Radius
  1243.     Y = 0
  1244.  
  1245.     If Radius = 0 Then
  1246.         'PSET (CX, CY), C
  1247.         'PlotPoint CX, CY, S, MyArray()
  1248.         Exit Sub
  1249.     End If
  1250.  
  1251.     ' Get total width
  1252.     W = (Radius * 2) + 1
  1253.  
  1254.     ' Define a temp array
  1255.     ReDim arrTemp(0 To W, 0 To W) As String
  1256.  
  1257.     ' Get minimum X, Y of target array
  1258.     MinY = LBound(MyArray, 1)
  1259.     MaxY = UBound(MyArray, 1)
  1260.     MinX = LBound(MyArray, 2)
  1261.     MaxX = UBound(MyArray, 2)
  1262.  
  1263.     ' Temp array's lbound is 0
  1264.     ' Calculate difference from MyArray the indices of arrTemp are
  1265.     AY = 0 - MinY
  1266.     AX = 0 - MinX
  1267.  
  1268.     ' Draw the middle span here so we don't draw it twice in the main loop,
  1269.     ' which would be a problem with blending turned on.
  1270.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  1271.     'FOR iLoopX = CX - X TO CX + X
  1272.     For iLoopX = R - X To R + X
  1273.         'PlotPoint iLoopX, CY, S, MyArray()
  1274.         'PlotPoint iLoopX, CY, S, arrTemp()
  1275.         PlotPoint iLoopX, R, S, arrTemp()
  1276.     Next iLoopX
  1277.  
  1278.     While X > Y
  1279.         RadiusError = RadiusError + Y * 2 + 1
  1280.         If RadiusError >= 0 Then
  1281.             If X <> Y + 1 Then
  1282.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  1283.                 'iLoopY = CY - X
  1284.                 iLoopY = R - X
  1285.                 'FOR iLoopX = CX - Y TO CX + Y
  1286.                 For iLoopX = R - Y To R + Y
  1287.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1288.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1289.                 Next iLoopX
  1290.  
  1291.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  1292.                 'iLoopY = CY + X
  1293.                 iLoopY = R + X
  1294.                 'FOR iLoopX = CX - Y TO CX + Y
  1295.                 For iLoopX = R - Y To R + Y
  1296.                     'PlotPoint iLoopX, iLoopY, S, MyArray()
  1297.                     PlotPoint iLoopX, iLoopY, S, arrTemp()
  1298.                 Next iLoopX
  1299.             End If
  1300.             X = X - 1
  1301.             RadiusError = RadiusError - X * 2
  1302.         End If
  1303.         Y = Y + 1
  1304.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  1305.         'iLoopY = CY - Y
  1306.         iLoopY = R - Y
  1307.         'FOR iLoopX = CX - X TO CX + X
  1308.         For iLoopX = R - X To R + X
  1309.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1310.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1311.         Next iLoopX
  1312.  
  1313.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  1314.         'iLoopY = CY + Y
  1315.         iLoopY = R + Y
  1316.         'FOR iLoopX = CX - X TO CX + X
  1317.         For iLoopX = R - X To R + X
  1318.             'PlotPoint iLoopX, iLoopY, S, MyArray()
  1319.             PlotPoint iLoopX, iLoopY, S, arrTemp()
  1320.         Next iLoopX
  1321.     Wend
  1322.  
  1323.     '_echo "MyArray(" + _Trim$(Str$(lbound(MyArray,1))) + " To " + _Trim$(Str$(ubound(MyArray,1))) + ", " + _Trim$(Str$(lbound(MyArray,2))) + " To " + _Trim$(Str$(ubound(MyArray,2))) + ")"
  1324.  
  1325.     ' Copy semicircle to destination Y,X
  1326.     ' JUST COPY SELECTED QUADRANT:
  1327.     Select Case Q
  1328.         Case 1:
  1329.             ' quadrant #1
  1330.             For DY = 0 To Radius
  1331.                 For DX = Radius To W
  1332.                     '_echo "DY=" + cstr$(DY) + ", DX=" + cstr$(DX)
  1333.                     If Len(arrTemp(DY, DX)) > 0 Then
  1334.                         TY = (DY + CY) - (AY + 1)
  1335.                         If TY >= MinY Then
  1336.                             If TY <= MaxY Then
  1337.                                 TX = (DX - Radius) - AX
  1338.                                 If TX >= MinX Then
  1339.                                     If TX <= MaxX Then
  1340.                                         MyArray(TY, TX) = arrTemp(DY, DX)
  1341.                                     End If
  1342.                                 End If
  1343.                             End If
  1344.                         End If
  1345.                     End If
  1346.                 Next DX
  1347.             Next DY
  1348.         Case 2:
  1349.             ' quadrant #2
  1350.             For DY = Radius To W
  1351.                 For DX = Radius To W
  1352.                     If Len(arrTemp(DY, DX)) > 0 Then
  1353.                         TY = (DY - Radius) - AY
  1354.                         If TY >= MinY Then
  1355.                             If TY <= MaxY Then
  1356.                                 TX = (DX - Radius) - AX
  1357.                                 If TX >= MinX Then
  1358.                                     If TX <= MaxX Then
  1359.                                         MyArray(TY, TX) = arrTemp(DY, DX)
  1360.                                     End If
  1361.                                 End If
  1362.                             End If
  1363.                         End If
  1364.                     End If
  1365.                 Next DX
  1366.             Next DY
  1367.         Case 3:
  1368.             ' quadrant #3
  1369.             For DY = Radius To W
  1370.                 For DX = 0 To Radius
  1371.                     If Len(arrTemp(DY, DX)) > 0 Then
  1372.                         TY = (DY - Radius) - AY
  1373.                         If TY >= MinY Then
  1374.                             If TY <= MaxY Then
  1375.                                 TX = (DX + CX) - (AX + 1)
  1376.                                 If TX >= MinX Then
  1377.                                     If TX <= MaxX Then
  1378.                                         MyArray(TY, TX) = arrTemp(DY, DX)
  1379.                                     End If
  1380.                                 End If
  1381.                             End If
  1382.                         End If
  1383.                     End If
  1384.                 Next DX
  1385.             Next DY
  1386.         Case 4:
  1387.             ' quadrant #4
  1388.             For DY = 0 To Radius
  1389.                 For DX = 0 To Radius
  1390.                     If Len(arrTemp(DY, DX)) > 0 Then
  1391.                         TY = (DY + CY) - (AY + 1)
  1392.                         If TY >= MinY Then
  1393.                             If TY <= MaxY Then
  1394.                                 TX = (DX + CX) - (AX + 1)
  1395.                                 If TX >= MinX Then
  1396.                                     If TX <= MaxX Then
  1397.                                         MyArray(TY, TX) = arrTemp(DY, DX)
  1398.                                     End If
  1399.                                 End If
  1400.                             End If
  1401.                         End If
  1402.                     End If
  1403.                 Next DX
  1404.             Next DY
  1405.         Case Else:
  1406.             ' (DO NOTHING)
  1407.     End Select
  1408.  
  1409.     '' Copy circle to destination:
  1410.     'For DY = lbound(arrTemp, 1) to ubound(arrTemp, 1)
  1411.     '    For DX = lbound(arrTemp, 2) to ubound(arrTemp, 2)
  1412.     '        IF LEN(arrTemp(DY, DX)) > 0 THEN
  1413.     '            MyArray(DY + CY, DX + CX) = arrTemp(DY, DX)
  1414.     '        END IF
  1415.     '    Next DX
  1416.     'Next DY
  1417.  
  1418. End Sub ' SemiCircleFill
  1419.  
  1420. ' /////////////////////////////////////////////////////////////////////////////
  1421.  
  1422. Sub SemiCircleFillTest
  1423.     Dim MyArray(1 To 32, 1 To 32) As String
  1424.     Dim iX As Integer
  1425.     Dim iY As Integer
  1426.     Dim in$
  1427.     Dim X As Integer
  1428.     Dim Y As Integer
  1429.     Dim R As Integer
  1430.     Dim Q As Integer
  1431.     Dim iChar As Integer
  1432.  
  1433.     ClearArray MyArray(), "."
  1434.     iChar = 64
  1435.  
  1436.     Cls
  1437.     Print "Plot a solid semicircle"
  1438.     Print "Based on CircleFill by SMcNeill."
  1439.     Print
  1440.     Print "Enter parameters to draw a semicircle."
  1441.     Print ArrayToStringTest(MyArray())
  1442.     Print
  1443.  
  1444.     Do
  1445.         Print "Type top left point x,y (1-32, 1-32) coordinate to plot semicircle,"
  1446.         Print "radius (1-32) of semicircle, and quadrant of circle to use:"
  1447.         Print "41"
  1448.         Print "32"
  1449.         Input "X,Y,R,Q OR 0 TO QUIT: "; X, Y, R, Q
  1450.         If X > 0 And Y > 0 And R > 0 Then
  1451.             iChar = iChar + 1
  1452.             If iChar > 90 Then iChar = 65
  1453.  
  1454.             Print "X=" + cstr$(X)
  1455.             Print "Y=" + cstr$(Y)
  1456.             Print "R=" + cstr$(R)
  1457.  
  1458.             SemiCircleFill X, Y, R, Q, Chr$(iChar), MyArray()
  1459.  
  1460.             Print "Semicircle plotted (from top left), drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1461.             Print ArrayToStringTest(MyArray())
  1462.             Print
  1463.         Else
  1464.             Exit Do
  1465.         End If
  1466.     Loop
  1467.  
  1468. End Sub ' SemiCircleFillTest
  1469.  
  1470. ' /////////////////////////////////////////////////////////////////////////////
  1471. ' Re: Is this fast enough as general circle fill?
  1472. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  1473.  
  1474. ' From: bplus
  1475. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  1476.  
  1477. Sub Ellipse (CX As Integer, CY As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String)
  1478.     Dim scale As Single
  1479.     Dim xs As Integer
  1480.     Dim x As Integer
  1481.     Dim y As Integer
  1482.     Dim lastx As Integer
  1483.     Dim lasty As Integer
  1484.     Dim iLoopX As Integer
  1485.     Dim iLoopY As Integer
  1486.  
  1487.     scale = yRadius / xRadius
  1488.     xs = xRadius * xRadius
  1489.  
  1490.     'PSET (CX, CY - yRadius)
  1491.     PlotPoint CX, CY - yRadius, S, MyArray()
  1492.  
  1493.     'PSET (CX, CY + yRadius)
  1494.     PlotPoint CX, CY + yRadius, S, MyArray()
  1495.  
  1496.     lastx = 0: lasty = yRadius
  1497.     For x = 1 To xRadius
  1498.         y = scale * Sqr(xs - x * x)
  1499.         'LINE (CX + lastx, CY - lasty)-(CX + x, CY - y)
  1500.         PlotLine CX + lastx, CY - lasty, CX + x, CY - y, S, MyArray()
  1501.  
  1502.         'LINE (CX + lastx, CY + lasty)-(CX + x, CY + y)
  1503.         PlotLine CX + lastx, CY + lasty, CX + x, CY + y, S, MyArray()
  1504.  
  1505.         'LINE (CX - lastx, CY - lasty)-(CX - x, CY - y)
  1506.         PlotLine CX - lastx, CY - lasty, CX - x, CY - y, S, MyArray()
  1507.  
  1508.         'LINE (CX - lastx, CY + lasty)-(CX - x, CY + y)
  1509.         PlotLine CX - lastx, CY + lasty, CX - x, CY + y, S, MyArray()
  1510.  
  1511.         lastx = x
  1512.         lasty = y
  1513.     Next x
  1514. End Sub ' Ellipse
  1515.  
  1516. ' /////////////////////////////////////////////////////////////////////////////
  1517.  
  1518. Sub EllipseTest
  1519.     Dim MyArray(1 To 32, 1 To 32) As String
  1520.     Dim iX As Integer
  1521.     Dim iY As Integer
  1522.     Dim in$
  1523.     Dim X As Integer
  1524.     Dim Y As Integer
  1525.     Dim RX As Integer
  1526.     Dim RY As Integer
  1527.     Dim iChar As Integer
  1528.  
  1529.     ClearArray MyArray(), "."
  1530.     iChar = 64
  1531.  
  1532.     Cls
  1533.     Print "Plot an ellipse"
  1534.     Print "Based on ellipse by bplus."
  1535.     Print
  1536.     Print "Enter parameters to draw an ellipse."
  1537.     Print ArrayToStringTest(MyArray())
  1538.     Print
  1539.  
  1540.     Do
  1541.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  1542.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  1543.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  1544.         If X > 0 And Y > 0 And RX > 0 And RY > 0 Then
  1545.             iChar = iChar + 1
  1546.             If iChar > 90 Then iChar = 65
  1547.  
  1548.             Print "X =" + cstr$(X)
  1549.             Print "Y =" + cstr$(Y)
  1550.             Print "RX=" + cstr$(RX)
  1551.             Print "RY=" + cstr$(RY)
  1552.  
  1553.             Ellipse X, Y, RX, RY, Chr$(iChar), MyArray()
  1554.  
  1555.             Print "Ellipse plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1556.             Print ArrayToStringTest(MyArray())
  1557.             Print
  1558.         Else
  1559.             Exit Do
  1560.         End If
  1561.     Loop
  1562.  
  1563. End Sub ' EllipseTest
  1564.  
  1565. ' /////////////////////////////////////////////////////////////////////////////
  1566. ' Re: Is this fast enough as general circle fill?
  1567. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  1568.  
  1569. ' From: bplus
  1570. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  1571. '
  1572. ' Here is my ellipse and filled ellipse routines, no where near
  1573. ' Steve's level of performance. The speed is cut in half at
  1574. ' least because you probably have to do a whole quadrants worth
  1575. ' of calculations (ellipse not as symmetric as circle).
  1576. '
  1577. ' But I am sure this code can be optimized more than it is:
  1578.  
  1579. Sub EllipseFill (CX As Integer, CY As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String)
  1580.     Dim scale As Single
  1581.     Dim x As Integer
  1582.     Dim y As Integer
  1583.     Dim iLoopX As Integer
  1584.     Dim iLoopY As Integer
  1585.  
  1586.     scale = yRadius / xRadius
  1587.  
  1588.     'LINE (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  1589.     For iLoopY = CY - yRadius To CY + yRadius
  1590.         PlotPoint CX, iLoopY, S, MyArray()
  1591.     Next iLoopY
  1592.  
  1593.     For x = 1 To xRadius
  1594.         y = scale * Sqr(xRadius * xRadius - x * x)
  1595.  
  1596.         'LINE (CX + x, CY - y)-(CX + x, CY + y), , BF
  1597.         iLoopX = CX + x
  1598.         For iLoopY = CY - y To CY + y
  1599.             PlotPoint iLoopX, iLoopY, S, MyArray()
  1600.         Next iLoopY
  1601.  
  1602.         'LINE (CX - x, CY - y)-(CX - x, CY + y), , BF
  1603.         iLoopX = CX - x
  1604.         For iLoopY = CY - y To CY + y
  1605.             PlotPoint iLoopX, iLoopY, S, MyArray()
  1606.         Next iLoopY
  1607.     Next x
  1608. End Sub ' EllipseFill
  1609.  
  1610. ' /////////////////////////////////////////////////////////////////////////////
  1611.  
  1612. Sub EllipseFillTest
  1613.     Dim MyArray(1 To 32, 1 To 32) As String
  1614.     Dim iX As Integer
  1615.     Dim iY As Integer
  1616.     Dim in$
  1617.     Dim X As Integer
  1618.     Dim Y As Integer
  1619.     Dim RX As Integer
  1620.     Dim RY As Integer
  1621.     Dim iChar As Integer
  1622.  
  1623.     ClearArray MyArray(), "."
  1624.     iChar = 64
  1625.  
  1626.     Cls
  1627.     Print "Plot a filled ellipse"
  1628.     Print "Based on fellipse by bplus."
  1629.     Print
  1630.     Print "Enter parameters to draw an ellipse."
  1631.     Print ArrayToStringTest(MyArray())
  1632.     Print
  1633.  
  1634.     Do
  1635.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  1636.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  1637.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  1638.         If X > 0 And Y > 0 And RX > 0 And RY > 0 Then
  1639.             iChar = iChar + 1
  1640.             If iChar > 90 Then iChar = 65
  1641.  
  1642.             Print "X =" + cstr$(X)
  1643.             Print "Y =" + cstr$(Y)
  1644.             Print "RX=" + cstr$(RX)
  1645.             Print "RY=" + cstr$(RY)
  1646.  
  1647.             EllipseFill X, Y, RX, RY, Chr$(iChar), MyArray()
  1648.  
  1649.             Print "Ellipse plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1650.             Print ArrayToStringTest(MyArray())
  1651.             Print
  1652.         Else
  1653.             Exit Do
  1654.         End If
  1655.     Loop
  1656.  
  1657. End Sub ' EllipseFillTest
  1658.  
  1659. ' /////////////////////////////////////////////////////////////////////////////
  1660. ' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
  1661. ' From: http://www.thedubber.altervista.org/qbsrc.htm
  1662.  
  1663. Sub PlotLine (x1%, y1%, x2%, y2%, c$, MyArray() As String)
  1664.     Dim iLoop%
  1665.     Dim steep%: steep% = 0
  1666.     Dim ev%: ev% = 0
  1667.     Dim sx%
  1668.     Dim sy%
  1669.     Dim dx%
  1670.     Dim dy%
  1671.  
  1672.     If (x2% - x1%) > 0 Then
  1673.         sx% = 1
  1674.     Else
  1675.         sx% = -1
  1676.     End If
  1677.  
  1678.     dx% = Abs(x2% - x1%)
  1679.     If (y2% - y1%) > 0 Then
  1680.         sy% = 1
  1681.     Else
  1682.         sy% = -1
  1683.     End If
  1684.  
  1685.     dy% = Abs(y2% - y1%)
  1686.     If (dy% > dx%) Then
  1687.         steep% = 1
  1688.         Swap x1%, y1%
  1689.         Swap dx%, dy%
  1690.         Swap sx%, sy%
  1691.     End If
  1692.  
  1693.     ev% = 2 * dy% - dx%
  1694.     For iLoop% = 0 To dx% - 1
  1695.         If steep% = 1 Then
  1696.             ''PSET (y1%, x1%), c%:
  1697.             'LOCATE y1%, x1%
  1698.             'PRINT c$;
  1699.             PlotPoint y1%, x1%, c$, MyArray()
  1700.         Else
  1701.             ''PSET (x1%, y1%), c%
  1702.             'LOCATE x1%, y1%
  1703.             'PRINT c$;
  1704.             PlotPoint x1%, y1%, c$, MyArray()
  1705.         End If
  1706.  
  1707.         While ev% >= 0
  1708.             y1% = y1% + sy%
  1709.             ev% = ev% - 2 * dx%
  1710.         Wend
  1711.         x1% = x1% + sx%
  1712.         ev% = ev% + 2 * dy%
  1713.     Next iLoop%
  1714.     ''PSET (x2%, y2%), c%
  1715.     'LOCATE x2%, y2%
  1716.     'PRINT c$;
  1717.     PlotPoint x2%, y2%, c$, MyArray()
  1718. End Sub ' PlotLine
  1719.  
  1720. ' /////////////////////////////////////////////////////////////////////////////
  1721.  
  1722. Sub PlotLineTest
  1723.     Dim MyArray(1 To 32, 1 To 32) As String
  1724.     Dim in$
  1725.     Dim X1 As Integer
  1726.     Dim Y1 As Integer
  1727.     Dim X2 As Integer
  1728.     Dim Y2 As Integer
  1729.     Dim iChar As Integer
  1730.  
  1731.     ClearArray MyArray(), "."
  1732.     iChar = 64
  1733.  
  1734.     Cls
  1735.     Print "Plot line with Bresenham Algorithm"
  1736.     Print "based on BRESNHAM.BAS by Kurt Kuzba (4/16/96)."
  1737.     Print
  1738.     Print ArrayToStringTest(MyArray())
  1739.     Do
  1740.         Print "Enter coordinate values for "
  1741.         Print "line start point x1, y1 (1-32, 1-32)"
  1742.         Print "line end   point x2, y2 (1-32, 1-32)"
  1743.         Input "ENTER X1,Y1,X2,Y2 OR 0 TO QUIT: "; X1, Y1, X2, Y2
  1744.         If X1 > 0 And Y1 > 0 And X2 > 0 And Y2 > 0 Then
  1745.             iChar = iChar + 1
  1746.             If iChar > 90 Then iChar = 65
  1747.  
  1748.             Print "X1=" + cstr$(X1)
  1749.             Print "Y1=" + cstr$(Y1)
  1750.             Print "X2=" + cstr$(X2)
  1751.             Print "Y2=" + cstr$(Y2)
  1752.  
  1753.             PlotLine X1, Y1, X2, Y2, Chr$(iChar), MyArray()
  1754.  
  1755.             Print "Line plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  1756.             Print ArrayToStringTest(MyArray())
  1757.  
  1758.         Else
  1759.             Exit Do
  1760.         End If
  1761.     Loop
  1762. End Sub ' PlotLineTest
  1763.  
  1764. ' /////////////////////////////////////////////////////////////////////////////
  1765. ' 3 shear method testing
  1766.  
  1767. ' _PUT Rotation Help
  1768. ' https://www.qb64.org/forum/index.php?topic=1959.0
  1769.  
  1770. ' 3 Shear Rotation - rotates without any aliasing(holes)
  1771. ' https://www.freebasic.net/forum/viewtopic.php?t=24557
  1772.  
  1773. ' From: leopardpm
  1774. ' Date: Apr 02, 2016 1:21
  1775. ' Last edited by leopardpm on Apr 02, 2016 17:18, edited 1 time in total.
  1776. '
  1777. ' This is just a little 3-shear rotation routine
  1778. ' (I am using 3-shear because it leaves no gaps/aliasing)
  1779. ' that I was wondering if anyone sees how to make it faster.
  1780. ' Obviously, I am just thinking about inside the double loop.
  1781.  
  1782. ' Thanks again to BasicCoder2 for linking me to this little routine, it is wonderful so far!
  1783.  
  1784. '''                      roto-zooming algorithm
  1785. '''                    coded by Michael S. Nissen
  1786. '''                        jernmager@yahoo.dk
  1787. '
  1788. ''' ===============================================================
  1789. ''' Recoded to run on FBC 32/64 bit WIN, Version 1.05.0, 2016, by MrSwiss
  1790. ''' Heavy flickering before going Full-Screen on 64 Bit !!!
  1791. ''' This seems NOT to be the Case on 32 Bit ...
  1792. ''' ===============================================================
  1793. '
  1794. 'Type Pixel
  1795. '  As Single   X, Y
  1796. '  As ULong    C
  1797. 'End Type
  1798. '
  1799. '''  dim vars
  1800. 'Dim shared as Any Ptr Img_Buffer
  1801. '''  write the name of the .bmp image you want to rotozoom here:
  1802. '''  (it has to be sqare ie. 100x100 pixels, 760x760 pixels or whatever)
  1803. 'Dim As String Img_Name = "phobos.bmp"
  1804. 'Dim shared as Integer X_Mid, Y_Mid, scrn_wid, scrn_hgt, P1, P2, P3, P4, C
  1805. 'Dim shared as Short Img_Hgt, Img_Wid, Img_Lft, Img_Rgt, Img_Top, Img_Btm, X, Y
  1806. 'Dim Shared As Single Cos_Ang, Sin_Ang, Rot_Fac_X, Rot_Fac_Y, Angle = 0, Scale = 1
  1807. '
  1808. ''' changed Function to Sub (+ recoded arguments list)
  1809. 'Sub Calc_rotozoom ( ByRef Cos_Ang As Single, _
  1810. '               ByRef Sin_Ang As Single, _
  1811. '               ByVal S_Fact  As Single, _
  1812. '               ByVal NewAng  As Single )
  1813. '  Cos_Ang = Cos(NewAng)*S_Fact
  1814. '  Sin_Ang = Sin(NewAng)*S_Fact
  1815. 'End Sub
  1816. '
  1817. '''  full screen
  1818. 'ScreenInfo scrn_wid, scrn_hgt
  1819. 'screenRes scrn_wid, scrn_hgt, 32,,1
  1820. '
  1821. '''  dim screenpointer (has to be done after screenres)
  1822. 'Dim As ULong Ptr Scrn_Ptr = Screenptr
  1823. '
  1824. '''  place image in center of screen
  1825. 'X_Mid = scrn_wid\2
  1826. 'Y_Mid = scrn_hgt\2
  1827. 'Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1828. '
  1829. '''  find image dimensions
  1830. 'Open Img_Name For Binary As #1
  1831. 'Get #1, 19, Img_Wid
  1832. 'Get #1, 23, Img_Hgt
  1833. 'Close #1
  1834. '
  1835. '''  prepare to dim the array that will hold the image.
  1836. 'Img_Rgt = (Img_Wid-1)\2
  1837. 'Img_Lft = -Img_Rgt
  1838. 'Img_Btm = (Img_Hgt-1)\2
  1839. 'Img_Top = -Img_Btm
  1840. '
  1841. '''  dim array to hold image. Note: pixel (0, 0) is in the center.
  1842. 'Dim As Pixel Pixel(Img_Lft to Img_Rgt, Img_Top to Img_Btm)
  1843. '
  1844. '''  imagecreate sprite and load image to sprite
  1845. 'Img_Buffer = ImageCreate (Img_Wid, Img_Hgt)
  1846. 'Bload (Img_Name, Img_Buffer)
  1847. '
  1848. '''  load image from sprite to array with point command
  1849. 'For Y = Img_Top to Img_Btm
  1850. '  For X = Img_Lft to Img_Rgt
  1851. '    With Pixel(X, Y)
  1852. '      .X = X_Mid+X
  1853. '      .Y = Y_Mid+Y
  1854. '      C = Point (X-Img_Top, Y-Img_Lft, Img_buffer)
  1855. '      If C <> RGB(255, 0, 255) Then
  1856. '        .C = C
  1857. '      Else
  1858. '        .C = RGB(0, 0, 0)
  1859. '      End If
  1860. '    End With
  1861. '  Next X
  1862. 'Next Y
  1863. '
  1864. '''  we don't need the sprite anymore, kill it
  1865. 'ImageDestroy Img_Buffer
  1866. 'Img_Buffer = 0
  1867. '
  1868. '''  main program loop
  1869. 'Do
  1870. '
  1871. '  ''  scale in/out with uparrow/downarrow
  1872. '  If Multikey(80) Then
  1873. '    Scale *= 1.03
  1874. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1875. '  ElseIf Multikey(72) Then
  1876. '    Scale *= 0.97
  1877. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1878. '  End If
  1879. '
  1880. '  ''  rotate left/right with leftarrow/rightarrow
  1881. '  If Multikey(77) Then
  1882. '    Angle -= 0.03
  1883. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1884. '  ElseIf Multikey(75) Then
  1885. '    Angle += 0.03
  1886. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  1887. '  End If
  1888. '
  1889. '  ''  lock screen in order to use screen pointers
  1890. '  ScreenLock
  1891. '
  1892. '    ''  draw pixel in center of image
  1893. '    Scrn_Ptr[ X_Mid + Y_Mid * scrn_wid ] = Pixel(0, 0).C
  1894. '    ''  draw all other pixels - 4 at a time
  1895. '    For Y = Img_Top to 0
  1896. '      For X = Img_Lft to -1
  1897. '        ''  find pixel positions
  1898. '        P1 = (X_Mid+X) + (Y_Mid+Y) * scrn_wid
  1899. '        P2 = (X_Mid-X) + (Y_Mid-Y) * scrn_wid
  1900. '        P3 = (X_Mid+Y) + (Y_Mid-X) * scrn_wid
  1901. '        P4 = (X_Mid-Y) + (Y_Mid+X) * scrn_wid
  1902. '        ''  erase old pixels (paint them black)
  1903. '        Scrn_Ptr[P1] = 0
  1904. '        Scrn_Ptr[P2] = 0
  1905. '        Scrn_Ptr[P3] = 0
  1906. '        Scrn_Ptr[P4] = 0
  1907. '        ''  rotate and zoom
  1908. '        Rot_Fac_X = X*Cos_Ang - Y*Sin_Ang
  1909. '        Rot_Fac_Y = X*Sin_Ang + Y*Cos_Ang
  1910. '        If Rot_Fac_X < Img_Lft Or Rot_Fac_X > Img_Rgt Then Continue For
  1911. '        If Rot_Fac_Y < Img_Top Or Rot_Fac_Y > Img_Btm Then Continue For
  1912. '        ''  draw new pixels
  1913. '        Scrn_Ptr[P1] = Pixel(Rot_Fac_X, Rot_Fac_Y).C
  1914. '        Scrn_Ptr[P2] = Pixel(-Rot_Fac_X, -Rot_Fac_Y).C
  1915. '        Scrn_Ptr[P3] = Pixel(Rot_Fac_Y, -Rot_Fac_X).C
  1916. '        Scrn_Ptr[P4] = Pixel(-Rot_Fac_Y, Rot_Fac_X).C
  1917. '      Next X
  1918. '    Next Y
  1919. '
  1920. '  ScreenUnLock
  1921. '
  1922. '  Sleep 10, 1
  1923. 'Loop Until InKey() = Chr(27)
  1924.  
  1925. ' UPDATES:
  1926. ' Fixed bug where values 135, 224, and 314 all resolve to -45 degrees.
  1927. ' Fixed bug where an angle of 46-135 degrees caused the image to be flipped wrong.
  1928.  
  1929. ' TODO:
  1930. ' Fix issue where image looks bad at 30, 60, 120, 150, 210, 240, 300, 330 degrees
  1931.  
  1932. Sub ShearRotate (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  1933.     Const Pi = 4 * Atn(1)
  1934.  
  1935.     Dim angle As Integer
  1936.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  1937.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  1938.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  1939.     Dim x As Integer
  1940.     Dim y As Integer
  1941.     Dim nangle As Integer
  1942.     Dim nx As Integer
  1943.     Dim ny As Integer
  1944.     Dim flipper As Integer
  1945.     Dim rotr As Double
  1946.     Dim shear1 As Double
  1947.     Dim shear2 As Double
  1948.     Dim clr As Integer
  1949.     Dim y1 As _Byte
  1950.     Dim xy1 As _Byte
  1951.     Dim fy As _Byte
  1952.     Dim fx As _Byte
  1953.     Dim in$
  1954.     Dim sLine As String
  1955.  
  1956.     ' initialize new with empty
  1957.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  1958.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1959.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1960.             NewArray(x, y, 0).origx = x
  1961.             NewArray(x, y, 0).origy = y
  1962.             NewArray(x, y, 0).c = iEmpty
  1963.         Next y
  1964.     Next x
  1965.  
  1966.     ' angle is reversed
  1967.     angle = 360 - angle1
  1968.  
  1969.     ' Shearing each element 3 times in one shot
  1970.     nangle = angle
  1971.  
  1972.     ' this pre-processing portion basically rotates by 90 to get
  1973.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  1974.     If angle > 45 And angle < 225 Then
  1975.         If angle < 135 Then
  1976.             nangle = angle - 90
  1977.         Else
  1978.             nangle = angle - 180
  1979.         End If
  1980.     End If
  1981.     If angle > 135 And angle < 315 Then
  1982.         If angle < 225 Then
  1983.             nangle = angle - 180
  1984.         Else
  1985.             nangle = angle - 270
  1986.         End If
  1987.     End If
  1988.     If nangle < 0 Then
  1989.         nangle = nangle + 360
  1990.     End If
  1991.     If nangle > 359 Then
  1992.         nangle = nangle - 360
  1993.     End If
  1994.  
  1995.     rotr = nangle * DtoR
  1996.     shear1 = Tan(rotr / 2) ' correct way
  1997.     shear2 = Sin(rotr)
  1998.  
  1999.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2000.     ' ***       all resolve to -45 degrees.
  2001.     ' ***       Fixed by changing < to <=
  2002.  
  2003.     'if angle >  45 and angle < 134 then
  2004.     If angle > 45 And angle <= 134 Then
  2005.         flipper = 1
  2006.     ElseIf angle > 134 And angle <= 224 Then
  2007.         flipper = 2
  2008.     ElseIf angle > 224 And angle <= 314 Then
  2009.         ' *** NOTE: this had a bug where this flipper was wrong
  2010.         '           Fixed by adding case 7
  2011.         'flipper = 3
  2012.         flipper = 7
  2013.     Else
  2014.         flipper = 0
  2015.     End If
  2016.  
  2017.     ' Here is where it needs some optimizing possibly... kinda slow...
  2018.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2019.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2020.             Select Case flipper
  2021.                 Case 1:
  2022.                     nx = -y
  2023.                     ny = x
  2024.                 Case 2:
  2025.                     nx = -x
  2026.                     ny = -y
  2027.                 Case 3:
  2028.                     nx = -y
  2029.                     ny = -x
  2030.                 Case 4:
  2031.                     nx = -x
  2032.                     ny = y
  2033.                 Case 5:
  2034.                     nx = x
  2035.                     ny = -y
  2036.                 Case 6:
  2037.                     nx = y
  2038.                     ny = x
  2039.                 Case 7:
  2040.                     nx = y
  2041.                     ny = -x
  2042.                 Case Else:
  2043.                     nx = x
  2044.                     ny = y
  2045.             End Select
  2046.  
  2047.             clr = OldArray(nx, ny, 0).c
  2048.  
  2049.             y1 = y * shear1
  2050.             xy1 = x + y1
  2051.             fy = (y - xy1 * shear2)
  2052.             fx = xy1 + fy * shear1
  2053.  
  2054.             If fx >= -16 And fx <= 16 Then
  2055.                 If fy >= -16 And fy <= 16 Then
  2056.                     NewArray(fx, fy, 0).c = clr
  2057.                     NewArray(fx, fy, 0).origx = fx
  2058.                     NewArray(fx, fy, 0).origy = fy
  2059.                 End If
  2060.             End If
  2061.         Next x
  2062.     Next y
  2063. End Sub ' ShearRotate
  2064.  
  2065. ' /////////////////////////////////////////////////////////////////////////////
  2066. ' Same as ShearRotate, except adds iOverwriteCount parameter,
  2067. ' and counts how many points are overwriting existing points,
  2068. ' and return that value byref in parameter iOverwriteCount.
  2069.  
  2070. Sub ShearRotate1 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iOverwriteCount As Integer)
  2071.     Const Pi = 4 * Atn(1)
  2072.  
  2073.     Dim angle As Integer
  2074.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2075.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2076.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2077.     Dim x As Integer
  2078.     Dim y As Integer
  2079.     Dim nangle As Integer
  2080.     Dim nx As Integer
  2081.     Dim ny As Integer
  2082.     Dim flipper As Integer
  2083.     Dim rotr As Double
  2084.     Dim shear1 As Double
  2085.     Dim shear2 As Double
  2086.     Dim clr As Integer
  2087.     Dim y1 As _Byte
  2088.     Dim xy1 As _Byte
  2089.     Dim fy As _Byte
  2090.     Dim fx As _Byte
  2091.     Dim in$
  2092.     Dim sLine As String
  2093.  
  2094.     ' initialize new with empty
  2095.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2096.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2097.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2098.             NewArray(x, y, 0).origx = x
  2099.             NewArray(x, y, 0).origy = y
  2100.             NewArray(x, y, 0).c = iEmpty
  2101.         Next y
  2102.     Next x
  2103.  
  2104.     ' angle is reversed
  2105.     angle = 360 - angle1
  2106.  
  2107.     ' Shearing each element 3 times in one shot
  2108.     nangle = angle
  2109.  
  2110.     ' this pre-processing portion basically rotates by 90 to get
  2111.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2112.     If angle > 45 And angle < 225 Then
  2113.         If angle < 135 Then
  2114.             nangle = angle - 90
  2115.         Else
  2116.             nangle = angle - 180
  2117.         End If
  2118.     End If
  2119.     If angle > 135 And angle < 315 Then
  2120.         If angle < 225 Then
  2121.             nangle = angle - 180
  2122.         Else
  2123.             nangle = angle - 270
  2124.         End If
  2125.     End If
  2126.     If nangle < 0 Then
  2127.         nangle = nangle + 360
  2128.     End If
  2129.     If nangle > 359 Then
  2130.         nangle = nangle - 360
  2131.     End If
  2132.  
  2133.     rotr = nangle * DtoR
  2134.     shear1 = Tan(rotr / 2) ' correct way
  2135.     shear2 = Sin(rotr)
  2136.  
  2137.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2138.     ' ***       all resolve to -45 degrees.
  2139.     ' ***       Fixed by changing < to <=
  2140.  
  2141.     'if angle >  45 and angle < 134 then
  2142.     If angle > 45 And angle <= 134 Then
  2143.         flipper = 1
  2144.     ElseIf angle > 134 And angle <= 224 Then
  2145.         flipper = 2
  2146.     ElseIf angle > 224 And angle <= 314 Then
  2147.         ' *** NOTE: this had a bug where this flipper was wrong
  2148.         '           Fixed by adding case 7
  2149.         'flipper = 3
  2150.         flipper = 7
  2151.     Else
  2152.         flipper = 0
  2153.     End If
  2154.  
  2155.     ' Here is where it needs some optimizing possibly... kinda slow...
  2156.     iOverwriteCount = 0
  2157.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2158.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2159.             Select Case flipper
  2160.                 Case 1:
  2161.                     nx = -y
  2162.                     ny = x
  2163.                 Case 2:
  2164.                     nx = -x
  2165.                     ny = -y
  2166.                 Case 3:
  2167.                     nx = -y
  2168.                     ny = -x
  2169.                 Case 4:
  2170.                     nx = -x
  2171.                     ny = y
  2172.                 Case 5:
  2173.                     nx = x
  2174.                     ny = -y
  2175.                 Case 6:
  2176.                     nx = y
  2177.                     ny = x
  2178.                 Case 7:
  2179.                     nx = y
  2180.                     ny = -x
  2181.                 Case Else:
  2182.                     nx = x
  2183.                     ny = y
  2184.             End Select
  2185.  
  2186.             clr = OldArray(nx, ny, 0).c
  2187.  
  2188.             y1 = y * shear1
  2189.             xy1 = x + y1
  2190.             fy = (y - xy1 * shear2)
  2191.             fx = xy1 + fy * shear1
  2192.  
  2193.             If fx >= -16 And fx <= 16 Then
  2194.                 If fy >= -16 And fy <= 16 Then
  2195.  
  2196.                     ' count points that will be overwritten
  2197.                     If NewArray(fx, fy, 0).c <> iEmpty Then
  2198.                         iOverwriteCount = iOverwriteCount + 1
  2199.                     End If
  2200.  
  2201.                     NewArray(fx, fy, 0).c = clr
  2202.                     NewArray(fx, fy, 0).origx = fx
  2203.                     NewArray(fx, fy, 0).origy = fy
  2204.                 End If
  2205.             End If
  2206.         Next x
  2207.     Next y
  2208. End Sub ' ShearRotate1
  2209.  
  2210. ' /////////////////////////////////////////////////////////////////////////////
  2211.  
  2212. Sub ShearRotate1Test1
  2213.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2214.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2215.     Dim sMap As String
  2216.     Dim D As Integer
  2217.     Dim in$
  2218.  
  2219.     ' GET A SHAPE TO BE ROTATED
  2220.     Cls
  2221.     Print "3 shear rotation based on code by leopardpm"
  2222.     Print
  2223.  
  2224.     sMap = TestSprite1$
  2225.  
  2226.     ' CONVERT SHAPE TO ARRAY
  2227.     StringToRotationArray RoArray1(), sMap, "."
  2228.     Print "Initial contents of Rotation Array:"
  2229.     Print RotationArrayToStringTest(RoArray1())
  2230.     Print
  2231.  
  2232.     ' ROTATE THE SHAPE
  2233.     Do
  2234.         Print "Type degrees to rotate (0 TO 360) or non-numeric value to quit."
  2235.         Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2236.  
  2237.         Input "Degrees to rotate (q to quit)? "; in$
  2238.         If IsNum%(in$) Then
  2239.             D = Val(in$)
  2240.             If D >= 0 And D <= 360 Then
  2241.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  2242.                 Print
  2243.                 Print "Rotated by " + cstr$(D) + " degrees:"
  2244.                 Print RotationArrayToStringTest(RoArray2())
  2245.                 Print
  2246.             Else
  2247.                 Exit Do
  2248.             End If
  2249.         Else
  2250.             Exit Do
  2251.         End If
  2252.     Loop
  2253. End Sub ' ShearRotate1Test1
  2254.  
  2255. ' /////////////////////////////////////////////////////////////////////////////
  2256. ' Now receives parameter sMap
  2257. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  2258.  
  2259. ' e.g. ShearRotate1Test2 TestSprite1$
  2260.  
  2261. Sub ShearRotate1Test2 (sMap As String)
  2262.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2263.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2264.     'Dim sMap As String
  2265.     Dim D As Integer
  2266.     Dim D1 As Integer
  2267.     Dim in$
  2268.     Dim bFinished As Integer
  2269.     Dim iOverwriteCount As Integer
  2270.  
  2271.     ' GET A SHAPE TO BE ROTATED
  2272.     Cls
  2273.     Print "3 shear rotation based on code by leopardpm"
  2274.     'sMap = TestSprite1$
  2275.  
  2276.     ' CONVERT SHAPE TO ARRAY
  2277.     StringToRotationArray RoArray1(), sMap, "."
  2278.  
  2279.     ' GET START ANGLE
  2280.     D = 0
  2281.     Print
  2282.     Print "Rotated by " + cstr$(D) + " degrees:"
  2283.     Print RotationArrayToStringTest(RoArray1())
  2284.     Print
  2285.     Print "Type an angle (-360 to 360) to rotate to, "
  2286.     Print "or blank to increase by 1 degree, or q to quit."
  2287.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2288.     Print "Hold down <ENTER> to rotate continually."
  2289.     Input "Angle (q to quit)? ", in$
  2290.     If Len(in$) > 0 Then
  2291.         If IsNum%(in$) Then
  2292.             D1 = Val(in$)
  2293.         Else
  2294.             D1 = -500
  2295.         End If
  2296.     Else
  2297.         D1 = 1
  2298.     End If
  2299.  
  2300.     ' ROTATE TO EACH ANGLE
  2301.     If D1 >= -360 And D1 <= 360 Then
  2302.         bFinished = FALSE
  2303.         Do
  2304.             ' ROTATE CLOCKWISE
  2305.             For D = D1 To 360
  2306.                 Cls
  2307.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  2308.                 Print
  2309.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2310.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  2311.  
  2312.                 Print RotationArrayToStringTest(RoArray2())
  2313.                 Print
  2314.  
  2315.                 Print "Type an angle (-360 to 360) to rotate to, "
  2316.                 Print "or blank to increase by 1 degree, or q to quit."
  2317.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2318.                 Print "Hold down <ENTER> to rotate continually."
  2319.                 Input "Angle (q to quit)? ", in$
  2320.                 If Len(in$) > 0 Then
  2321.                     If IsNum%(in$) Then
  2322.                         D = Val(in$)
  2323.                         If D >= 0 And D <= 360 Then
  2324.                             D = D - 1
  2325.                         Else
  2326.                             bFinished = TRUE
  2327.                             Exit For
  2328.                         End If
  2329.                     Else
  2330.                         bFinished = TRUE
  2331.                         Exit For
  2332.                     End If
  2333.                 End If
  2334.             Next D
  2335.             If bFinished = TRUE Then Exit Do
  2336.  
  2337.             ' ROTATE COUNTER-CLOCKWISE
  2338.             For D = 360 To D1 Step -1
  2339.                 Cls
  2340.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  2341.                 Print
  2342.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2343.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  2344.  
  2345.                 Print RotationArrayToStringTest(RoArray2())
  2346.                 Print
  2347.  
  2348.                 Print "Type an angle (0 to 360) to rotate to, "
  2349.                 Print "or blank to increase by 1 degree, or q to quit."
  2350.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2351.                 Print "Hold down <ENTER> to rotate continually."
  2352.                 Input "Angle (q to quit)? ", in$
  2353.                 If Len(in$) > 0 Then
  2354.                     If IsNum%(in$) Then
  2355.                         D = Val(in$)
  2356.                         If D >= 0 And D <= 360 Then
  2357.                             D = D + 1
  2358.                         Else
  2359.                             bFinished = TRUE
  2360.                             Exit For
  2361.                         End If
  2362.                     Else
  2363.                         bFinished = TRUE
  2364.                         Exit For
  2365.                     End If
  2366.                 End If
  2367.             Next D
  2368.             If bFinished = TRUE Then Exit Do
  2369.         Loop
  2370.     End If
  2371. End Sub ' ShearRotate1Test2
  2372.  
  2373. ' /////////////////////////////////////////////////////////////////////////////
  2374. ' ShearRotate v2
  2375. ' Tries to fix the problem of 2 points resolving to the same coordinate
  2376. ' (one overwrites the other, which becomes "lost")
  2377.  
  2378. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  2379.  
  2380. Sub ShearRotate2 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iMissing As Integer)
  2381.     Const Pi = 4 * Atn(1)
  2382.  
  2383.     Dim angle As Integer
  2384.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2385.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2386.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2387.     Dim x As Integer
  2388.     Dim y As Integer
  2389.     Dim nangle As Integer
  2390.     Dim nx As Integer
  2391.     Dim ny As Integer
  2392.     Dim flipper As Integer
  2393.     Dim rotr As Double
  2394.     Dim shear1 As Double
  2395.     Dim shear2 As Double
  2396.     Dim clr As Integer
  2397.     Dim y1 As _Byte
  2398.     Dim xy1 As _Byte
  2399.     Dim fy As _Byte
  2400.     Dim fx As _Byte
  2401.     Dim in$
  2402.     Dim sLine As String
  2403.     ReDim arrLost(-1) As RotationType
  2404.     Dim iLoop As Integer
  2405.     Dim bFound As Integer
  2406.  
  2407.     ' initialize new with empty
  2408.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2409.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2410.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2411.             NewArray(x, y, 0).origx = x
  2412.             NewArray(x, y, 0).origy = y
  2413.             NewArray(x, y, 0).c = iEmpty
  2414.         Next y
  2415.     Next x
  2416.  
  2417.     ' angle is reversed
  2418.     angle = 360 - angle1
  2419.  
  2420.     ' Shearing each element 3 times in one shot
  2421.     nangle = angle
  2422.  
  2423.     ' this pre-processing portion basically rotates by 90 to get
  2424.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2425.     If angle > 45 And angle < 225 Then
  2426.         If angle < 135 Then
  2427.             nangle = angle - 90
  2428.         Else
  2429.             nangle = angle - 180
  2430.         End If
  2431.     End If
  2432.     If angle > 135 And angle < 315 Then
  2433.         If angle < 225 Then
  2434.             nangle = angle - 180
  2435.         Else
  2436.             nangle = angle - 270
  2437.         End If
  2438.     End If
  2439.     If nangle < 0 Then
  2440.         nangle = nangle + 360
  2441.     End If
  2442.     If nangle > 359 Then
  2443.         nangle = nangle - 360
  2444.     End If
  2445.  
  2446.     rotr = nangle * DtoR
  2447.     shear1 = Tan(rotr / 2) ' correct way
  2448.     shear2 = Sin(rotr)
  2449.  
  2450.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2451.     ' ***       all resolve to -45 degrees.
  2452.     ' ***       Fixed by changing < to <=
  2453.  
  2454.     'if angle >  45 and angle < 134 then
  2455.     If angle > 45 And angle <= 134 Then
  2456.         flipper = 1
  2457.     ElseIf angle > 134 And angle <= 224 Then
  2458.         flipper = 2
  2459.     ElseIf angle > 224 And angle <= 314 Then
  2460.         ' *** NOTE: this had a bug where this flipper was wrong
  2461.         '           Fixed by adding case 7
  2462.         'flipper = 3
  2463.         flipper = 7
  2464.     Else
  2465.         flipper = 0
  2466.     End If
  2467.  
  2468.     ' Here is where it needs some optimizing possibly... kinda slow...
  2469.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2470.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2471.             Select Case flipper
  2472.                 Case 1:
  2473.                     nx = -y
  2474.                     ny = x
  2475.                 Case 2:
  2476.                     nx = -x
  2477.                     ny = -y
  2478.                 Case 3:
  2479.                     nx = -y
  2480.                     ny = -x
  2481.                 Case 4:
  2482.                     nx = -x
  2483.                     ny = y
  2484.                 Case 5:
  2485.                     nx = x
  2486.                     ny = -y
  2487.                 Case 6:
  2488.                     nx = y
  2489.                     ny = x
  2490.                 Case 7:
  2491.                     nx = y
  2492.                     ny = -x
  2493.                 Case Else:
  2494.                     nx = x
  2495.                     ny = y
  2496.             End Select
  2497.  
  2498.             clr = OldArray(nx, ny, 0).c
  2499.  
  2500.             y1 = y * shear1
  2501.             xy1 = x + y1
  2502.             fy = (y - xy1 * shear2)
  2503.             fx = xy1 + fy * shear1
  2504.  
  2505.             If fx >= -16 And fx <= 16 Then
  2506.                 If fy >= -16 And fy <= 16 Then
  2507.                     ' only draw here if this spot is empty
  2508.                     If NewArray(fx, fy, 0).c = iEmpty Then
  2509.                         NewArray(fx, fy, 0).c = clr
  2510.                         NewArray(fx, fy, 0).origx = fx
  2511.                         NewArray(fx, fy, 0).origy = fy
  2512.                     Else
  2513.                         ' don't draw, but save it to a list to handle later
  2514.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  2515.                         arrLost(UBound(arrLost)).c = clr
  2516.                         arrLost(UBound(arrLost)).origx = fx
  2517.                         arrLost(UBound(arrLost)).origy = fy
  2518.                     End If
  2519.                 End If
  2520.             End If
  2521.         Next x
  2522.     Next y
  2523.  
  2524.     ' try to place any points that would have overwritten to a spot nearby
  2525.     ' can nearby be determined by the angle of rotation?
  2526.     ' perhaps if we divide the screen up into 4 zones:
  2527.     '
  2528.     ' --------------------------------------
  2529.     '|                   |                  |
  2530.     '| zone 4            | zone 1           |
  2531.     '| 271-359 degrees)  | (1-89 degrees)   |
  2532.     '|--------------------------------------|
  2533.     '|                   |                  |
  2534.     '| zone 3            | zone 2           |
  2535.     '| (181-269 degrees) | (91-179 degrees) |
  2536.     '|                   |                  |
  2537.     ' --------------------------------------
  2538.  
  2539.     ' in zone   search direction (y,x)
  2540.     ' -------   ----------------------
  2541.     ' 1         up   + right
  2542.     ' 2         down + right
  2543.     ' 3         down + left
  2544.     ' 4         up   + left
  2545.  
  2546.     iMissing = 0
  2547.     For iLoop = 0 To UBound(arrLost)
  2548.         bFound = FindEmptyShearRotationPoint2%(arrLost(iLoop), angle1, iEmpty, x, y, NewArray())
  2549.         If bFound = TRUE Then
  2550.             If m_bDebug = TRUE Then
  2551.                 _Echo "Plotted  missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  2552.             End If
  2553.         Else
  2554.             iMissing = iMissing + 1
  2555.             If m_bDebug = TRUE Then
  2556.                 _Echo "Detected missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  2557.             End If
  2558.         End If
  2559.     Next iLoop
  2560.  
  2561. End Sub ' ShearRotate2
  2562.  
  2563. ' /////////////////////////////////////////////////////////////////////////////
  2564. ' Receives
  2565. ' FindMe (RotationType) = contains the starting location (.origx, .origy) to start looking from, and the value (.c) to write
  2566. ' angle1 (Integer) = angle we were rotating to, to determine direction to look in
  2567. ' iEmpty (Integer) = value to test against for empty
  2568. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  2569. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  2570. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  2571.  
  2572. ' Returns
  2573. ' FALSE if no empty spot was found
  2574. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  2575.  
  2576. Function FindEmptyShearRotationPoint2% (FindMe As RotationType, angle1 As Integer, iEmpty As Integer, destX As Integer, destY As Integer, NewArray() As RotationType)
  2577.     Dim bResult As Integer: bResult = FALSE
  2578.     Dim x As Integer
  2579.     Dim y As Integer
  2580.     Dim dirX As Integer
  2581.     Dim dirY As Integer
  2582.  
  2583.     destX = 0
  2584.     destY = 0
  2585.  
  2586.     ' Choose search direction depending on the angle
  2587.     If angle1 > 0 And angle1 < 90 Then
  2588.         dirX = 1
  2589.         dirY = -1
  2590.     ElseIf angle1 > 90 And angle1 < 180 Then
  2591.         dirX = 1
  2592.         dirY = 1
  2593.     ElseIf angle1 > 180 And angle1 < 270 Then
  2594.         dirX = -1
  2595.         dirY = 1
  2596.     ElseIf angle1 > 270 And angle1 < 360 Then
  2597.         dirX = -1
  2598.         dirY = -1
  2599.     Else
  2600.         dirX = 0
  2601.         dirY = 0
  2602.     End If
  2603.  
  2604.     If dirX <> 0 Then
  2605.         x = FindMe.origx
  2606.         y = FindMe.origy
  2607.         Do
  2608.             ' quit if we're out of bounds
  2609.             If x < LBound(NewArray, 1) Then Exit Do
  2610.             If x > UBound(NewArray, 1) Then Exit Do
  2611.             If y < LBound(NewArray, 2) Then Exit Do
  2612.             If y > UBound(NewArray, 2) Then Exit Do
  2613.  
  2614.             ' =============================================================================
  2615.             ' BEGIN SEARCH
  2616.             ' =============================================================================
  2617.             ' look along y axis for a blank spot
  2618.             destX = x
  2619.             destY = y + dirY
  2620.             If destX >= LBound(NewArray, 1) Then
  2621.                 If destX <= UBound(NewArray, 1) Then
  2622.                     If destY >= LBound(NewArray, 2) Then
  2623.                         If destY <= UBound(NewArray, 2) Then
  2624.                             If NewArray(destX, destY, 0).c = iEmpty Then
  2625.                                 NewArray(destX, destY, 0).c = FindMe.c
  2626.                                 bResult = TRUE
  2627.                                 Exit Do
  2628.                             End If
  2629.                         End If
  2630.                     End If
  2631.                 End If
  2632.             End If
  2633.  
  2634.             ' look along x axis for a blank spot
  2635.             destX = x + dirX
  2636.             destY = y
  2637.             If destX >= LBound(NewArray, 1) Then
  2638.                 If destX <= UBound(NewArray, 1) Then
  2639.                     If destY >= LBound(NewArray, 2) Then
  2640.                         If destY <= UBound(NewArray, 2) Then
  2641.                             If NewArray(x + dirX, y, 0).c = iEmpty Then
  2642.                                 NewArray(destX, destY, 0).c = FindMe.c
  2643.                                 bResult = TRUE
  2644.                                 Exit Do
  2645.                             End If
  2646.                         End If
  2647.                     End If
  2648.                 End If
  2649.             End If
  2650.  
  2651.             ' look diagonally for a blank spot
  2652.             destX = x + dirX
  2653.             destY = y + dirY
  2654.             If destX >= LBound(NewArray, 1) Then
  2655.                 If destX <= UBound(NewArray, 1) Then
  2656.                     If destY >= LBound(NewArray, 2) Then
  2657.                         If destY <= UBound(NewArray, 2) Then
  2658.                             If NewArray(x + dirX, y + dirY, 0).c = iEmpty Then
  2659.                                 NewArray(destX, destY, 0).c = FindMe.c
  2660.                                 bResult = TRUE
  2661.                                 Exit Do
  2662.                             End If
  2663.                         End If
  2664.                     End If
  2665.                 End If
  2666.             End If
  2667.             ' =============================================================================
  2668.             ' END SEARCH
  2669.             ' =============================================================================
  2670.  
  2671.             ' Keep looking
  2672.             x = x + dirX
  2673.             y = y + dirY
  2674.         Loop
  2675.     End If
  2676.  
  2677.     ' Return result
  2678.     FindEmptyShearRotationPoint2% = bResult
  2679. End Function ' FindEmptyShearRotationPoint2%
  2680.  
  2681. ' /////////////////////////////////////////////////////////////////////////////
  2682. ' Tries to correct for missing points.
  2683.  
  2684. ' Receives parameter sMap
  2685. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  2686.  
  2687. ' e.g. ShearRotate2Test1 TestSprite1$
  2688.  
  2689. Sub ShearRotate2Test1 (sMap As String)
  2690.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  2691.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  2692.     'Dim sMap As String
  2693.     Dim D As Integer
  2694.     Dim D1 As Integer
  2695.     Dim in$
  2696.     Dim bFinished As Integer
  2697.     Dim iMissing As Integer
  2698.  
  2699.     ' GET A SHAPE TO BE ROTATED
  2700.     Cls
  2701.     Print "3 shear rotation based on code by leopardpm"
  2702.     'sMap = TestSprite1$
  2703.  
  2704.     ' CONVERT SHAPE TO ARRAY
  2705.     StringToRotationArray RoArray1(), sMap, "."
  2706.  
  2707.     ' GET START ANGLE
  2708.     D = 0
  2709.     Print
  2710.     Print "Rotated by " + cstr$(D) + " degrees:"
  2711.     Print RotationArrayToStringTest(RoArray1())
  2712.     Print
  2713.     Print "Type an angle (-360 to 360) to rotate to, "
  2714.     Print "or blank to increase by 1 degree, or q to quit."
  2715.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2716.     Print "Hold down <ENTER> to rotate continually."
  2717.     Input "Angle (q to quit)? ", in$
  2718.     If Len(in$) > 0 Then
  2719.         If IsNum%(in$) Then
  2720.             D1 = Val(in$)
  2721.         Else
  2722.             D1 = -500
  2723.         End If
  2724.     Else
  2725.         D1 = 1
  2726.     End If
  2727.  
  2728.     ' ROTATE TO EACH ANGLE
  2729.     If D1 >= -360 And D1 <= 360 Then
  2730.         bFinished = FALSE
  2731.         Do
  2732.             ' ROTATE CLOCKWISE
  2733.             For D = D1 To 360
  2734.                 Cls
  2735.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  2736.                 Print
  2737.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2738.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  2739.  
  2740.                 Print RotationArrayToStringTest(RoArray2())
  2741.                 Print
  2742.  
  2743.                 Print "Type an angle (-360 to 360) to rotate to, "
  2744.                 Print "or blank to increase by 1 degree, or q to quit."
  2745.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2746.                 Print "Hold down <ENTER> to rotate continually."
  2747.                 Input "Angle (q to quit)? ", in$
  2748.                 If Len(in$) > 0 Then
  2749.                     If IsNum%(in$) Then
  2750.                         D = Val(in$)
  2751.                         If D >= 0 And D <= 360 Then
  2752.                             D = D - 1
  2753.                         Else
  2754.                             bFinished = TRUE
  2755.                             Exit For
  2756.                         End If
  2757.                     Else
  2758.                         bFinished = TRUE
  2759.                         Exit For
  2760.                     End If
  2761.                 End If
  2762.             Next D
  2763.             If bFinished = TRUE Then Exit Do
  2764.  
  2765.             ' ROTATE COUNTER-CLOCKWISE
  2766.             For D = 360 To D1 Step -1
  2767.                 Cls
  2768.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  2769.                 Print
  2770.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  2771.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  2772.  
  2773.                 Print RotationArrayToStringTest(RoArray2())
  2774.                 Print
  2775.  
  2776.                 Print "Type an angle (0 to 360) to rotate to, "
  2777.                 Print "or blank to increase by 1 degree, or q to quit."
  2778.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  2779.                 Print "Hold down <ENTER> to rotate continually."
  2780.                 Input "Angle (q to quit)? ", in$
  2781.                 If Len(in$) > 0 Then
  2782.                     If IsNum%(in$) Then
  2783.                         D = Val(in$)
  2784.                         If D >= 0 And D <= 360 Then
  2785.                             D = D + 1
  2786.                         Else
  2787.                             bFinished = TRUE
  2788.                             Exit For
  2789.                         End If
  2790.                     Else
  2791.                         bFinished = TRUE
  2792.                         Exit For
  2793.                     End If
  2794.                 End If
  2795.             Next D
  2796.             If bFinished = TRUE Then Exit Do
  2797.         Loop
  2798.     End If
  2799. End Sub ' ShearRotate2Test1
  2800.  
  2801. ' /////////////////////////////////////////////////////////////////////////////
  2802. ' ShearRotate v3
  2803.  
  2804. ' Tries to fix the problem of 2 points resolving to the same coordinate
  2805. ' (one overwrites the other, which becomes "lost")
  2806. ' a little more accurately, using iDirection parameter
  2807. ' (which can be cClockwise or cCounterClockwise)
  2808. ' together with which quarter of the screen the point is in,
  2809.  
  2810. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  2811.  
  2812. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  2813.  
  2814. Sub ShearRotate3 ( _
  2815.     OldArray() As RotationType, _
  2816.     NewArray() As RotationType, _
  2817.     angle1 As Integer, _
  2818.     iDirection As Integer, _
  2819.     iEmpty As Integer, _
  2820.     iMissing As Integer)
  2821.  
  2822.     Const Pi = 4 * Atn(1)
  2823.  
  2824.     Dim angle As Integer
  2825.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  2826.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  2827.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  2828.     Dim x As Integer
  2829.     Dim y As Integer
  2830.     Dim nangle As Integer
  2831.     Dim nx As Integer
  2832.     Dim ny As Integer
  2833.     Dim flipper As Integer
  2834.     Dim rotr As Double
  2835.     Dim shear1 As Double
  2836.     Dim shear2 As Double
  2837.     Dim clr As Integer
  2838.     Dim y1 As _Byte
  2839.     Dim xy1 As _Byte
  2840.     Dim fy As _Byte
  2841.     Dim fx As _Byte
  2842.     Dim in$
  2843.     Dim sLine As String
  2844.     ReDim arrLost(-1) As RotationType
  2845.     Dim iLoop As Integer
  2846.     Dim bFound As Integer
  2847.     Dim iScreenZone As Integer
  2848.     Dim iMidX As Integer
  2849.     Dim iMidY As Integer
  2850.  
  2851.     ' initialize new with empty
  2852.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  2853.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2854.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2855.             NewArray(x, y, 0).origx = x
  2856.             NewArray(x, y, 0).origy = y
  2857.             NewArray(x, y, 0).c = iEmpty
  2858.         Next y
  2859.     Next x
  2860.  
  2861.     ' find midpoints
  2862.     iMidX = (UBound(OldArray, 1) - LBound(OldArray, 1)) / 2
  2863.     iMidY = (UBound(OldArray, 2) - LBound(OldArray, 2)) / 2
  2864.  
  2865.     ' angle is reversed
  2866.     angle = 360 - angle1
  2867.  
  2868.     ' Shearing each element 3 times in one shot
  2869.     nangle = angle
  2870.  
  2871.     ' this pre-processing portion basically rotates by 90 to get
  2872.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  2873.     If angle > 45 And angle < 225 Then
  2874.         If angle < 135 Then
  2875.             nangle = angle - 90
  2876.         Else
  2877.             nangle = angle - 180
  2878.         End If
  2879.     End If
  2880.     If angle > 135 And angle < 315 Then
  2881.         If angle < 225 Then
  2882.             nangle = angle - 180
  2883.         Else
  2884.             nangle = angle - 270
  2885.         End If
  2886.     End If
  2887.     If nangle < 0 Then
  2888.         nangle = nangle + 360
  2889.     End If
  2890.     If nangle > 359 Then
  2891.         nangle = nangle - 360
  2892.     End If
  2893.  
  2894.     rotr = nangle * DtoR
  2895.     shear1 = Tan(rotr / 2) ' correct way
  2896.     shear2 = Sin(rotr)
  2897.  
  2898.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  2899.     ' ***       all resolve to -45 degrees.
  2900.     ' ***       Fixed by changing < to <=
  2901.  
  2902.     'if angle >  45 and angle < 134 then
  2903.     If angle > 45 And angle <= 134 Then
  2904.         flipper = 1
  2905.     ElseIf angle > 134 And angle <= 224 Then
  2906.         flipper = 2
  2907.     ElseIf angle > 224 And angle <= 314 Then
  2908.         ' *** NOTE: this had a bug where this flipper was wrong
  2909.         '           Fixed by adding case 7
  2910.         'flipper = 3
  2911.         flipper = 7
  2912.     Else
  2913.         flipper = 0
  2914.     End If
  2915.  
  2916.     ' Here is where it needs some optimizing possibly... kinda slow...
  2917.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  2918.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  2919.  
  2920.             ' find which part of screen the current point is in
  2921.             If y > iMidY Then
  2922.                 ' bottom half of screen
  2923.                 If x > iMidX Then
  2924.                     ' right half of screen
  2925.                     iScreenZone = 2
  2926.                 Else
  2927.                     ' left half of screen
  2928.                     iScreenZone = 3
  2929.                 End If
  2930.             Else
  2931.                 ' top half of screen
  2932.                 If x > iMidX Then
  2933.                     ' right half of screen
  2934.                     iScreenZone = 1
  2935.                 Else
  2936.                     ' left half of screen
  2937.                     iScreenZone = 4
  2938.                 End If
  2939.             End If
  2940.  
  2941.             ' calculate directions
  2942.             Select Case flipper
  2943.                 Case 1:
  2944.                     nx = -y
  2945.                     ny = x
  2946.                 Case 2:
  2947.                     nx = -x
  2948.                     ny = -y
  2949.                 Case 3:
  2950.                     nx = -y
  2951.                     ny = -x
  2952.                 Case 4:
  2953.                     nx = -x
  2954.                     ny = y
  2955.                 Case 5:
  2956.                     nx = x
  2957.                     ny = -y
  2958.                 Case 6:
  2959.                     nx = y
  2960.                     ny = x
  2961.                 Case 7:
  2962.                     nx = y
  2963.                     ny = -x
  2964.                 Case Else:
  2965.                     nx = x
  2966.                     ny = y
  2967.             End Select
  2968.  
  2969.             clr = OldArray(nx, ny, 0).c
  2970.  
  2971.             y1 = y * shear1
  2972.             xy1 = x + y1
  2973.             fy = (y - xy1 * shear2)
  2974.             fx = xy1 + fy * shear1
  2975.  
  2976.             If fx >= -16 And fx <= 16 Then
  2977.                 If fy >= -16 And fy <= 16 Then
  2978.                     ' only draw here if this spot is empty
  2979.                     If NewArray(fx, fy, 0).c = iEmpty Then
  2980.                         NewArray(fx, fy, 0).c = clr
  2981.                         NewArray(fx, fy, 0).origx = fx
  2982.                         NewArray(fx, fy, 0).origy = fy
  2983.                     Else
  2984.                         ' don't draw, but save it to a list to handle later
  2985.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  2986.                         arrLost(UBound(arrLost)).c = clr
  2987.                         arrLost(UBound(arrLost)).origx = fx
  2988.                         arrLost(UBound(arrLost)).origy = fy
  2989.  
  2990.                         ' preserve which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  2991.                         arrLost(UBound(arrLost)).z = iScreenZone
  2992.                     End If
  2993.                 End If
  2994.             End If
  2995.         Next x
  2996.     Next y
  2997.  
  2998.     ' try to place any points that would have overwritten to a spot nearby
  2999.     ' can nearby be determined by the direction of rotation  (iDirection)
  3000.     ' together with which quarter of the screen the point is in (iScreenZone)
  3001.     ' where we divide the screen up into 4 zones:
  3002.  
  3003.     ' --------------------------------------
  3004.     '|                   |                  |
  3005.     '| zone 4            | zone 1           |
  3006.     '|                   |                  |
  3007.     '|--------------------------------------|
  3008.     '|                   |                  |
  3009.     '| zone 3            | zone 2           |
  3010.     '|                   |                  |
  3011.     '|                   |                  |
  3012.     ' --------------------------------------
  3013.  
  3014.     ' in zone   rotation direction   search direction (y,x)
  3015.     ' -------   ------------------   ----------------------
  3016.     ' 1         clockwise            down + right
  3017.     ' 1         counter-clockwise    up   + left
  3018.     ' 2         clockwise            down + left
  3019.     ' 2         counter-clockwise    up   + right
  3020.     ' 3         clockwise            up   + left
  3021.     ' 3         counter-clockwise    down + right
  3022.     ' 4         clockwise            up   + right
  3023.     ' 4         counter-clockwise    down + left
  3024.  
  3025.     iMissing = 0
  3026.     For iLoop = 0 To UBound(arrLost)
  3027.         bFound = FindEmptyShearRotationPoint3%(arrLost(iLoop), iDirection, iEmpty, x, y, NewArray())
  3028.         If bFound = TRUE Then
  3029.             If m_bDebug = TRUE Then
  3030.                 _Echo "Plotted  missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3031.             End If
  3032.         Else
  3033.             iMissing = iMissing + 1
  3034.             If m_bDebug = TRUE Then
  3035.                 _Echo "Detected missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3036.             End If
  3037.         End If
  3038.     Next iLoop
  3039.  
  3040. End Sub ' ShearRotate3
  3041.  
  3042. ' /////////////////////////////////////////////////////////////////////////////
  3043. ' Looks for a new point
  3044. ' a little more accurately, using iDirection parameter
  3045. ' which can be cClockwise or cCounterClockwise.
  3046.  
  3047. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3048.  
  3049. ' Receives
  3050. ' FindMe (RotationType) = contains
  3051. '                         .origx, .origy = the starting location to start looking from,
  3052. '                         .z = which area of the screen the point is in
  3053. '                              (1=top right, 2=bottom right, 3=bottom left, 4=top left)
  3054. '                              to determine direction to look in
  3055. '                         .c = the value to write
  3056. ' iDirection (Integer) = direction of rotation, can be cClockwise or cCounterClockwise (constants must be declared globally)
  3057. ' iEmpty (Integer) = value to test against for empty
  3058. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  3059. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  3060. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  3061.  
  3062. ' Returns
  3063. ' FALSE if no empty spot was found
  3064. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  3065.  
  3066. Function FindEmptyShearRotationPoint3% (FindMe As RotationType, iDirection As Integer, iEmpty As Integer, destX As Integer, destY As Integer, NewArray() As RotationType)
  3067.     Dim bResult As Integer: bResult = FALSE
  3068.     Dim x As Integer
  3069.     Dim y As Integer
  3070.     Dim dirX As Integer
  3071.     Dim dirY As Integer
  3072.     Dim bContinue As Integer
  3073.  
  3074.     ' Initialize
  3075.     destX = 0
  3076.     destY = 0
  3077.     bContinue = TRUE
  3078.  
  3079.     ' Choose search direction based on the quadrant of the screen
  3080.     ' and the direction of rotation:
  3081.  
  3082.     ' iScreenZone   iDirection           search direction (y,x)
  3083.     ' -----------   ------------------   ----------------------
  3084.     ' 1             cClockwise           down + right ( 1, 1)
  3085.     ' 1             cCounterClockwise    up   + left  (-1,-1)
  3086.     ' 2             cClockwise           down + left  ( 1,-1)
  3087.     ' 2             cCounterClockwise    up   + right (-1, 1)
  3088.     ' 3             cClockwise           up   + left  (-1,-1)
  3089.     ' 3             cCounterClockwise    down + right ( 1, 1)
  3090.     ' 4             cClockwise           up   + right (-1, 1)
  3091.     ' 4             cCounterClockwise    down + left  ( 1,-1)
  3092.  
  3093.     If FindMe.z = 1 And iDirection = cClockwise Then
  3094.         dirY = 1
  3095.         dirX = 1
  3096.     ElseIf FindMe.z = 1 And iDirection = cCounterClockwise Then
  3097.         dirY = -1
  3098.         dirX = -1
  3099.     ElseIf FindMe.z = 2 And iDirection = cClockwise Then
  3100.         dirY = 1
  3101.         dirX = -1
  3102.     ElseIf FindMe.z = 2 And iDirection = cCounterClockwise Then
  3103.         dirY = -1
  3104.         dirX = 1
  3105.     ElseIf FindMe.z = 3 And iDirection = cClockwise Then
  3106.         dirY = -1
  3107.         dirX = -1
  3108.     ElseIf FindMe.z = 3 And iDirection = cCounterClockwise Then
  3109.         dirY = 1
  3110.         dirX = 1
  3111.     ElseIf FindMe.z = 4 And iDirection = cClockwise Then
  3112.         dirY = -1
  3113.         dirX = 1
  3114.     ElseIf FindMe.z = 4 And iDirection = cCounterClockwise Then
  3115.         dirY = 1
  3116.         dirX = -1
  3117.     Else
  3118.         bContinue = FALSE
  3119.     End If
  3120.  
  3121.     ' Quit if we're out of bounds
  3122.     If bContinue = TRUE Then
  3123.         bContinue = FALSE
  3124.         x = FindMe.origx
  3125.         y = FindMe.origy
  3126.         If x >= LBound(NewArray, 1) Then
  3127.             If x <= UBound(NewArray, 1) Then
  3128.                 If y >= LBound(NewArray, 2) Then
  3129.                     If y <= UBound(NewArray, 2) Then
  3130.                         bContinue = TRUE
  3131.                     End If
  3132.                 End If
  3133.             End If
  3134.         End If
  3135.     End If
  3136.  
  3137.     ' look along y axis for an available adjacent point
  3138.     If bContinue = TRUE Then
  3139.         destX = x
  3140.         destY = y + dirY
  3141.         If destX >= LBound(NewArray, 1) Then
  3142.             If destX <= UBound(NewArray, 1) Then
  3143.                 If destY >= LBound(NewArray, 2) Then
  3144.                     If destY <= UBound(NewArray, 2) Then
  3145.                         If NewArray(destX, destY, 0).c = iEmpty Then
  3146.                             NewArray(destX, destY, 0).c = FindMe.c
  3147.                             bResult = TRUE
  3148.                             bContinue = FALSE
  3149.                         End If
  3150.                     End If
  3151.                 End If
  3152.             End If
  3153.         End If
  3154.     End If
  3155.  
  3156.     ' look along x axis for an available adjacent point
  3157.     If bContinue = TRUE Then
  3158.         destX = x + dirX
  3159.         destY = y
  3160.         If destX >= LBound(NewArray, 1) Then
  3161.             If destX <= UBound(NewArray, 1) Then
  3162.                 If destY >= LBound(NewArray, 2) Then
  3163.                     If destY <= UBound(NewArray, 2) Then
  3164.                         If NewArray(x + dirX, y, 0).c = iEmpty Then
  3165.                             NewArray(destX, destY, 0).c = FindMe.c
  3166.                             bResult = TRUE
  3167.                             bContinue = FALSE
  3168.                         End If
  3169.                     End If
  3170.                 End If
  3171.             End If
  3172.         End If
  3173.     End If
  3174.  
  3175.     ' look diagonally for an available adjacent point
  3176.     If bContinue = TRUE Then
  3177.         destX = x + dirX
  3178.         destY = y + dirY
  3179.         If destX >= LBound(NewArray, 1) Then
  3180.             If destX <= UBound(NewArray, 1) Then
  3181.                 If destY >= LBound(NewArray, 2) Then
  3182.                     If destY <= UBound(NewArray, 2) Then
  3183.                         If NewArray(x + dirX, y + dirY, 0).c = iEmpty Then
  3184.                             NewArray(destX, destY, 0).c = FindMe.c
  3185.                             bResult = TRUE
  3186.                             bContinue = FALSE
  3187.                         End If
  3188.                     End If
  3189.                 End If
  3190.             End If
  3191.         End If
  3192.     End If
  3193.  
  3194.     ' Return result
  3195.     FindEmptyShearRotationPoint3% = bResult
  3196. End Function ' FindEmptyShearRotationPoint3%
  3197.  
  3198. ' /////////////////////////////////////////////////////////////////////////////
  3199. ' Receives parameter sMap
  3200. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3201.  
  3202. ' e.g. ShearRotate3Test1 TestSprite1$
  3203.  
  3204. Sub ShearRotate3Test1 (sMap As String)
  3205.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3206.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3207.     'Dim sMap As String
  3208.     Dim D As Integer
  3209.     Dim D1 As Integer
  3210.     Dim in$
  3211.     Dim bFinished As Integer
  3212.     Dim iMissing As Integer
  3213.  
  3214.     ' GET A SHAPE TO BE ROTATED
  3215.     Cls
  3216.     Print "3 shear rotation based on code by leopardpm"
  3217.     'sMap = TestSprite1$
  3218.  
  3219.     ' CONVERT SHAPE TO ARRAY
  3220.     StringToRotationArray RoArray1(), sMap, "."
  3221.  
  3222.     ' GET START ANGLE
  3223.     D = 0
  3224.     Print
  3225.     Print "Rotated by " + cstr$(D) + " degrees:"
  3226.     Print RotationArrayToStringTest(RoArray1())
  3227.     Print
  3228.     Print "Type an angle (-360 to 360) to rotate to, "
  3229.     Print "or blank to increase by 1 degree, or q to quit."
  3230.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3231.     Print "Hold down <ENTER> to rotate continually."
  3232.     Input "Angle (q to quit)? ", in$
  3233.     If Len(in$) > 0 Then
  3234.         If IsNum%(in$) Then
  3235.             D1 = Val(in$)
  3236.         Else
  3237.             D1 = -500
  3238.         End If
  3239.     Else
  3240.         D1 = 1
  3241.     End If
  3242.  
  3243.     ' ROTATE TO EACH ANGLE
  3244.     If D1 >= -360 And D1 <= 360 Then
  3245.         bFinished = FALSE
  3246.         Do
  3247.             ' ROTATE CLOCKWISE
  3248.             For D = D1 To 360
  3249.                 Cls
  3250.  
  3251.                 ShearRotate3 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  3252.                 Print
  3253.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3254.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3255.  
  3256.                 Print RotationArrayToStringTest(RoArray2())
  3257.                 Print
  3258.  
  3259.                 Print "Type an angle (-360 to 360) to rotate to, "
  3260.                 Print "or blank to increase by 1 degree, or q to quit."
  3261.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3262.                 Print "Hold down <ENTER> to rotate continually."
  3263.                 Input "Angle (q to quit)? ", in$
  3264.                 If Len(in$) > 0 Then
  3265.                     If IsNum%(in$) Then
  3266.                         D = Val(in$)
  3267.                         If D >= 0 And D <= 360 Then
  3268.                             D = D - 1
  3269.                         Else
  3270.                             bFinished = TRUE
  3271.                             Exit For
  3272.                         End If
  3273.                     Else
  3274.                         bFinished = TRUE
  3275.                         Exit For
  3276.                     End If
  3277.                 End If
  3278.             Next D
  3279.             If bFinished = TRUE Then Exit Do
  3280.  
  3281.             ' ROTATE COUNTER-CLOCKWISE
  3282.             For D = 360 To D1 Step -1
  3283.                 Cls
  3284.                 ShearRotate3 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  3285.                 Print
  3286.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3287.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3288.  
  3289.                 Print RotationArrayToStringTest(RoArray2())
  3290.                 Print
  3291.  
  3292.                 Print "Type an angle (0 to 360) to rotate to, "
  3293.                 Print "or blank to increase by 1 degree, or q to quit."
  3294.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3295.                 Print "Hold down <ENTER> to rotate continually."
  3296.                 Input "Angle (q to quit)? ", in$
  3297.                 If Len(in$) > 0 Then
  3298.                     If IsNum%(in$) Then
  3299.                         D = Val(in$)
  3300.                         If D >= 0 And D <= 360 Then
  3301.                             D = D + 1
  3302.                         Else
  3303.                             bFinished = TRUE
  3304.                             Exit For
  3305.                         End If
  3306.                     Else
  3307.                         bFinished = TRUE
  3308.                         Exit For
  3309.                     End If
  3310.                 End If
  3311.             Next D
  3312.             If bFinished = TRUE Then Exit Do
  3313.         Loop
  3314.     End If
  3315. End Sub ' ShearRotate3Test1
  3316.  
  3317. ' /////////////////////////////////////////////////////////////////////////////
  3318. ' ShearRotate v4
  3319.  
  3320. ' Tries to fix the problem of 2 points resolving to the same coordinate
  3321. ' (one overwrites the other, which becomes "lost")
  3322. ' using a different approach, by just looking at the problem angles:
  3323. ' 30, 60, 120, 150, 210, 240, 300, 330 degrees
  3324.  
  3325. ' (which can be cClockwise or cCounterClockwise)
  3326. ' together with which quarter of the screen the point is in,
  3327.  
  3328. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3329.  
  3330. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  3331.  
  3332. Sub ShearRotate4 ( _
  3333.     OldArray() As RotationType, _
  3334.     NewArray() As RotationType, _
  3335.     angle1 As Integer, _
  3336.     iDirection As Integer, _
  3337.     iEmpty As Integer, _
  3338.     iMissing As Integer)
  3339.  
  3340.     Const Pi = 4 * Atn(1)
  3341.  
  3342.     Dim angle As Integer
  3343.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  3344.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  3345.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  3346.     Dim x As Integer
  3347.     Dim y As Integer
  3348.     Dim nangle As Integer
  3349.     Dim nx As Integer
  3350.     Dim ny As Integer
  3351.     Dim flipper As Integer
  3352.     Dim rotr As Double
  3353.     Dim shear1 As Double
  3354.     Dim shear2 As Double
  3355.     Dim clr As Integer
  3356.     Dim y1 As _Byte
  3357.     Dim xy1 As _Byte
  3358.     Dim fy As _Byte
  3359.     Dim fx As _Byte
  3360.     Dim in$
  3361.     Dim sLine As String
  3362.     ReDim arrLost(-1) As RotationType
  3363.     Dim iLoop As Integer
  3364.     Dim bFound As Integer
  3365.     Dim iScreenZone As Integer
  3366.     Dim iMidX As Integer
  3367.     Dim iMidY As Integer
  3368.  
  3369.     ' initialize new with empty
  3370.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3371.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3372.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3373.             NewArray(x, y, 0).origx = x
  3374.             NewArray(x, y, 0).origy = y
  3375.             NewArray(x, y, 0).c = iEmpty
  3376.         Next y
  3377.     Next x
  3378.  
  3379.     ' find midpoints
  3380.     iMidX = (UBound(OldArray, 1) - LBound(OldArray, 1)) / 2
  3381.     iMidY = (UBound(OldArray, 2) - LBound(OldArray, 2)) / 2
  3382.  
  3383.     ' angle is reversed
  3384.     angle = 360 - angle1
  3385.  
  3386.     ' Shearing each element 3 times in one shot
  3387.     nangle = angle
  3388.  
  3389.     ' this pre-processing portion basically rotates by 90 to get
  3390.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  3391.     If angle > 45 And angle < 225 Then
  3392.         If angle < 135 Then
  3393.             nangle = angle - 90
  3394.         Else
  3395.             nangle = angle - 180
  3396.         End If
  3397.     End If
  3398.     If angle > 135 And angle < 315 Then
  3399.         If angle < 225 Then
  3400.             nangle = angle - 180
  3401.         Else
  3402.             nangle = angle - 270
  3403.         End If
  3404.     End If
  3405.     If nangle < 0 Then
  3406.         nangle = nangle + 360
  3407.     End If
  3408.     If nangle > 359 Then
  3409.         nangle = nangle - 360
  3410.     End If
  3411.  
  3412.     rotr = nangle * DtoR
  3413.     shear1 = Tan(rotr / 2) ' correct way
  3414.     shear2 = Sin(rotr)
  3415.  
  3416.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  3417.     ' ***       all resolve to -45 degrees.
  3418.     ' ***       Fixed by changing < to <=
  3419.  
  3420.     'if angle >  45 and angle < 134 then
  3421.     If angle > 45 And angle <= 134 Then
  3422.         flipper = 1
  3423.     ElseIf angle > 134 And angle <= 224 Then
  3424.         flipper = 2
  3425.     ElseIf angle > 224 And angle <= 314 Then
  3426.         ' *** NOTE: this had a bug where this flipper was wrong
  3427.         '           Fixed by adding case 7
  3428.         'flipper = 3
  3429.         flipper = 7
  3430.     Else
  3431.         flipper = 0
  3432.     End If
  3433.  
  3434.     ' Here is where it needs some optimizing possibly... kinda slow...
  3435.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3436.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3437.  
  3438.             ' find which part of screen the current point is in
  3439.             If y > iMidY Then
  3440.                 ' bottom half of screen
  3441.                 If x > iMidX Then
  3442.                     ' right half of screen
  3443.                     iScreenZone = 2
  3444.                 Else
  3445.                     ' left half of screen
  3446.                     iScreenZone = 3
  3447.                 End If
  3448.             Else
  3449.                 ' top half of screen
  3450.                 If x > iMidX Then
  3451.                     ' right half of screen
  3452.                     iScreenZone = 1
  3453.                 Else
  3454.                     ' left half of screen
  3455.                     iScreenZone = 4
  3456.                 End If
  3457.             End If
  3458.  
  3459.             ' calculate directions
  3460.             Select Case flipper
  3461.                 Case 1:
  3462.                     nx = -y
  3463.                     ny = x
  3464.                 Case 2:
  3465.                     nx = -x
  3466.                     ny = -y
  3467.                 Case 3:
  3468.                     nx = -y
  3469.                     ny = -x
  3470.                 Case 4:
  3471.                     nx = -x
  3472.                     ny = y
  3473.                 Case 5:
  3474.                     nx = x
  3475.                     ny = -y
  3476.                 Case 6:
  3477.                     nx = y
  3478.                     ny = x
  3479.                 Case 7:
  3480.                     nx = y
  3481.                     ny = -x
  3482.                 Case Else:
  3483.                     nx = x
  3484.                     ny = y
  3485.             End Select
  3486.  
  3487.             clr = OldArray(nx, ny, 0).c
  3488.  
  3489.             y1 = y * shear1
  3490.             xy1 = x + y1
  3491.             fy = (y - xy1 * shear2)
  3492.             fx = xy1 + fy * shear1
  3493.  
  3494.             If fx >= -16 And fx <= 16 Then
  3495.                 If fy >= -16 And fy <= 16 Then
  3496.                     ' only draw here if this spot is empty
  3497.                     If NewArray(fx, fy, 0).c = iEmpty Then
  3498.                         NewArray(fx, fy, 0).c = clr
  3499.                         NewArray(fx, fy, 0).origx = fx
  3500.                         NewArray(fx, fy, 0).origy = fy
  3501.                     Else
  3502.                         ' don't draw, but save it to a list to handle later
  3503.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  3504.                         arrLost(UBound(arrLost)).c = clr
  3505.                         arrLost(UBound(arrLost)).origx = fx
  3506.                         arrLost(UBound(arrLost)).origy = fy
  3507.  
  3508.                         ' preserve which zone screen is in, 1 = top right, 2 = bottom right, 3 = bottom left, 4 = top left
  3509.                         arrLost(UBound(arrLost)).z = iScreenZone
  3510.                     End If
  3511.                 End If
  3512.             End If
  3513.         Next x
  3514.     Next y
  3515.  
  3516.     ' try to place any points that would have overwritten to a spot nearby
  3517.     ' can nearby be determined by the direction of rotation  (iDirection)
  3518.     ' together with which quarter of the screen the point is in (iScreenZone)
  3519.     ' where we divide the screen up into 4 zones:
  3520.  
  3521.     ' --------------------------------------
  3522.     '|                   |                  |
  3523.     '| zone 4            | zone 1           |
  3524.     '|                   |                  |
  3525.     '|--------------------------------------|
  3526.     '|                   |                  |
  3527.     '| zone 3            | zone 2           |
  3528.     '|                   |                  |
  3529.     '|                   |                  |
  3530.     ' --------------------------------------
  3531.  
  3532.     ' in zone   rotation direction   search direction (y,x)
  3533.     ' -------   ------------------   ----------------------
  3534.     ' 1         clockwise            down + right
  3535.     ' 1         counter-clockwise    up   + left
  3536.     ' 2         clockwise            down + left
  3537.     ' 2         counter-clockwise    up   + right
  3538.     ' 3         clockwise            up   + left
  3539.     ' 3         counter-clockwise    down + right
  3540.     ' 4         clockwise            up   + right
  3541.     ' 4         counter-clockwise    down + left
  3542.  
  3543.     If IsProblemAngle%(angle1) Then
  3544.         iMissing = 0
  3545.         For iLoop = 0 To UBound(arrLost)
  3546.             bFound = FindEmptyShearRotationPoint4%(arrLost(iLoop), iDirection, iEmpty, x, y, NewArray())
  3547.             If bFound = TRUE Then
  3548.                 If m_bDebug = TRUE Then
  3549.                     _Echo "Plotted  missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3550.                 End If
  3551.             Else
  3552.                 iMissing = iMissing + 1
  3553.                 If m_bDebug = TRUE Then
  3554.                     _Echo "Detected missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  3555.                 End If
  3556.             End If
  3557.         Next iLoop
  3558.     End If
  3559. End Sub ' ShearRotate4
  3560.  
  3561. ' /////////////////////////////////////////////////////////////////////////////
  3562. ' Returns TRUE if angle is any of
  3563. ' 30, 60, 120, 150, 210, 240, 300, 330
  3564.  
  3565. ' div: int1% = num1% \ den1%
  3566. ' mod: rem1% = num1% MOD den1%
  3567.  
  3568. Function IsProblemAngle% (angle As Integer)
  3569.     Dim bResult As Integer: bResult = FALSE
  3570.     Dim i%
  3571.     For i% = 0 To 360 Step 30
  3572.         If i% Mod 90 <> 0 Then
  3573.             If angle = i% Then
  3574.                 bResult = TRUE
  3575.                 Exit For
  3576.             End If
  3577.         End If
  3578.     Next i%
  3579.     IsProblemAngle% = bResult
  3580. End Function ' IsProblemAngle%
  3581.  
  3582. ' /////////////////////////////////////////////////////////////////////////////
  3583. ' Looks for a new point
  3584. ' a little more accurately, using iDirection parameter
  3585. ' which can be cClockwise or cCounterClockwise.
  3586.  
  3587. ' Note: cClockwise and cCounterClockwise constants must be declared globally.
  3588.  
  3589. ' Receives
  3590. ' FindMe (RotationType) = contains
  3591. '                         .origx, .origy = the starting location to start looking from,
  3592. '                         .z = which area of the screen the point is in
  3593. '                              (1=top right, 2=bottom right, 3=bottom left, 4=top left)
  3594. '                              to determine direction to look in
  3595. '                         .c = the value to write
  3596. ' iDirection (Integer) = direction of rotation, can be cClockwise or cCounterClockwise (constants must be declared globally)
  3597. ' iEmpty (Integer) = value to test against for empty
  3598. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  3599. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  3600. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  3601.  
  3602. ' Returns
  3603. ' FALSE if no empty spot was found
  3604. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  3605.  
  3606. Function FindEmptyShearRotationPoint4% (FindMe As RotationType, iDirection As Integer, iEmpty As Integer, destX As Integer, destY As Integer, NewArray() As RotationType)
  3607.     Dim bResult As Integer: bResult = FALSE
  3608.     Dim x As Integer
  3609.     Dim y As Integer
  3610.     Dim dirX As Integer
  3611.     Dim dirY As Integer
  3612.     Dim bContinue As Integer
  3613.  
  3614.     ' Initialize
  3615.     destX = 0
  3616.     destY = 0
  3617.     bContinue = TRUE
  3618.  
  3619.     ' Choose search direction based on the quadrant of the screen
  3620.     ' and the direction of rotation:
  3621.  
  3622.     ' iScreenZone   iDirection           search direction (y,x)
  3623.     ' -----------   ------------------   ----------------------
  3624.     ' 1             cClockwise           down + right ( 1, 1)
  3625.     ' 1             cCounterClockwise    up   + left  (-1,-1)
  3626.     ' 2             cClockwise           down + left  ( 1,-1)
  3627.     ' 2             cCounterClockwise    up   + right (-1, 1)
  3628.     ' 3             cClockwise           up   + left  (-1,-1)
  3629.     ' 3             cCounterClockwise    down + right ( 1, 1)
  3630.     ' 4             cClockwise           up   + right (-1, 1)
  3631.     ' 4             cCounterClockwise    down + left  ( 1,-1)
  3632.  
  3633.     If FindMe.z = 1 And iDirection = cClockwise Then
  3634.         dirY = 1
  3635.         dirX = 1
  3636.     ElseIf FindMe.z = 1 And iDirection = cCounterClockwise Then
  3637.         dirY = -1
  3638.         dirX = -1
  3639.     ElseIf FindMe.z = 2 And iDirection = cClockwise Then
  3640.         dirY = 1
  3641.         dirX = -1
  3642.     ElseIf FindMe.z = 2 And iDirection = cCounterClockwise Then
  3643.         dirY = -1
  3644.         dirX = 1
  3645.     ElseIf FindMe.z = 3 And iDirection = cClockwise Then
  3646.         dirY = -1
  3647.         dirX = -1
  3648.     ElseIf FindMe.z = 3 And iDirection = cCounterClockwise Then
  3649.         dirY = 1
  3650.         dirX = 1
  3651.     ElseIf FindMe.z = 4 And iDirection = cClockwise Then
  3652.         dirY = -1
  3653.         dirX = 1
  3654.     ElseIf FindMe.z = 4 And iDirection = cCounterClockwise Then
  3655.         dirY = 1
  3656.         dirX = -1
  3657.     Else
  3658.         bContinue = FALSE
  3659.     End If
  3660.  
  3661.     ' Quit if we're out of bounds
  3662.     If bContinue = TRUE Then
  3663.         bContinue = FALSE
  3664.         x = FindMe.origx
  3665.         y = FindMe.origy
  3666.         If x >= LBound(NewArray, 1) Then
  3667.             If x <= UBound(NewArray, 1) Then
  3668.                 If y >= LBound(NewArray, 2) Then
  3669.                     If y <= UBound(NewArray, 2) Then
  3670.                         bContinue = TRUE
  3671.                     End If
  3672.                 End If
  3673.             End If
  3674.         End If
  3675.     End If
  3676.  
  3677.     ' look along y axis for an available adjacent point
  3678.     If bContinue = TRUE Then
  3679.         destX = x
  3680.         destY = y + dirY
  3681.         If destX >= LBound(NewArray, 1) Then
  3682.             If destX <= UBound(NewArray, 1) Then
  3683.                 If destY >= LBound(NewArray, 2) Then
  3684.                     If destY <= UBound(NewArray, 2) Then
  3685.                         If NewArray(destX, destY, 0).c = iEmpty Then
  3686.                             NewArray(destX, destY, 0).c = FindMe.c
  3687.                             bResult = TRUE
  3688.                             bContinue = FALSE
  3689.                         End If
  3690.                     End If
  3691.                 End If
  3692.             End If
  3693.         End If
  3694.     End If
  3695.  
  3696.     ' look along x axis for an available adjacent point
  3697.     If bContinue = TRUE Then
  3698.         destX = x + dirX
  3699.         destY = y
  3700.         If destX >= LBound(NewArray, 1) Then
  3701.             If destX <= UBound(NewArray, 1) Then
  3702.                 If destY >= LBound(NewArray, 2) Then
  3703.                     If destY <= UBound(NewArray, 2) Then
  3704.                         If NewArray(x + dirX, y, 0).c = iEmpty Then
  3705.                             NewArray(destX, destY, 0).c = FindMe.c
  3706.                             bResult = TRUE
  3707.                             bContinue = FALSE
  3708.                         End If
  3709.                     End If
  3710.                 End If
  3711.             End If
  3712.         End If
  3713.     End If
  3714.  
  3715.     ' look diagonally for an available adjacent point
  3716.     If bContinue = TRUE Then
  3717.         destX = x + dirX
  3718.         destY = y + dirY
  3719.         If destX >= LBound(NewArray, 1) Then
  3720.             If destX <= UBound(NewArray, 1) Then
  3721.                 If destY >= LBound(NewArray, 2) Then
  3722.                     If destY <= UBound(NewArray, 2) Then
  3723.                         If NewArray(x + dirX, y + dirY, 0).c = iEmpty Then
  3724.                             NewArray(destX, destY, 0).c = FindMe.c
  3725.                             bResult = TRUE
  3726.                             bContinue = FALSE
  3727.                         End If
  3728.                     End If
  3729.                 End If
  3730.             End If
  3731.         End If
  3732.     End If
  3733.  
  3734.     '   ' look (in the opposite direction) along y axis for an available adjacent point
  3735.     '   If bContinue = TRUE Then
  3736.     '       destX = x
  3737.     '       destY = y - dirY
  3738.     '       if destX >= LBound(NewArray, 1) then
  3739.     '           if destX <= UBound(NewArray, 1) then
  3740.     '               if destY >= LBound(NewArray, 2) then
  3741.     '                   if destY <= UBound(NewArray, 2) then
  3742.     '                       if NewArray(destX, destY, 0).c = iEmpty then
  3743.     '                           NewArray(destX, destY, 0).c = FindMe.c
  3744.     '                           bResult = TRUE
  3745.     '                           bContinue = FALSE
  3746.     '                       end if
  3747.     '                   end if
  3748.     '               end if
  3749.     '           end if
  3750.     '       end if
  3751.     '   end if
  3752.     '
  3753.     '   ' look (in the opposite direction) along x axis for an available adjacent point
  3754.     '   If bContinue = TRUE Then
  3755.     '       destX = x - dirX
  3756.     '       destY = y
  3757.     '       if destX >= LBound(NewArray, 1) then
  3758.     '           if destX <= UBound(NewArray, 1) then
  3759.     '               if destY >= LBound(NewArray, 2) then
  3760.     '                   if destY <= UBound(NewArray, 2) then
  3761.     '                       if NewArray(x + dirX, y, 0).c = iEmpty then
  3762.     '                           NewArray(destX, destY, 0).c = FindMe.c
  3763.     '                           bResult = TRUE
  3764.     '                           bContinue = FALSE
  3765.     '                       end if
  3766.     '                   end if
  3767.     '               end if
  3768.     '           end if
  3769.     '       end if
  3770.     '   end if
  3771.     '
  3772.     '   ' look (in the opposite direction) diagonally for an available adjacent point
  3773.     '   If bContinue = TRUE Then
  3774.     '       destX = x - dirX
  3775.     '       destY = y - dirY
  3776.     '       if destX >= LBound(NewArray, 1) then
  3777.     '           if destX <= UBound(NewArray, 1) then
  3778.     '               if destY >= LBound(NewArray, 2) then
  3779.     '                   if destY <= UBound(NewArray, 2) then
  3780.     '                       if NewArray(x + dirX, y + dirY, 0).c = iEmpty then
  3781.     '                           NewArray(destX, destY, 0).c = FindMe.c
  3782.     '                           bResult = TRUE
  3783.     '                           bContinue = FALSE
  3784.     '                       end if
  3785.     '                   end if
  3786.     '               end if
  3787.     '           end if
  3788.     '       end if
  3789.     '    End If
  3790.  
  3791.     ' Return result
  3792.     FindEmptyShearRotationPoint4% = bResult
  3793. End Function ' FindEmptyShearRotationPoint4%
  3794.  
  3795. ' /////////////////////////////////////////////////////////////////////////////
  3796. ' Tries to correct for missing points with improved logic v3
  3797.  
  3798. ' Receives parameter sMap
  3799. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3800.  
  3801. ' e.g. ShearRotate4Test1 TestSprite1$
  3802.  
  3803. Sub ShearRotate4Test1 (sMap As String)
  3804.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3805.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3806.     'Dim sMap As String
  3807.     Dim D As Integer
  3808.     Dim D1 As Integer
  3809.     Dim in$
  3810.     Dim bFinished As Integer
  3811.     Dim iMissing As Integer
  3812.  
  3813.     ' GET A SHAPE TO BE ROTATED
  3814.     Cls
  3815.     Print "3 shear rotation based on code by leopardpm"
  3816.     'sMap = TestSprite1$
  3817.  
  3818.     ' CONVERT SHAPE TO ARRAY
  3819.     StringToRotationArray RoArray1(), sMap, "."
  3820.  
  3821.     ' GET START ANGLE
  3822.     D = 0
  3823.     Print
  3824.     Print "Rotated by " + cstr$(D) + " degrees:"
  3825.     Print RotationArrayToStringTest(RoArray1())
  3826.     Print
  3827.     Print "Type an angle (-360 to 360) to rotate to, "
  3828.     Print "or blank to increase by 1 degree, or q to quit."
  3829.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3830.     Print "Hold down <ENTER> to rotate continually."
  3831.     Input "Angle (q to quit)? ", in$
  3832.     If Len(in$) > 0 Then
  3833.         If IsNum%(in$) Then
  3834.             D1 = Val(in$)
  3835.         Else
  3836.             D1 = -500
  3837.         End If
  3838.     Else
  3839.         D1 = 1
  3840.     End If
  3841.  
  3842.     ' ROTATE TO EACH ANGLE
  3843.     If D1 >= -360 And D1 <= 360 Then
  3844.         bFinished = FALSE
  3845.         Do
  3846.             ' ROTATE CLOCKWISE
  3847.             For D = D1 To 360
  3848.                 Cls
  3849.  
  3850.                 ShearRotate4 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  3851.                 Print
  3852.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3853.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3854.  
  3855.                 Print RotationArrayToStringTest(RoArray2())
  3856.                 Print
  3857.  
  3858.                 Print "Type an angle (-360 to 360) to rotate to, "
  3859.                 Print "or blank to increase by 1 degree, or q to quit."
  3860.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3861.                 Print "Hold down <ENTER> to rotate continually."
  3862.                 Input "Angle (q to quit)? ", in$
  3863.                 If Len(in$) > 0 Then
  3864.                     If IsNum%(in$) Then
  3865.                         D = Val(in$)
  3866.                         If D >= 0 And D <= 360 Then
  3867.                             D = D - 1
  3868.                         Else
  3869.                             bFinished = TRUE
  3870.                             Exit For
  3871.                         End If
  3872.                     Else
  3873.                         bFinished = TRUE
  3874.                         Exit For
  3875.                     End If
  3876.                 End If
  3877.             Next D
  3878.             If bFinished = TRUE Then Exit Do
  3879.  
  3880.             ' ROTATE COUNTER-CLOCKWISE
  3881.             For D = 360 To D1 Step -1
  3882.                 Cls
  3883.                 ShearRotate4 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  3884.                 Print
  3885.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  3886.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  3887.  
  3888.                 Print RotationArrayToStringTest(RoArray2())
  3889.                 Print
  3890.  
  3891.                 Print "Type an angle (0 to 360) to rotate to, "
  3892.                 Print "or blank to increase by 1 degree, or q to quit."
  3893.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3894.                 Print "Hold down <ENTER> to rotate continually."
  3895.                 Input "Angle (q to quit)? ", in$
  3896.                 If Len(in$) > 0 Then
  3897.                     If IsNum%(in$) Then
  3898.                         D = Val(in$)
  3899.                         If D >= 0 And D <= 360 Then
  3900.                             D = D + 1
  3901.                         Else
  3902.                             bFinished = TRUE
  3903.                             Exit For
  3904.                         End If
  3905.                     Else
  3906.                         bFinished = TRUE
  3907.                         Exit For
  3908.                     End If
  3909.                 End If
  3910.             Next D
  3911.             If bFinished = TRUE Then Exit Do
  3912.         Loop
  3913.     End If
  3914. End Sub ' ShearRotate4Test1
  3915.  
  3916. ' /////////////////////////////////////////////////////////////////////////////
  3917. ' Correct for overwriting points issue
  3918. ' (happens at 30, 60, 120, 150, 210, 240, 300, 330 degrees)
  3919. ' using STxAxTIC's method of merging array rotated to angle-1 and angle+1
  3920.  
  3921. Sub ShearRotate5 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  3922.     ReDim arrCW(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3923.     ReDim arrCCW(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  3924.  
  3925.     ' If rotation is 30, 60, 120, 150, 210, 240, 300, 330 degrees
  3926.     ' then try correcting for overwriting.
  3927.     If IsProblemAngle%(angle1) Then
  3928.         ' get array rotated to angle-1
  3929.         ShearRotate OldArray(), arrCW(), angle1 - 1, iEmpty
  3930.  
  3931.         ' get array rotated to angle
  3932.         ShearRotate OldArray(), NewArray(), angle1 - 1, iEmpty
  3933.  
  3934.         ' get array rotated to angle=1
  3935.         ShearRotate OldArray(), arrCCW(), angle1 + 1, iEmpty
  3936.  
  3937.         ' merge the results
  3938.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  3939.             For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  3940.                 ' is point empty?
  3941.                 If NewArray(x, y, 0).c = iEmpty Then
  3942.                     ' see if point is occupied 1 deg. counter-clockwise
  3943.                     If arrCCW(x, y, 0).c <> iEmpty Then
  3944.                         NewArray(x, y, 0).c = arrCCW(x, y, 0).c
  3945.                         ' see if point is occupied 1 deg. clockwise
  3946.                     ElseIf arrCW(x, y, 0).c <> iEmpty Then
  3947.                         NewArray(x, y, 0).c = arrCW(x, y, 0).c
  3948.                     End If
  3949.                 End If
  3950.             Next y
  3951.         Next x
  3952.         ' Otherwise rotate without correcting.
  3953.     Else
  3954.         ShearRotate OldArray(), NewArray(), angle1, iEmpty
  3955.     End If
  3956. End Sub ' ShearRotate5
  3957.  
  3958. ' /////////////////////////////////////////////////////////////////////////////
  3959. ' Tries to correct for missing (overwritten) points
  3960. ' using STxAxTIC's method to correct for overwritten points
  3961.  
  3962. ' Receives parameter sMap
  3963. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  3964.  
  3965. ' e.g. ShearRotate5Test1 TestSprite1$
  3966.  
  3967. Sub ShearRotate5Test1 (sMap As String)
  3968.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  3969.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  3970.     'Dim sMap As String
  3971.     Dim D As Integer
  3972.     Dim D1 As Integer
  3973.     Dim in$
  3974.     Dim bFinished As Integer
  3975.     'Dim iMissing As Integer
  3976.  
  3977.     ' GET A SHAPE TO BE ROTATED
  3978.     Cls
  3979.     Print "3 shear rotation based on code by leopardpm"
  3980.     Print "using STxAxTIC's method to correct for overwritten points"
  3981.     'sMap = TestSprite1$
  3982.  
  3983.     ' CONVERT SHAPE TO ARRAY
  3984.     StringToRotationArray RoArray1(), sMap, "."
  3985.  
  3986.     ' GET START ANGLE
  3987.     D = 0
  3988.     Print
  3989.     Print "Rotated by " + cstr$(D) + " degrees:"
  3990.     Print RotationArrayToStringTest(RoArray1())
  3991.     Print
  3992.     Print "Type an angle (-360 to 360) to rotate to, "
  3993.     Print "or blank to increase by 1 degree, or q to quit."
  3994.     Print "Note: Tries to fix for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  3995.     Print "Hold down <ENTER> to rotate continually."
  3996.     Input "Angle (q to quit)? ", in$
  3997.     If Len(in$) > 0 Then
  3998.         If IsNum%(in$) Then
  3999.             D1 = Val(in$)
  4000.         Else
  4001.             D1 = -500
  4002.         End If
  4003.     Else
  4004.         D1 = 1
  4005.     End If
  4006.  
  4007.     ' ROTATE TO EACH ANGLE
  4008.     If D1 >= -360 And D1 <= 360 Then
  4009.         bFinished = FALSE
  4010.         Do
  4011.             ' ROTATE CLOCKWISE
  4012.             For D = D1 To 360
  4013.                 Cls
  4014.  
  4015.                 'ShearRotate4 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  4016.                 ShearRotate5 RoArray1(), RoArray2(), D, Asc(".")
  4017.                 Print
  4018.                 Print "Rotated by " + cstr$(D) + " degrees:"
  4019.                 'Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  4020.  
  4021.                 Print RotationArrayToStringTest(RoArray2())
  4022.                 Print
  4023.  
  4024.                 Print "Type an angle (-360 to 360) to rotate to, "
  4025.                 Print "or blank to increase by 1 degree, or q to quit."
  4026.                 Print "Note: Tries to fix for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4027.                 Print "Hold down <ENTER> to rotate continually."
  4028.                 Input "Angle (q to quit)? ", in$
  4029.                 If Len(in$) > 0 Then
  4030.                     If IsNum%(in$) Then
  4031.                         D = Val(in$)
  4032.                         If D >= 0 And D <= 360 Then
  4033.                             D = D - 1
  4034.                         Else
  4035.                             bFinished = TRUE
  4036.                             Exit For
  4037.                         End If
  4038.                     Else
  4039.                         bFinished = TRUE
  4040.                         Exit For
  4041.                     End If
  4042.                 End If
  4043.             Next D
  4044.             If bFinished = TRUE Then Exit Do
  4045.  
  4046.             ' ROTATE COUNTER-CLOCKWISE
  4047.             For D = 360 To D1 Step -1
  4048.                 Cls
  4049.                 'ShearRotate4 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  4050.                 ShearRotate5 RoArray1(), RoArray2(), D, Asc(".")
  4051.                 Print
  4052.                 Print "Rotated by " + cstr$(D) + " degrees:"
  4053.                 'Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$ (iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  4054.  
  4055.                 Print RotationArrayToStringTest(RoArray2())
  4056.                 Print
  4057.  
  4058.                 Print "Type an angle (0 to 360) to rotate to, "
  4059.                 Print "or blank to increase by 1 degree, or q to quit."
  4060.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4061.                 Print "Hold down <ENTER> to rotate continually."
  4062.                 Input "Angle (q to quit)? ", in$
  4063.                 If Len(in$) > 0 Then
  4064.                     If IsNum%(in$) Then
  4065.                         D = Val(in$)
  4066.                         If D >= 0 And D <= 360 Then
  4067.                             D = D + 1
  4068.                         Else
  4069.                             bFinished = TRUE
  4070.                             Exit For
  4071.                         End If
  4072.                     Else
  4073.                         bFinished = TRUE
  4074.                         Exit For
  4075.                     End If
  4076.                 End If
  4077.             Next D
  4078.             If bFinished = TRUE Then Exit Do
  4079.         Loop
  4080.     End If
  4081. End Sub ' ShearRotate5Test1
  4082.  
  4083. ' /////////////////////////////////////////////////////////////////////////////
  4084. ' Correct for overwriting points issue
  4085. ' (happens at 30, 60, 120, 150, 210, 240, 300, 330 degrees)
  4086. ' using STxAxTIC's method of merging array rotated to angle-1 and angle+1
  4087. ' updated with using precalculated arrays to find the exact location
  4088. ' a given point should rotate to.
  4089.  
  4090. ' Receives:
  4091. ' OldArray = array to rotate
  4092. ' NewArray = rotated array returned here
  4093. ' angle = angle to rotate to
  4094. ' iDirection = cClockwise or cCounterClockwise (cClockwise and cCounterClockwise constants must be declared globally)
  4095. ' iEmpty = value for empty
  4096. ' iMissing = return value (byref), number of points not found
  4097.  
  4098. Sub ShearRotate6 (OldArray() As RotationType, NewArray() As RotationType, angle As Integer, iDirection As Integer, iEmpty As Integer, iMissing As Integer)
  4099.     Dim iValue As Integer
  4100.     Dim iMaxValue As Integer
  4101.     Dim sLine As String
  4102.     Dim oSearch As RotationType
  4103.  
  4104.     ' *****************************************************************************
  4105.     ' NOTE: THESE WOULD BE SHARED ARRAYS, PRE-POPULATED AHEAD OF TIME
  4106.     ReDim arrMaskIndex(-1) As Integer
  4107.     ReDim arrMasks(-1, -1, -1) As RotationType
  4108.  
  4109.     ' Initialize
  4110.     iMissing = 0
  4111.  
  4112.     ' Get index
  4113.     GetMaskIndex arrMaskIndex()
  4114.  
  4115.     ' Get rotation masks
  4116.     GetRotationMasks OldArray(), arrMasks(), iMaxValue
  4117.     ' *****************************************************************************
  4118.  
  4119.     ' If rotation is 30, 60, 120, 150, 210, 240, 300, 330 degrees
  4120.     ' then try correcting for overwriting.
  4121.     If IsProblemAngle%(angle) Then
  4122.  
  4123.         ' do we have a mask index for this angle?
  4124.         If arrMaskIndex(angle) > 0 Then
  4125.  
  4126.             ' initialize new with empty
  4127.             ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  4128.             For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  4129.                 For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  4130.                     NewArray(x, y, 0).origx = x
  4131.                     NewArray(x, y, 0).origy = y
  4132.                     NewArray(x, y, 0).c = iEmpty
  4133.                 Next y
  4134.             Next x
  4135.  
  4136.             ' first do basic rotate
  4137.             For y = LBound(OldArray, 2) To UBound(OldArray, 2)
  4138.                 For x = LBound(OldArray, 1) To UBound(OldArray, 1)
  4139.                     ' get the mask value from unrotated
  4140.                     iValue = arrMasks(arrMaskIndex(0), x, y).c
  4141.  
  4142.                     ' is mask value in the rotated?
  4143.                     FindValueInMask arrMasks(), arrMaskIndex(angle), iValue, oSearch
  4144.                     If oSearch.c = TRUE Then
  4145.                         ' found, copy point
  4146.                         NewArray(oSearch.origx, oSearch.origy, 0).c = OldArray(x, y, 0).c
  4147.                     Else
  4148.                         ' not found, try get from adjacent angles
  4149.  
  4150.                         If iDirection = cCounterClockwise Then
  4151.                             ' is mask value in the rotated -1 ?
  4152.                             FindValueInMask arrMasks(), arrMaskIndex(angle - 1), iValue, oSearch
  4153.                             If oSearch.c = TRUE Then
  4154.                                 ' found, copy point
  4155.                                 NewArray(oSearch.origx, oSearch.origy, 0).c = OldArray(x, y, 0).c
  4156.                             Else
  4157.                                 ' not found, try to get from rotated +1
  4158.                                 FindValueInMask arrMasks(), arrMaskIndex(angle + 1), iValue, oSearch
  4159.                                 If oSearch.c = TRUE Then
  4160.                                     ' found, copy point
  4161.                                     NewArray(oSearch.origx, oSearch.origy, 0).c = OldArray(x, y, 0).c
  4162.                                 Else
  4163.                                     ' not found, oh well
  4164.                                     iMissing = iMissing + 1
  4165.                                 End If
  4166.                             End If
  4167.                         Else ' assume iDirection = cClockwise
  4168.                             ' is mask value in the rotated +1 ?
  4169.                             FindValueInMask arrMasks(), arrMaskIndex(angle + 1), iValue, oSearch
  4170.                             If oSearch.c = TRUE Then
  4171.                                 ' found, copy point
  4172.                                 NewArray(oSearch.origx, oSearch.origy, 0).c = OldArray(x, y, 0).c
  4173.                             Else
  4174.                                 ' not found, try to get from rotated -1
  4175.                                 FindValueInMask arrMasks(), arrMaskIndex(angle - 1), iValue, oSearch
  4176.                                 If oSearch.c = TRUE Then
  4177.                                     ' found, copy point
  4178.                                     NewArray(oSearch.origx, oSearch.origy, 0).c = OldArray(x, y, 0).c
  4179.                                 Else
  4180.                                     ' not found, oh well
  4181.                                     iMissing = iMissing + 1
  4182.                                 End If
  4183.                             End If
  4184.                         End If
  4185.                     End If
  4186.                 Next x
  4187.             Next y
  4188.         End If
  4189.         ' Otherwise rotate without correcting.
  4190.     Else
  4191.         ShearRotate OldArray(), NewArray(), angle, iEmpty
  4192.     End If
  4193. End Sub ' ShearRotate6
  4194.  
  4195. ' /////////////////////////////////////////////////////////////////////////////
  4196. ' looks for value iValue in arrMasks(iIndex, [x], [y])
  4197. ' and returns results in oResult (RotationType):
  4198. ' * if found, returns oResult.c = TRUE, and x,y found at in oResult.origx, oResult.origy
  4199. ' * if not found, returns oResult.c = FALSE
  4200.  
  4201. '   FindValueInMask arrMasks(), arrMaskIndex(angle), iValue, c
  4202.  
  4203. Sub FindValueInMask (arrMasks() As RotationType, iIndex As Integer, iValue As Integer, oResult As RotationType)
  4204.     Dim iLoopY As Integer
  4205.     Dim iLoopX As Integer
  4206.     Dim bFound As Integer
  4207.     oResult.c = FALSE
  4208.     bFound = FALSE
  4209.     For iLoopY = LBound(arrMasks, 3) To UBound(arrMasks, 3)
  4210.         For iLoopX = LBound(arrMasks, 2) To UBound(arrMasks, 2)
  4211.             If arrMasks(iIndex, iLoopX, iLoopY).c = iValue Then
  4212.                 oResult.c = TRUE
  4213.                 oResult.origx = iLoopX
  4214.                 oResult.origy = iLoopY
  4215.                 'iLoopY = ubound(arrMasks, 3)+1
  4216.                 bFound = TRUE
  4217.                 Exit For
  4218.             End If
  4219.         Next iLoopX
  4220.         If bFound = TRUE Then Exit For
  4221.     Next iLoopY
  4222. End Sub ' FindValueInMask
  4223.  
  4224. ' /////////////////////////////////////////////////////////////////////////////
  4225. ' Tries to correct for missing (overwritten) points
  4226. ' using STxAxTIC's method to correct for overwritten points
  4227. ' updated with using precalculated arrays to find the exact location
  4228. ' a given point should rotate to.
  4229.  
  4230. ' Receives parameter sMap
  4231. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  4232.  
  4233. ' e.g. ShearRotate6Test1 TestSprite1$
  4234.  
  4235. Sub ShearRotate6Test1 (sMap As String)
  4236.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  4237.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  4238.     'Dim sMap As String
  4239.     Dim D As Integer
  4240.     Dim D1 As Integer
  4241.     Dim in$
  4242.     Dim bFinished As Integer
  4243.     Dim iDirection As Integer
  4244.     Dim iMissing As Integer
  4245.  
  4246.     ' GET A SHAPE TO BE ROTATED
  4247.     Cls
  4248.     Print "3 shear rotation based on code by leopardpm"
  4249.     Print "using STxAxTIC's method to correct for overwritten points"
  4250.     Print "updated with using precalculated arrays to find the exact location"
  4251.     Print "a given point should rotate to."
  4252.  
  4253.     'sMap = TestSprite1$
  4254.  
  4255.     ' CONVERT SHAPE TO ARRAY
  4256.     StringToRotationArray RoArray1(), sMap, "."
  4257.  
  4258.     ' GET START ANGLE
  4259.     D = 0
  4260.     Print
  4261.     Print "Rotated by " + cstr$(D) + " degrees:"
  4262.     Print RotationArrayToStringTest(RoArray1())
  4263.     Print
  4264.     Print "Type an angle (-360 to 360) to rotate to, "
  4265.     Print "or blank to increase by 1 degree, or q to quit."
  4266.     Print "Note: Tries to fix for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4267.     Print "Hold down <ENTER> to rotate continually."
  4268.     Input "Angle (q to quit)? ", in$
  4269.     If Len(in$) > 0 Then
  4270.         If IsNum%(in$) Then
  4271.             D1 = Val(in$)
  4272.         Else
  4273.             D1 = -500
  4274.         End If
  4275.     Else
  4276.         D1 = 1
  4277.     End If
  4278.  
  4279.     ' ROTATE TO EACH ANGLE
  4280.     If D1 >= -360 And D1 <= 360 Then
  4281.         bFinished = FALSE
  4282.         Do
  4283.             ' ROTATE CLOCKWISE
  4284.             iDirection = cClockwise
  4285.             For D = D1 To 360
  4286.                 Cls
  4287.  
  4288.                 'ShearRotate4 RoArray1(), RoArray2(), D, cClockwise, Asc("."), iMissing
  4289.                 ShearRotate6 RoArray1(), RoArray2(), D, iDirection, Asc("."), iMissing
  4290.  
  4291.                 Print
  4292.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  4293.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  4294.  
  4295.                 Print RotationArrayToStringTest(RoArray2())
  4296.                 Print
  4297.  
  4298.                 Print "Type an angle (-360 to 360) to rotate to, "
  4299.                 Print "or blank to increase by 1 degree, or q to quit."
  4300.                 Print "Note: Tries to fix for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4301.                 Print "Hold down <ENTER> to rotate continually."
  4302.                 Input "Angle (q to quit)? ", in$
  4303.                 If Len(in$) > 0 Then
  4304.                     If IsNum%(in$) Then
  4305.                         D = Val(in$)
  4306.                         If D >= 0 And D <= 360 Then
  4307.                             D = D - 1
  4308.                         Else
  4309.                             bFinished = TRUE
  4310.                             Exit For
  4311.                         End If
  4312.                     Else
  4313.                         bFinished = TRUE
  4314.                         Exit For
  4315.                     End If
  4316.                 End If
  4317.             Next D
  4318.             If bFinished = TRUE Then Exit Do
  4319.  
  4320.             ' ROTATE COUNTER-CLOCKWISE
  4321.             iDirection = cCounterClockwise
  4322.             For D = 360 To D1 Step -1
  4323.                 Cls
  4324.                 'ShearRotate4 RoArray1(), RoArray2(), D, cCounterClockwise, Asc("."), iMissing
  4325.                 ShearRotate6 RoArray1(), RoArray2(), D, iDirection, Asc("."), iMissing
  4326.  
  4327.                 Print
  4328.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  4329.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  4330.  
  4331.                 Print RotationArrayToStringTest(RoArray2())
  4332.                 Print
  4333.  
  4334.                 Print "Type an angle (0 to 360) to rotate to, "
  4335.                 Print "or blank to increase by 1 degree, or q to quit."
  4336.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  4337.                 Print "Hold down <ENTER> to rotate continually."
  4338.                 Input "Angle (q to quit)? ", in$
  4339.                 If Len(in$) > 0 Then
  4340.                     If IsNum%(in$) Then
  4341.                         D = Val(in$)
  4342.                         If D >= 0 And D <= 360 Then
  4343.                             D = D + 1
  4344.                         Else
  4345.                             bFinished = TRUE
  4346.                             Exit For
  4347.                         End If
  4348.                     Else
  4349.                         bFinished = TRUE
  4350.                         Exit For
  4351.                     End If
  4352.                 End If
  4353.             Next D
  4354.             If bFinished = TRUE Then Exit Do
  4355.         Loop
  4356.     End If
  4357. End Sub ' ShearRotate6Test1
  4358.  
  4359. ' /////////////////////////////////////////////////////////////////////////////
  4360.  
  4361. Sub GetRotationMaskTest
  4362.     Dim RoutineName As String: RoutineName = "GetRotationMaskTest"
  4363.     ReDim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  4364.     'ReDim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  4365.     ReDim arrMaskIndex(-1) As Integer
  4366.     ReDim arrMasks(-1, -1, -1) As RotationType
  4367.     Dim iLoop%
  4368.     Dim x As Integer
  4369.     Dim y As Integer
  4370.     Dim sLine As String
  4371.     Dim iIndex%
  4372.     Dim iMaxValue%
  4373.     Dim in$
  4374.  
  4375.     Width 180, 100
  4376.  
  4377.     ' Get index
  4378.     GetMaskIndex arrMaskIndex()
  4379.  
  4380.     Cls
  4381.     Print "Contents of arrMaskIndex:"
  4382.     For iLoop% = LBound(arrMaskIndex) To UBound(arrMaskIndex)
  4383.         If arrMaskIndex(iLoop%) > 0 Then
  4384.             Print "arrMaskIndex(" + cstr$(iLoop%) + ") = " + cstr$(arrMaskIndex(iLoop%))
  4385.         End If
  4386.     Next iLoop%
  4387.     Print
  4388.     Input "PRESS <ENTER> TO CONTINUE OR q TO QUIT"; in$
  4389.     If in$ = "q" Then GoTo CleanupAndExit
  4390.  
  4391.     ' Get rotation masks
  4392.     GetRotationMasks RoArray1(), arrMasks(), iMaxValue%
  4393.  
  4394.     ' Show unrotated mask
  4395.     Cls
  4396.     Print "Unrotated mask, containing unique values 1-" + cstr$(iMaxValue%) + ":"
  4397.     iIndex% = 0
  4398.     For y = LBound(arrMasks, 3) To UBound(arrMasks, 3)
  4399.         sLine = ""
  4400.         For x = LBound(arrMasks, 2) To UBound(arrMasks, 2)
  4401.             sLine = sLine + IIFSTR$(Len(sLine) = 0, "", ",") + Right$("    " + cstr$(arrMasks(iIndex%, x, y).c), 4)
  4402.         Next x
  4403.         Print sLine
  4404.     Next y
  4405.     Print
  4406.     Input "PRESS <ENTER> TO CONTINUE OR q TO QUIT"; in$
  4407.     If in$ = "q" Then GoTo CleanupAndExit
  4408.  
  4409.     ' Show what we have
  4410.     For iLoop% = 0 To 360
  4411.         iIndex% = arrMaskIndex(iLoop%)
  4412.         'print "arrMaskIndex(" + cstr$(iLoop%) + ") = " + cstr$(iIndex%)
  4413.         If iIndex% > 0 Then
  4414.             Cls
  4415.             Print "arrMaskIndex(" + cstr$(iLoop%) + ") = " + cstr$(iIndex%)
  4416.             For y = LBound(arrMasks, 3) To UBound(arrMasks, 3)
  4417.                 sLine = ""
  4418.                 For x = LBound(arrMasks, 2) To UBound(arrMasks, 2)
  4419.                     sLine = sLine + IIFSTR$(Len(sLine) = 0, "", ",") + Right$("    " + cstr$(arrMasks(iIndex%, x, y).c), 4)
  4420.                 Next x
  4421.                 Print sLine
  4422.             Next y
  4423.             Print
  4424.             Input "PRESS <ENTER> TO CONTINUE OR q TO QUIT"; in$
  4425.             If in$ = "q" Then GoTo CleanupAndExit
  4426.         End If
  4427.     Next iLoop%
  4428.  
  4429.     Print
  4430.     Print RoutineName + " finished."
  4431.     Input "PRESS <ENTER> TO CONTINUE"; in$
  4432.  
  4433.     CleanupAndExit:
  4434.     'Screen 0
  4435.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  4436. End Sub ' GetRotationMaskTest
  4437.  
  4438. ' /////////////////////////////////////////////////////////////////////////////
  4439. ' Returns array with rotation masks
  4440. ' NewArray(index, x, y) of RotationType
  4441. ' and maximum unique value iValue.
  4442. ' (Values range from 1 to iValue.)
  4443.  
  4444. Sub GetRotationMasks (OldArray() As RotationType, NewArray() As RotationType, iValue As Integer)
  4445.     ReDim arrMask(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  4446.     ReDim arrNext(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  4447.     ReDim arrMaskIndex(-1) As Integer
  4448.     Dim x As Integer
  4449.     Dim y As Integer
  4450.     Dim angle As Integer
  4451.     Dim iIndex As Integer
  4452.  
  4453.     ' Get index
  4454.     GetMaskIndex arrMaskIndex()
  4455.  
  4456.     ' Size array
  4457.     ReDim NewArray(0 To UBound(arrMaskIndex), LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2)) As RotationType
  4458.  
  4459.     ' create the original mask
  4460.     iValue = 0
  4461.     For y = LBound(OldArray, 2) To UBound(OldArray, 2)
  4462.         For x = LBound(OldArray, 1) To UBound(OldArray, 1)
  4463.             iValue = iValue + 1
  4464.             arrMask(x, y, 0).c = iValue
  4465.             arrMask(x, y, 0).origx = x
  4466.             arrMask(x, y, 0).origy = y
  4467.  
  4468.             NewArray(0, x, y).c = iValue
  4469.             NewArray(0, x, y).origx = x
  4470.             NewArray(0, x, y).origy = y
  4471.         Next x
  4472.     Next y
  4473.  
  4474.     ' create rotated masks
  4475.     For angle = 30 To 330
  4476.         ' If angle is 30, 60, 120, 150, 210, 240, 300, 330 degrees
  4477.         ' then precalculate rotation masks for angle-1, angle, angle+1
  4478.         ' and store in NewArray
  4479.         If IsProblemAngle%(angle) Then
  4480.             ' get array rotated to angle-1
  4481.             ShearRotate arrMask(), arrNext(), angle - 1, iEmpty
  4482.  
  4483.             ' copy to mask array
  4484.             iIndex = arrMaskIndex(angle - 1)
  4485.             For x = LBound(arrNext, 1) To UBound(arrNext, 1)
  4486.                 For y = LBound(arrNext, 2) To UBound(arrNext, 2)
  4487.                     NewArray(iIndex, x, y).c = arrNext(x, y, 0).c
  4488.                     NewArray(iIndex, x, y).origx = arrNext(x, y, 0).origx
  4489.                     NewArray(iIndex, x, y).origy = arrNext(x, y, 0).origy
  4490.                 Next y
  4491.             Next x
  4492.  
  4493.             ' get array rotated to angle
  4494.             ShearRotate arrMask(), arrNext(), angle, iEmpty
  4495.  
  4496.             ' copy to mask array
  4497.             iIndex = arrMaskIndex(angle)
  4498.             For x = LBound(arrNext, 1) To UBound(arrNext, 1)
  4499.                 For y = LBound(arrNext, 2) To UBound(arrNext, 2)
  4500.                     NewArray(iIndex, x, y).c = arrNext(x, y, 0).c
  4501.                     NewArray(iIndex, x, y).origx = arrNext(x, y, 0).origx
  4502.                     NewArray(iIndex, x, y).origy = arrNext(x, y, 0).origy
  4503.                 Next y
  4504.             Next x
  4505.  
  4506.             ' get array rotated to angle+1
  4507.             ShearRotate arrMask(), arrNext(), angle + 1, iEmpty
  4508.  
  4509.             ' copy to mask array
  4510.             iIndex = arrMaskIndex(angle + 1)
  4511.             For x = LBound(arrNext, 1) To UBound(arrNext, 1)
  4512.                 For y = LBound(arrNext, 2) To UBound(arrNext, 2)
  4513.                     NewArray(iIndex, x, y).c = arrNext(x, y, 0).c
  4514.                     NewArray(iIndex, x, y).origx = arrNext(x, y, 0).origx
  4515.                     NewArray(iIndex, x, y).origy = arrNext(x, y, 0).origy
  4516.                 Next y
  4517.             Next x
  4518.  
  4519.         End If
  4520.     Next angle
  4521.  
  4522. End Sub ' GetRotationMasks
  4523.  
  4524. ' /////////////////////////////////////////////////////////////////////////////
  4525. ' Returns an array 0 to 360
  4526. ' that returns the index of the mask array for the given angle
  4527. ' for looking up the mask for a given angle in the mask array
  4528. ' (a value 0 means no entry exists in the mask array)
  4529.  
  4530. ' The values that matter are:
  4531. ' arrMaskIndex( 29) = 1
  4532. ' arrMaskIndex( 30) = 2
  4533. ' arrMaskIndex( 31) = 3
  4534. ' arrMaskIndex( 59) = 4
  4535. ' arrMaskIndex( 60) = 5
  4536. ' arrMaskIndex( 61) = 6
  4537. ' arrMaskIndex(119) = 7
  4538. ' arrMaskIndex(120) = 8
  4539. ' arrMaskIndex(121) = 9
  4540. ' arrMaskIndex(149) = 10
  4541. ' arrMaskIndex(150) = 11
  4542. ' arrMaskIndex(151) = 12
  4543. ' arrMaskIndex(209) = 13
  4544. ' arrMaskIndex(210) = 14
  4545. ' arrMaskIndex(211) = 15
  4546. ' arrMaskIndex(239) = 16
  4547. ' arrMaskIndex(240) = 17
  4548. ' arrMaskIndex(241) = 18
  4549. ' arrMaskIndex(299) = 19
  4550. ' arrMaskIndex(300) = 20
  4551. ' arrMaskIndex(301) = 21
  4552. ' arrMaskIndex(329) = 22
  4553. ' arrMaskIndex(330) = 23
  4554. ' arrMaskIndex(331) = 24
  4555.  
  4556. Sub GetMaskIndex (arrMaskIndex() As Integer)
  4557.     Dim iLoop%
  4558.     Dim iCount%
  4559.     ReDim arrMaskIndex(0 To 360) As Integer
  4560.  
  4561.     iCount% = -1
  4562.  
  4563.     For iLoop% = 0 To 360
  4564.         arrMaskIndex(iLoop%) = 0
  4565.     Next iLoop%
  4566.  
  4567.     For iLoop% = 0 To 359 Step 30
  4568.         If iLoop% Mod 90 <> 0 Then
  4569.             iCount% = iCount% + 3
  4570.             arrMaskIndex(iLoop% - 1) = iCount% - 1
  4571.             arrMaskIndex(iLoop% + 0) = iCount% + 0
  4572.             arrMaskIndex(iLoop% + 1) = iCount% + 1
  4573.         End If
  4574.     Next iLoop%
  4575. End Sub ' GetMaskIndex
  4576.  
  4577. ' /////////////////////////////////////////////////////////////////////////////
  4578.  
  4579. Sub GetMaskIndexTest
  4580.     Dim in$
  4581.     Dim iLoop%
  4582.     ReDim arrMaskIndex(-1) As Integer
  4583.  
  4584.     'Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  4585.     'Width 80, 80
  4586.  
  4587.     Print "Testing GetMaskIndex"
  4588.     GetMaskIndex arrMaskIndex()
  4589.     Print
  4590.     Print "GetMaskIndex arrMaskIndex()"
  4591.     Print "    LBound(arrMaskIndex) = " + cstr$(LBound(arrmaskindex))
  4592.     Print "    UBound(arrMaskIndex) = " + cstr$(UBound(arrmaskindex))
  4593.     Print
  4594.  
  4595.     Print "Testing problem angles:"
  4596.  
  4597.     For iLoop% = 0 To 360
  4598.         If IsProblemAngle%(iLoop%) Then
  4599.             If iLoop% - 1 >= LBound(arrmaskindex) And iLoop% + 1 <= UBound(arrmaskindex) Then
  4600.                 Print "   angle-1, arrMaskIndex(" + cstr$(iLoop% - 1) + ") = " + cstr$(arrMaskIndex(iLoop% - 1))
  4601.                 Print "   angle  , arrMaskIndex(" + cstr$(iLoop% + 0) + ") = " + cstr$(arrMaskIndex(iLoop% + 0))
  4602.                 Print "   angle+1, arrMaskIndex(" + cstr$(iLoop% + 1) + ") = " + cstr$(arrMaskIndex(iLoop% + 1))
  4603.                 Print
  4604.             Else
  4605.                 Print "   angle " + cstr$(iLoop%) + "is  out of range."
  4606.                 Print
  4607.             End If
  4608.         End If
  4609.     Next iLoop%
  4610.  
  4611.     Input "PRESS <ENTER> TO CONTINUE"; in$
  4612. End Sub ' GetMaskIndexTest
  4613.  
  4614. ' /////////////////////////////////////////////////////////////////////////////
  4615.  
  4616. Function TestSprite1$
  4617.     Dim m$
  4618.     m$ = ""
  4619.     '                   11111111112222222222333
  4620.     '          12345678901234567890123456789012
  4621.     m$ = m$ + "11111111111111111111111111111111" + Chr$(13) ' 1
  4622.     m$ = m$ + "4..............................2" + Chr$(13) ' 2
  4623.     m$ = m$ + "4....##.....#######.....####...2" + Chr$(13) ' 3
  4624.     m$ = m$ + "4...####....##...###...######..2" + Chr$(13) ' 4
  4625.     m$ = m$ + "4..##..##...##...###..##....##.2" + Chr$(13) ' 5
  4626.     m$ = m$ + "4.##....##..#######...##.......2" + Chr$(13) ' 6
  4627.     m$ = m$ + "4.########..#######...##.......2" + Chr$(13) ' 7
  4628.     m$ = m$ + "4.########..##...###..##....##.2" + Chr$(13) ' 8
  4629.     m$ = m$ + "4.##....##..##...###...######..2" + Chr$(13) ' 9
  4630.     m$ = m$ + "4.##....##..#######.....####...2" + Chr$(13) ' 10
  4631.     m$ = m$ + "4..............................2" + Chr$(13) ' 11
  4632.     m$ = m$ + "4..............................2" + Chr$(13) ' 12
  4633.     m$ = m$ + "4..ABBBBBBBBBBBBBBBBBBBBBBBBC..2" + Chr$(13) ' 13
  4634.     m$ = m$ + "4..A...........EE...........C..2" + Chr$(13) ' 14
  4635.     m$ = m$ + "4..A..........FFFF..........C..2" + Chr$(13) ' 15
  4636.     m$ = m$ + "4..A.........GGGGGG.........C..2" + Chr$(13) ' 16
  4637.     m$ = m$ + "4..A........HHHHHHHH........C..2" + Chr$(13) ' 17
  4638.     m$ = m$ + "4..A.......IIIIIIIIII.......C..2" + Chr$(13) ' 18
  4639.     m$ = m$ + "4..A......JJJJJJJJJJJJ......C..2" + Chr$(13) ' 19
  4640.     m$ = m$ + "4..DDDDDDDDDDDDDDDDDDDDDDDDDC..2" + Chr$(13) ' 20
  4641.     m$ = m$ + "4..............................2" + Chr$(13) ' 21
  4642.     m$ = m$ + "4..............................2" + Chr$(13) ' 22
  4643.     m$ = m$ + "4.######....########..########.2" + Chr$(13) ' 23
  4644.     m$ = m$ + "4.#######...########..########.2" + Chr$(13) ' 24
  4645.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 25
  4646.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 26
  4647.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 27
  4648.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 28
  4649.     m$ = m$ + "4.#######...##........##.......2" + Chr$(13) ' 29
  4650.     m$ = m$ + "4.######....########..##.......2" + Chr$(13) ' 30
  4651.     m$ = m$ + "4..............................2" + Chr$(13) ' 31
  4652.     m$ = m$ + "33333333333333333333333333333332" + Chr$(13) ' 32
  4653.     TestSprite1$ = m$
  4654. End Function ' TestSprite1$
  4655.  
  4656. ' /////////////////////////////////////////////////////////////////////////////
  4657.  
  4658. Function TestSprite2$
  4659.     Dim m$
  4660.     m$ = ""
  4661.     '                   11111111112222222222333
  4662.     '          12345678901234567890123456789012
  4663.     m$ = m$ + "...............AA..............." + Chr$(13) ' 1
  4664.     m$ = m$ + "..............//BB.............." + Chr$(13) ' 2
  4665.     m$ = m$ + ".............??..CC............." + Chr$(13) ' 3
  4666.     m$ = m$ + "............==....DD............" + Chr$(13) ' 4
  4667.     m$ = m$ + "...........++......EE..........." + Chr$(13) ' 5
  4668.     m$ = m$ + "..........&&........FF.........." + Chr$(13) ' 6
  4669.     m$ = m$ + ".........zz..........GG........." + Chr$(13) ' 7
  4670.     m$ = m$ + "........yy............HH........" + Chr$(13) ' 8
  4671.     m$ = m$ + ".......xx..............II......." + Chr$(13) ' 9
  4672.     m$ = m$ + "......ww................JJ......" + Chr$(13) ' 10
  4673.     m$ = m$ + ".....vv..................KK....." + Chr$(13) ' 11
  4674.     m$ = m$ + "....uu....................LL...." + Chr$(13) ' 12
  4675.     m$ = m$ + "...tt......DDAAAAAAA.......MM..." + Chr$(13) ' 13
  4676.     m$ = m$ + "..ss.......DDAAAAAAA........NN.." + Chr$(13) ' 14
  4677.     m$ = m$ + ".rr........DD.....BB.........OO." + Chr$(13) ' 15
  4678.     m$ = m$ + "qq.........DD.....BB..........PP" + Chr$(13) ' 16
  4679.     m$ = m$ + "pp.........DD.....BB..........QQ" + Chr$(13) ' 17
  4680.     m$ = m$ + ".oo........DD.....BB.........RR." + Chr$(13) ' 18
  4681.     m$ = m$ + "..nn.......CCCCCCCBB........SS.." + Chr$(13) ' 19
  4682.     m$ = m$ + "...mm......CCCCCCCBB.......TT..." + Chr$(13) ' 20
  4683.     m$ = m$ + "....ll....................UU...." + Chr$(13) ' 21
  4684.     m$ = m$ + ".....kk..................VV....." + Chr$(13) ' 22
  4685.     m$ = m$ + "......jj................WW......" + Chr$(13) ' 23
  4686.     m$ = m$ + ".......ii..............XX......." + Chr$(13) ' 24
  4687.     m$ = m$ + "........hh............YY........" + Chr$(13) ' 25
  4688.     m$ = m$ + ".........gg..........ZZ........." + Chr$(13) ' 26
  4689.     m$ = m$ + "..........ff........@@.........." + Chr$(13) ' 27
  4690.     m$ = m$ + "...........ee......##..........." + Chr$(13) ' 28
  4691.     m$ = m$ + "............dd....$$............" + Chr$(13) ' 29
  4692.     m$ = m$ + ".............cc..%%............." + Chr$(13) ' 30
  4693.     m$ = m$ + "..............bb\\.............." + Chr$(13) ' 31
  4694.     m$ = m$ + "...............aa..............." + Chr$(13) ' 32
  4695.     TestSprite2$ = m$
  4696. End Function ' TestSprite2$
  4697.  
  4698. ' /////////////////////////////////////////////////////////////////////////////
  4699.  
  4700. Function PetrText1$
  4701.     Dim m$
  4702.     m$ = ""
  4703.     '                   11111111112222222222333
  4704.     '          12345678901234567890123456789012
  4705.     m$ = m$ + "................................" + Chr$(13) ' 1
  4706.     m$ = m$ + "................................" + Chr$(13) ' 2
  4707.     m$ = m$ + "................................" + Chr$(13) ' 3
  4708.     m$ = m$ + "................................" + Chr$(13) ' 4
  4709.     m$ = m$ + "................................" + Chr$(13) ' 5
  4710.     m$ = m$ + "................................" + Chr$(13) ' 6
  4711.     m$ = m$ + "................................" + Chr$(13) ' 7
  4712.     m$ = m$ + "................................" + Chr$(13) ' 8
  4713.     m$ = m$ + "................................" + Chr$(13) ' 9
  4714.     m$ = m$ + "................................" + Chr$(13) ' 10
  4715.     m$ = m$ + "................................" + Chr$(13) ' 11
  4716.     m$ = m$ + "................................" + Chr$(13) ' 12
  4717.     m$ = m$ + "................................" + Chr$(13) ' 13
  4718.     m$ = m$ + "................................" + Chr$(13) ' 14
  4719.     m$ = m$ + "....It's a SCREEN resolution?..." + Chr$(13) ' 15
  4720.     m$ = m$ + "................................" + Chr$(13) ' 16
  4721.     m$ = m$ + "................................" + Chr$(13) ' 17
  4722.     m$ = m$ + "................................" + Chr$(13) ' 18
  4723.     m$ = m$ + "................................" + Chr$(13) ' 19
  4724.     m$ = m$ + "................................" + Chr$(13) ' 20
  4725.     m$ = m$ + "................................" + Chr$(13) ' 21
  4726.     m$ = m$ + "................................" + Chr$(13) ' 22
  4727.     m$ = m$ + "................................" + Chr$(13) ' 23
  4728.     m$ = m$ + "................................" + Chr$(13) ' 24
  4729.     m$ = m$ + "................................" + Chr$(13) ' 25
  4730.     m$ = m$ + "................................" + Chr$(13) ' 26
  4731.     m$ = m$ + "................................" + Chr$(13) ' 27
  4732.     m$ = m$ + "................................" + Chr$(13) ' 28
  4733.     m$ = m$ + "................................" + Chr$(13) ' 29
  4734.     m$ = m$ + "................................" + Chr$(13) ' 30
  4735.     m$ = m$ + "................................" + Chr$(13) ' 31
  4736.     m$ = m$ + "................................" + Chr$(13) ' 32
  4737.     PetrText1$ = m$
  4738. End Function ' PetrText1$
  4739.  
  4740. ' /////////////////////////////////////////////////////////////////////////////
  4741.  
  4742. Function ArrayToString$ (MyArray( 1 To 32 , 1 To 32) As String)
  4743.     Dim MyString As String
  4744.     Dim iY As Integer
  4745.     Dim iX As Integer
  4746.     Dim sLine As String
  4747.     MyString = ""
  4748.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  4749.         sLine = ""
  4750.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  4751.             sLine = sLine + MyArray(iY, iX)
  4752.         Next iX
  4753.         MyString = MyString + sLine + Chr$(13)
  4754.     Next iY
  4755.     ArrayToString$ = MyString
  4756. End Function ' ArrayToString$
  4757.  
  4758. ' /////////////////////////////////////////////////////////////////////////////
  4759.  
  4760. Function ArrayToStringTest$ (MyArray() As String)
  4761.     Dim MyString As String
  4762.     Dim iY As Integer
  4763.     Dim iX As Integer
  4764.     Dim sLine As String
  4765.     MyString = ""
  4766.  
  4767.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  4768.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  4769.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  4770.         sLine = ""
  4771.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  4772.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  4773.             sLine = sLine + MyArray(iY, iX)
  4774.         Next iX
  4775.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  4776.         MyString = MyString + sLine + Chr$(13)
  4777.     Next iY
  4778.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  4779.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  4780.     ArrayToStringTest$ = MyString
  4781. End Function ' ArrayToStringTest$
  4782.  
  4783. ' /////////////////////////////////////////////////////////////////////////////
  4784.  
  4785. Function RotationArrayToStringTest$ (RoArray() As RotationType)
  4786.     Dim MyString As String
  4787.     Dim iY As Integer
  4788.     Dim iX As Integer
  4789.     Dim sLine As String
  4790.     MyString = ""
  4791.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  4792.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  4793.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  4794.     For iY = LBound(RoArray, 1) To UBound(RoArray, 1)
  4795.         sLine = ""
  4796.         sLine = sLine + Right$("    " + cstr$(iY), 3)
  4797.         For iX = LBound(RoArray, 2) To UBound(RoArray, 2)
  4798.             sLine = sLine + Chr$(RoArray(iX, iY, 0).c)
  4799.         Next iX
  4800.         sLine = sLine + Right$("   " + cstr$(iY), 3)
  4801.         MyString = MyString + sLine + Chr$(13)
  4802.     Next iY
  4803.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  4804.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  4805.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  4806.     RotationArrayToStringTest$ = MyString
  4807. End Function ' RotationArrayToStringTest$
  4808.  
  4809. ' /////////////////////////////////////////////////////////////////////////////
  4810. ' 1. split string by line breaks CHR$(13)
  4811. ' 2. split lines up to 1 column per char
  4812. ' 3. count rows, columns
  4813. ' 4. DIM array, making sure array has
  4814. '    a) an _ODD_ number of rows/columns, with a center point
  4815. '    b) index is in cartesian format, where center is (0,0)
  4816. ' 5. populate array with contents of string
  4817.  
  4818. ' dimension #1 = columns
  4819. ' dimension #2 = rows
  4820.  
  4821. Sub StringToRotationArray (RoArray() As RotationType, MyString As String, EmptyChar As String)
  4822.     Dim RoutineName As String: RoutineName = "StringToRotationArray"
  4823.     ReDim arrLines$(0)
  4824.     Dim delim$
  4825.     Dim iRow%
  4826.     Dim iCol%
  4827.     Dim sChar$
  4828.     Dim iColCount As Integer
  4829.     Dim iRowCount As Integer
  4830.     Dim iCount As Integer
  4831.     Dim bAddedRow As Integer: bAddedRow = FALSE
  4832.     Dim bAddedColumn As Integer: bAddedColumn = FALSE
  4833.     Dim iHalf1 As Integer
  4834.     Dim iHalf2 As Integer
  4835.     Dim iFrom1 As Integer
  4836.     Dim iFrom2 As Integer
  4837.     Dim iTo1 As Integer
  4838.     Dim iTo2 As Integer
  4839.     Dim iEmpty As Integer
  4840.     Dim iX As Integer
  4841.     Dim iY As Integer
  4842.  
  4843.     delim$ = Chr$(13)
  4844.     split MyString, delim$, arrLines$()
  4845.  
  4846.     iRowCount = UBound(arrLines$) + 1
  4847.  
  4848.     ' look at all the rows and find the max # of columns used
  4849.     iColCount = 0
  4850.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4851.  
  4852.         ' count the columns for this row
  4853.         iCount = 0
  4854.         For iCol% = 1 To Len(arrLines$(iRow%))
  4855.             iCount = iCount + 1
  4856.         Next iCol%
  4857.  
  4858.         ' if this row has the most so far, then set that to the max
  4859.         If iCount > iColCount Then
  4860.             iColCount = iCount
  4861.         End If
  4862.     Next iRow%
  4863.  
  4864.     ' adjust columns to be odd
  4865.     If IsEven%(iColCount) Then
  4866.         iColCount = iColCount + 1
  4867.         bAddedColumn = TRUE
  4868.     End If
  4869.  
  4870.     ' calculate array bounds for columns
  4871.     iHalf1 = (iColCount - 1) / 2
  4872.     iFrom1 = 0 - iHalf1
  4873.     iTo1 = iHalf1
  4874.  
  4875.     ' adjust rows to be odd
  4876.     If IsEven%(iRowCount) Then
  4877.         iRowCount = iRowCount + 1
  4878.         bAddedRow = TRUE
  4879.     End If
  4880.  
  4881.     ' calculate array bounds for rows
  4882.     iHalf2 = (iRowCount - 1) / 2
  4883.     iFrom2 = 0 - iHalf2
  4884.     iTo2 = iHalf2
  4885.  
  4886.     ' size array to new bounds
  4887.     ReDim RoArray(iFrom1 To iTo1, iFrom2 To iTo2, 127) As RotationType
  4888.  
  4889.     ' get value for empty
  4890.     If Len(EmptyChar) > 0 Then
  4891.         iEmpty = Asc(EmptyChar)
  4892.     Else
  4893.         iEmpty = 32 ' (use space as default)
  4894.     End If
  4895.  
  4896.     ' clear array
  4897.     For iY = LBound(RoArray, 2) To UBound(RoArray, 2)
  4898.         For iX = LBound(RoArray, 1) To UBound(RoArray, 1)
  4899.             RoArray(iX, iY, 0).c = iEmpty
  4900.             RoArray(iX, iY, 0).origx = iX
  4901.             RoArray(iX, iY, 0).origy = iY
  4902.         Next iX
  4903.     Next iY
  4904.  
  4905.     ' fill array
  4906.     iY = LBound(RoArray, 2) - 1
  4907.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4908.         iY = iY + 1
  4909.         iX = LBound(RoArray, 1) - 1
  4910.         For iCol% = 1 To Len(arrLines$(iRow%))
  4911.             iX = iX + 1
  4912.             sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  4913.             RoArray(iX, iY, 0).c = Asc(sChar$)
  4914.         Next iCol%
  4915.     Next iRow%
  4916.  
  4917. End Sub ' StringToRotationArray
  4918.  
  4919. ' /////////////////////////////////////////////////////////////////////////////
  4920.  
  4921. Sub StringToArray (MyArray() As String, MyString As String)
  4922.     Dim delim$
  4923.     ReDim arrLines$(0)
  4924.     Dim iRow%
  4925.     Dim iCol%
  4926.     Dim sChar$
  4927.     Dim iDim1 As Integer
  4928.     Dim iDim2 As Integer
  4929.     iDim1 = LBound(MyArray, 1)
  4930.     iDim2 = LBound(MyArray, 2)
  4931.     delim$ = Chr$(13)
  4932.     split MyString, delim$, arrLines$()
  4933.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  4934.         If iRow% <= UBound(MyArray, 2) Then
  4935.             For iCol% = 1 To Len(arrLines$(iRow%))
  4936.                 If iCol% <= UBound(MyArray, 1) Then
  4937.                     sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  4938.  
  4939.                     If Len(sChar$) > 1 Then
  4940.                         sChar$ = Left$(sChar$, 1)
  4941.                     Else
  4942.                         If Len(sChar$) = 0 Then
  4943.                             sChar$ = "."
  4944.                         End If
  4945.                     End If
  4946.                     MyArray(iRow% + iDim1, (iCol% - 1) + iDim2) = sChar$
  4947.                 Else
  4948.                     ' Exit if out of bounds
  4949.                     Exit For
  4950.                 End If
  4951.             Next iCol%
  4952.         Else
  4953.             ' Exit if out of bounds
  4954.             Exit For
  4955.         End If
  4956.     Next iRow%
  4957. End Sub ' StringToArray
  4958.  
  4959. ' /////////////////////////////////////////////////////////////////////////////
  4960.  
  4961. 'SUB ClearArray (MyArray(1 To 32, 1 To 32) AS STRING, MyString As String)
  4962. Sub ClearArray (MyArray() As String, MyString As String)
  4963.     Dim iRow As Integer
  4964.     Dim iCol As Integer
  4965.     Dim sChar$
  4966.     If Len(MyString) = 1 Then
  4967.         sChar$ = MyString
  4968.     Else
  4969.         If Len(MyString) = 0 Then
  4970.             sChar$ = " "
  4971.         Else
  4972.             sChar$ = Left$(MyString, 1)
  4973.         End If
  4974.     End If
  4975.     For iRow = LBound(MyArray, 1) To UBound(MyArray, 1)
  4976.         For iCol = LBound(MyArray, 2) To UBound(MyArray, 2)
  4977.             MyArray(iRow, iCol) = sChar$
  4978.         Next iCol
  4979.     Next iRow
  4980. End Sub ' ClearArray
  4981.  
  4982. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4983. ' BEGIN GENERAL PURPOSE ROUTINES
  4984. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4985.  
  4986. ' /////////////////////////////////////////////////////////////////////////////
  4987.  
  4988. Function cstr$ (myValue)
  4989.     'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
  4990.     cstr$ = _Trim$(Str$(myValue))
  4991. End Function ' cstr$
  4992.  
  4993. ' /////////////////////////////////////////////////////////////////////////////
  4994.  
  4995. Function cstrl$ (myValue As Long)
  4996.     cstrl$ = _Trim$(Str$(myValue))
  4997. End Function ' cstrl$
  4998.  
  4999. ' /////////////////////////////////////////////////////////////////////////////
  5000.  
  5001. Function TrueFalse$ (myValue)
  5002.     If myValue = TRUE Then
  5003.         TrueFalse$ = "TRUE"
  5004.     Else
  5005.         TrueFalse$ = "FALSE"
  5006.     End If
  5007. End Function ' TrueFalse$
  5008.  
  5009. ' /////////////////////////////////////////////////////////////////////////////
  5010.  
  5011. Function IIF (Condition, IfTrue, IfFalse)
  5012.     If Condition Then IIF = IfTrue Else IIF = IfFalse
  5013.  
  5014. ' /////////////////////////////////////////////////////////////////////////////
  5015.  
  5016. Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
  5017.     If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
  5018.  
  5019. ' /////////////////////////////////////////////////////////////////////////////
  5020. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  5021.  
  5022. Function IsEven% (n)
  5023.     If n Mod 2 = 0 Then
  5024.         IsEven% = TRUE
  5025.     Else
  5026.         IsEven% = FALSE
  5027.     End If
  5028. End Function ' IsEven%
  5029.  
  5030. ' /////////////////////////////////////////////////////////////////////////////
  5031. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  5032.  
  5033. Function IsOdd% (n)
  5034.     If n Mod 2 = 1 Then
  5035.         IsOdd% = TRUE
  5036.     Else
  5037.         IsOdd% = FALSE
  5038.     End If
  5039. End Function ' IsOdd%
  5040.  
  5041. ' /////////////////////////////////////////////////////////////////////////////
  5042. ' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0
  5043.  
  5044. Function IsNum% (text$)
  5045.     Dim a$
  5046.     Dim b$
  5047.     a$ = _Trim$(text$)
  5048.     b$ = _Trim$(Str$(Val(text$)))
  5049.     If a$ = b$ Then
  5050.         IsNum% = TRUE
  5051.     Else
  5052.         IsNum% = FALSE
  5053.     End If
  5054. End Function ' IsNum%
  5055.  
  5056. ' /////////////////////////////////////////////////////////////////////////////
  5057. ' Split and join strings
  5058. ' https://www.qb64.org/forum/index.php?topic=1073.0
  5059.  
  5060. 'Combine all elements of in$() into a single string with delimiter$ separating the elements.
  5061.  
  5062. Function join$ (in$(), delimiter$)
  5063.     result$ = in$(LBound(in$))
  5064.     For i = LBound(in$) + 1 To UBound(in$)
  5065.         result$ = result$ + delimiter$ + in$(i)
  5066.     Next i
  5067.     join$ = result$
  5068. End Function ' join$
  5069.  
  5070. ' /////////////////////////////////////////////////////////////////////////////
  5071. ' FROM: String Manipulation
  5072. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index_topic_5964-0/
  5073. '
  5074. 'SUMMARY:
  5075. '   Purpose:  A library of custom functions that transform strings.
  5076. '   Author:   Dustinian Camburides (dustinian@gmail.com)
  5077. '   Platform: QB64 (www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there])
  5078. '   Revision: 1.6
  5079. '   Updated:  5/28/2012
  5080.  
  5081. 'SUMMARY:
  5082. '[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
  5083. 'INPUT:
  5084. 'Text: The input string; the text that's being manipulated.
  5085. 'Find: The specified sub-string; the string sought within the [Text] string.
  5086. 'Add: The sub-string that's being added to the [Text] string.
  5087.  
  5088. Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
  5089.     ' VARIABLES:
  5090.     Dim Text2 As String
  5091.     Dim Find2 As String
  5092.     Dim Add2 As String
  5093.     Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
  5094.     Dim strBefore As String ' The characters before the string to be replaced.
  5095.     Dim strAfter As String ' The characters after the string to be replaced.
  5096.  
  5097.     ' INITIALIZE:
  5098.     ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
  5099.     Text2 = Text1
  5100.     Find2 = Find1
  5101.     Add2 = Add1
  5102.  
  5103.     lngLocation = InStr(1, Text2, Find2)
  5104.  
  5105.     ' PROCESSING:
  5106.     ' While [Find2] appears in [Text2]...
  5107.     While lngLocation
  5108.         ' Extract all Text2 before the [Find2] substring:
  5109.         strBefore = Left$(Text2, lngLocation - 1)
  5110.  
  5111.         ' Extract all text after the [Find2] substring:
  5112.         strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
  5113.  
  5114.         ' Return the substring:
  5115.         Text2 = strBefore + Add2 + strAfter
  5116.  
  5117.         ' Locate the next instance of [Find2]:
  5118.         lngLocation = InStr(1, Text2, Find2)
  5119.  
  5120.         ' Next instance of [Find2]...
  5121.     Wend
  5122.  
  5123.     ' OUTPUT:
  5124.     Replace$ = Text2
  5125. End Function ' Replace$
  5126.  
  5127. ' /////////////////////////////////////////////////////////////////////////////
  5128. ' Split and join strings
  5129. ' https://www.qb64.org/forum/index.php?topic=1073.0
  5130. '
  5131. ' FROM luke, QB64 Developer
  5132. ' Date: February 15, 2019, 04:11:07 AM
  5133. '
  5134. ' Given a string of words separated by spaces (or any other character),
  5135. ' splits it into an array of the words. I've no doubt many people have
  5136. ' written a version of this over the years and no doubt there's a million
  5137. ' ways to do it, but I thought I'd put mine here so we have at least one
  5138. ' version. There's also a join function that does the opposite
  5139. ' array -> single string.
  5140. '
  5141. ' Code is hopefully reasonably self explanatory with comments and a little demo.
  5142. ' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.
  5143.  
  5144. 'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
  5145. 'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
  5146. '
  5147. 'delimiter$ must be one character long.
  5148. 'result$() must have been REDIMmed previously.
  5149.  
  5150. Sub split (in$, delimiter$, result$())
  5151.     ReDim result$(-1)
  5152.     start = 1
  5153.     Do
  5154.         While Mid$(in$, start, 1) = delimiter$
  5155.             start = start + 1
  5156.             If start > Len(in$) Then Exit Sub
  5157.         Wend
  5158.         finish = InStr(start, in$, delimiter$)
  5159.         If finish = 0 Then finish = Len(in$) + 1
  5160.         ReDim _Preserve result$(0 To UBound(result$) + 1)
  5161.         result$(UBound(result$)) = Mid$(in$, start, finish - start)
  5162.         start = finish + 1
  5163.     Loop While start <= Len(in$)
  5164. End Sub ' split
  5165.  
  5166. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5167. ' END GENERAL PURPOSE ROUTINES
  5168. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  5169.  
  5170. ' #END
  5171. ' ################################################################################################################################################################
  5172.  

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
SheerRotate4 vs SheerRotate6:

29 degrees (same for all versions):
  [ You are not allowed to view this attachment ]  

30 degrees with SheerRotate4:
  [ You are not allowed to view this attachment ]  

30 degrees with SheerRotate6:
  [ You are not allowed to view this attachment ]  

31 degrees (same for all versions):
  [ You are not allowed to view this attachment ]