QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: madscijr on December 20, 2021, 06:33:02 pm

Title: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 20, 2021, 06:33:02 pm
I've been playing with some basic 2D raster drawing / plotting / manipulation routines (operating on a 2-D array).

For rotating a 2-D sprite array to an arbitrary angle, I found a 3-shear rotation routine that works after some massaging, but am seeing this issue where the quality drops when rotating to multiples of 30 degrees (specifically 30, 60, 120, 150, 210, 240, 300, and 330 degrees are the sour spots, 90, 180, & 270 are OK).

If anyone has a minute, run the program and try option 5 or 6, and notice how it looks when it gets to any of those angles.

To quickly find the rotation logic, search for "Sub ShearRotate".

What gives? Any help much appreciated...

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. ' -----------------------------------------------------------------------------
  18. ' USER DEFINED TYPES
  19. ' -----------------------------------------------------------------------------
  20. Type RotationType
  21.     origx As Integer
  22.     origy As Integer
  23.     'z as integer
  24.     c As Integer
  25. End Type ' RotationType
  26.  
  27. ' -----------------------------------------------------------------------------
  28. ' GLOBAL VARIABLES
  29. ' -----------------------------------------------------------------------------
  30. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  31. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  32. Dim Shared m_bDebug: m_bDebug = FALSE
  33.  
  34. ' =============================================================================
  35. ' BEGIN MAIN PROGRAM
  36. ' =============================================================================
  37. Dim in$
  38.  
  39. ' ****************************************************************************************************************************************************************
  40. ' ACTIVATE DEBUGGING WINDOW
  41. If m_bDebug = TRUE Then
  42.     $Console
  43.     _Delay 4
  44.     _Console On
  45.     _Echo "Started " + m_ProgramName$
  46.     _Echo "Debugging on..."
  47. ' ****************************************************************************************************************************************************************
  48.  
  49. ' -----------------------------------------------------------------------------
  50. ' START THE MENU
  51. main
  52.  
  53. ' -----------------------------------------------------------------------------
  54. ' DONE
  55. Print m_ProgramName$ + " finished."
  56. 'Screen 0
  57. Input "Press <ENTER> to continue", in$
  58.  
  59. ' ****************************************************************************************************************************************************************
  60. ' DEACTIVATE DEBUGGING WINDOW
  61. If m_bDebug = TRUE Then
  62. ' ****************************************************************************************************************************************************************
  63.  
  64. ' -----------------------------------------------------------------------------
  65. ' EXIT
  66. System ' return control to the operating system
  67.  
  68. ' =============================================================================
  69. ' END MAIN PROGRAM
  70. ' =============================================================================
  71.  
  72. ' /////////////////////////////////////////////////////////////////////////////
  73. ' MAIN MENU
  74.  
  75. Sub main
  76.     Dim RoutineName As String: RoutineName = "main"
  77.     Dim in$
  78.  
  79.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  80.     Do
  81.         Cls
  82.         Print m_ProgramName$
  83.         Print
  84.         Print "Some basic 2D plotting"
  85.         Print
  86.         Print "1. PlotPointTest"
  87.         Print "2. PlotSquareTest"
  88.         Print "3. PlotCircleTest"
  89.         Print "4. PlotLineTest"
  90.         Print "5. ShearRotateTest1"
  91.         Print "6. ShearRotateTest2"
  92.         Print
  93.         Print "What to do? ('q' to exit)"
  94.  
  95.         Input in$: in$ = LCase$(Left$(in$, 1))
  96.  
  97.         If in$ = "1" Then
  98.             PlotPointTest
  99.         ElseIf in$ = "2" Then
  100.             PlotSquareTest
  101.         ElseIf in$ = "3" Then
  102.             PlotCircleTest
  103.         ElseIf in$ = "4" Then
  104.             PlotLineTest
  105.         ElseIf in$ = "5" Then
  106.             ShearRotateTest1
  107.         ElseIf in$ = "6" Then
  108.             ShearRotateTest2
  109.         End If
  110.     Loop Until in$ = "q"
  111. End Sub ' main
  112.  
  113. ' /////////////////////////////////////////////////////////////////////////////
  114. ' MyArray(1 To 32, 1 To 32) AS STRING
  115.  
  116. Sub PlotPoint (X As Integer, Y As Integer, S As String, MyArray() As String)
  117.     If (X >= LBound(MyArray, 2)) Then
  118.         If (X <= UBound(MyArray, 2)) Then
  119.             If (Y >= LBound(MyArray, 1)) Then
  120.                 If (Y <= UBound(MyArray, 1)) Then
  121.                     If Len(S) = 1 Then
  122.                         MyArray(Y, X) = S
  123.                     Else
  124.                         If Len(S) > 1 Then
  125.                             MyArray(Y, X) = Left$(S, 1)
  126.                         End If
  127.                     End If
  128.                 End If
  129.             End If
  130.         End If
  131.     End If
  132. End Sub ' PlotPoint
  133.  
  134. ' /////////////////////////////////////////////////////////////////////////////
  135.  
  136. Sub PlotPointTest
  137.     Dim MyArray(1 To 32, 1 To 32) As String
  138.     Dim iX As Integer
  139.     Dim iY As Integer
  140.     Dim in$
  141.     Dim X As Integer
  142.     Dim Y As Integer
  143.     Dim L As Integer
  144.     Dim iChar As Integer
  145.  
  146.     ClearArray MyArray(), "."
  147.     iChar = 64
  148.  
  149.     Cls
  150.     Print "Plot a point."
  151.     Print ArrayToStringTest(MyArray())
  152.     Print
  153.  
  154.     Do
  155.         Print "Type x,y (1-32, 1-32) coordinate to plot point at."
  156.         Input "X,Y OR 0 TO QUIT? "; X, Y
  157.         If X > 0 And Y > 0 Then
  158.             iChar = iChar + 1
  159.             If iChar > 90 Then iChar = 65
  160.  
  161.             Print "X=" + cstr$(X) + ", Y=" + cstr$(Y)
  162.             PlotPoint X, Y, Chr$(iChar), MyArray()
  163.  
  164.             Print "Current point plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  165.             Print ArrayToStringTest(MyArray())
  166.             Print
  167.  
  168.         Else
  169.             Exit Do
  170.         End If
  171.     Loop
  172. End Sub ' PlotPointTest
  173.  
  174. ' /////////////////////////////////////////////////////////////////////////////
  175.  
  176. Sub PlotSquare (X1 As Integer, Y1 As Integer, L As Integer, S As String, MyArray() As String)
  177.     Dim X As Integer
  178.     Dim X2 As Integer
  179.     Dim Y As Integer
  180.     Dim Y2 As Integer
  181.     Dim sChar$
  182.  
  183.     If Len(S) = 1 Then
  184.         sChar$ = S
  185.     Else
  186.         If Len(S) = 0 Then
  187.             sChar$ = " "
  188.         Else
  189.             sChar$ = Left$(S, 1)
  190.         End If
  191.     End If
  192.  
  193.     X2 = (X1 + L) - 1
  194.     Y2 = (Y1 + L) - 1
  195.     For X = X1 To X2
  196.         For Y = Y1 To Y2
  197.             PlotPoint X, Y, sChar$, MyArray()
  198.         Next Y
  199.     Next X
  200. End Sub ' PlotSquare
  201.  
  202. ' /////////////////////////////////////////////////////////////////////////////
  203.  
  204. Sub PlotSquareTest
  205.     Dim MyArray(1 To 32, 1 To 32) As String
  206.     Dim iX As Integer
  207.     Dim iY As Integer
  208.     Dim in$
  209.     Dim X As Integer
  210.     Dim Y As Integer
  211.     Dim L As Integer
  212.     Dim iChar As Integer
  213.  
  214.     ClearArray MyArray(), "."
  215.     iChar = 64
  216.  
  217.     Cls
  218.     Print "Enter parameters to draw a square."
  219.     Print ArrayToStringTest(MyArray())
  220.     Print
  221.     Do
  222.         Print "Type top left x,y (1-32, 1-32) coordinate to plot square,"
  223.         Print "and size (1-32) of square."
  224.         Input "X,Y,L OR 0 TO QUIT? "; X, Y, L
  225.         If X > 0 And Y > 0 And L > 0 Then
  226.             iChar = iChar + 1
  227.             If iChar > 90 Then iChar = 65
  228.  
  229.             Print
  230.             Print "X=" + cstr$(X)
  231.             Print "Y=" + cstr$(Y)
  232.             Print "L=" + cstr$(L)
  233.             Print
  234.             PlotSquare X, Y, L, Chr$(iChar), MyArray()
  235.  
  236.             Print "Square plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  237.             Print ArrayToStringTest(MyArray())
  238.             Print
  239.         Else
  240.             Exit Do
  241.         End If
  242.     Loop
  243. End Sub ' PlotSquareTest
  244.  
  245. ' /////////////////////////////////////////////////////////////////////////////
  246. ' Fast circle drawing in pure Atari BASIC#
  247. ' https://atariwiki.org/wiki/Wiki.jsp?page=Super%20fast%20circle%20routine
  248.  
  249. ' * Magazine: Moj Mikro, 1989/3
  250. ' * Author : Zlatko Bleha
  251. ' * Page : 27 - 31
  252. ' * Atari BASIC listing on disk (tokenized): M8903282.BAS
  253. ' * Atari BASIC listing (listed): M8903282.LST
  254.  
  255. ' Next example is demonstration of implementing mentioned circle algorithm
  256. ' in pure Atari BASIC. This program shows how much faster it is compared to
  257. ' classic program using sine and cosine functions from Atari BASIC
  258. ' (shown in last example).
  259.  
  260. ' Basic Listing M8903282.LST#
  261. '1 REM *******************************
  262. '2 REM PROGRAM  : FAST CIRCLE DRAWING
  263. '3 REM AUTHOR   : ZLATKO BLEHA
  264. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  265. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  266. '6 REM *******************************
  267. '7 REM
  268. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  269. '20 PRINT "ENTER X, Y AND R"
  270. '30 INPUT X,Y,R
  271. '40 IF R=0 THEN PLOT X,Y:END
  272. '50 B=R:C=0:A=R-1
  273. '60 PLOT X+C,Y+B
  274. '70 PLOT X+C,Y-B
  275. '80 PLOT X-C,Y-B
  276. '90 PLOT X-C,Y+B
  277. '100 PLOT X+B,Y+C
  278. '110 PLOT X+B,Y-C
  279. '120 PLOT X-B,Y-C
  280. '130 PLOT X-B,Y+C
  281. '140 C=C+1
  282. '150 A=A+1-C-C
  283. '160 IF A>=0 THEN 190
  284. '170 B=B-1
  285. '180 A=A+B+B
  286. '190 IF B>=C THEN 60
  287.  
  288. ' Use some valid values for coordinates and radius, for example:
  289. ' X=40, Y=40, R=30
  290. ' X=130, Y=90, R=60
  291. ' Slow circle drawing in Atari BASIC#
  292. ' * Magazine: Moj Mikro, 1989/3
  293. ' * Author : Zlatko Bleha
  294. ' * Page : 27 - 31
  295. ' * Atari BASIC listing on disk (tokenized): M8903281.BAS
  296. ' * Atari BASIC listing (listed): M8903281.LST
  297.  
  298. ' This is classic example for drawing circles from Atari BASIC
  299. ' using sine and cosine functions. Unfortunatelly, this is very slow
  300. ' way of doing it and not recommended.
  301. ' Just use routine shown above and everybody will be happy
  302.  
  303. ' Basic Listing M8903281.LST#
  304. '1 REM *******************************
  305. '2 REM PROGRAM  : SLOW CIRCLE DRAWING
  306. '3 REM AUTHOR   : ZLATKO BLEHA
  307. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  308. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  309. '6 REM *******************************
  310. '7 REM
  311. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  312. '20 FOR A=0 TO 6.28 STEP 0.02
  313. '30 X=SIN(A)*50+150
  314. '40 Y=COS(A)*50+80
  315. '50 PLOT X,Y
  316. '60 NEXT A
  317.  
  318. ' Conclusion#
  319. ' Returning back to first program with the fastest way of drawing circles...
  320. ' There is one more thing to note. In case you want to use PLOT subroutine,
  321. ' which is part of the main circle routine, then read following explanation.
  322. ' PLOT routine is written so it can be used easily from Atari BASIC program
  323. ' independently from main circle routine, by using like this:
  324. ' A=USR(30179,POK,X,Y)
  325. '
  326. ' POK   1 (drawing a pixel), 0 (erasing a pixel)
  327. ' X     X coordinate of the pixel
  328. ' Y     Y coordinate of the pixel
  329. '
  330. ' The routine alone is not any faster than normal PLOT command
  331. ' from Atari BASIC, because USR command takes approximately 75%
  332. ' of whole execution. But, used as part of the main circle routine
  333. ' it does not matter anymore, because it is integrated in one larger
  334. ' entity. There the execution is very fast, with no overhead.
  335. ' PLOT routine is here for you to examine anyway.
  336. ' You never know if you will maybe need it in the future.
  337.  
  338. ' More on plotting circles:
  339. '     Drawing a circle in BASIC - fast
  340. '     https://www.cpcwiki.eu/forum/programming/drawing-a-circle-in-basic-fast/
  341.  
  342. ' X,Y     = center point of circle
  343. ' R       = radius
  344. ' S       = char to draw
  345. ' MyArray = 2D string array to plot circle in
  346.  
  347. Sub PlotCircle (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  348.     Dim A As Integer
  349.     Dim B As Integer
  350.     Dim C As Integer
  351.     Dim S2 As String
  352.  
  353.     If Len(S) = 1 Then
  354.         S2 = S
  355.     Else
  356.         If Len(S) = 0 Then
  357.             S2 = " "
  358.         Else
  359.             S2 = Left$(S, 1)
  360.         End If
  361.     End If
  362.  
  363.     If R > 0 Then
  364.         B = R
  365.         C = 0
  366.         A = R - 1
  367.         Do
  368.             PlotPoint X + C, Y + B, S2, MyArray()
  369.             PlotPoint X + C, Y - B, S2, MyArray()
  370.             PlotPoint X - C, Y - B, S2, MyArray()
  371.             PlotPoint X - C, Y + B, S2, MyArray()
  372.             PlotPoint X + B, Y + C, S2, MyArray()
  373.             PlotPoint X + B, Y - C, S2, MyArray()
  374.             PlotPoint X - B, Y - C, S2, MyArray()
  375.             PlotPoint X - B, Y + C, S2, MyArray()
  376.             C = C + 1
  377.             A = A + 1 - C - C
  378.             If A < 0 Then ' IF A>=0 THEN 190
  379.                 B = B - 1
  380.                 A = A + B + B
  381.             End If
  382.             If B < C Then Exit Do ' 190 IF B>=C THEN 60
  383.         Loop
  384.     End If
  385. End Sub ' PlotCircle
  386.  
  387. ' /////////////////////////////////////////////////////////////////////////////
  388.  
  389. Sub PlotCircleTest
  390.     Dim MyArray(1 To 32, 1 To 32) As String
  391.     Dim iX As Integer
  392.     Dim iY As Integer
  393.     Dim in$
  394.     Dim X As Integer
  395.     Dim Y As Integer
  396.     Dim R As Integer
  397.     Dim iChar As Integer
  398.  
  399.     ClearArray MyArray(), "."
  400.     iChar = 64
  401.  
  402.     Cls
  403.     Print "Plot a raster circle"
  404.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  405.     Print
  406.     Print "Enter parameters to draw a circle."
  407.     Print ArrayToStringTest(MyArray())
  408.     Print
  409.  
  410.     Do
  411.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  412.         Print "and radius (1-32) of circle."
  413.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  414.         If X > 0 And Y > 0 And R > 0 Then
  415.             iChar = iChar + 1
  416.             If iChar > 90 Then iChar = 65
  417.  
  418.             Print "X=" + cstr$(X)
  419.             Print "Y=" + cstr$(Y)
  420.             Print "R=" + cstr$(R)
  421.  
  422.             PlotCircle X, Y, R, Chr$(iChar), MyArray()
  423.  
  424.             Print "Circle plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  425.             Print ArrayToStringTest(MyArray())
  426.             Print
  427.         Else
  428.             Exit Do
  429.         End If
  430.     Loop
  431.  
  432. End Sub ' PlotCircleTest
  433.  
  434. ' /////////////////////////////////////////////////////////////////////////////
  435. ' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
  436. ' From: http://www.thedubber.altervista.org/qbsrc.htm
  437.  
  438. Sub PlotLine (x1%, y1%, x2%, y2%, c$, MyArray() As String)
  439.     Dim iLoop%
  440.     Dim steep%: steep% = 0
  441.     Dim ev%: ev% = 0
  442.     Dim sx%
  443.     Dim sy%
  444.     Dim dx%
  445.     Dim dy%
  446.  
  447.     If (x2% - x1%) > 0 Then
  448.         sx% = 1
  449.     Else
  450.         sx% = -1
  451.     End If
  452.  
  453.     dx% = Abs(x2% - x1%)
  454.     If (y2% - y1%) > 0 Then
  455.         sy% = 1
  456.     Else
  457.         sy% = -1
  458.     End If
  459.  
  460.     dy% = Abs(y2% - y1%)
  461.     If (dy% > dx%) Then
  462.         steep% = 1
  463.         Swap x1%, y1%
  464.         Swap dx%, dy%
  465.         Swap sx%, sy%
  466.     End If
  467.  
  468.     ev% = 2 * dy% - dx%
  469.     For iLoop% = 0 To dx% - 1
  470.         If steep% = 1 Then
  471.             ''PSET (y1%, x1%), c%:
  472.             'LOCATE y1%, x1%
  473.             'PRINT c$;
  474.             PlotPoint y1%, x1%, c$, MyArray()
  475.         Else
  476.             ''PSET (x1%, y1%), c%
  477.             'LOCATE x1%, y1%
  478.             'PRINT c$;
  479.             PlotPoint x1%, y1%, c$, MyArray()
  480.         End If
  481.  
  482.         While ev% >= 0
  483.             y1% = y1% + sy%
  484.             ev% = ev% - 2 * dx%
  485.         Wend
  486.         x1% = x1% + sx%
  487.         ev% = ev% + 2 * dy%
  488.     Next iLoop%
  489.     ''PSET (x2%, y2%), c%
  490.     'LOCATE x2%, y2%
  491.     'PRINT c$;
  492.     PlotPoint x2%, y2%, c$, MyArray()
  493. End Sub ' PlotLine
  494.  
  495. ' /////////////////////////////////////////////////////////////////////////////
  496.  
  497. Sub PlotLineTest
  498.     Dim MyArray(1 To 32, 1 To 32) As String
  499.     Dim in$
  500.     Dim X1 As Integer
  501.     Dim Y1 As Integer
  502.     Dim X2 As Integer
  503.     Dim Y2 As Integer
  504.     Dim iChar As Integer
  505.  
  506.     ClearArray MyArray(), "."
  507.     iChar = 64
  508.  
  509.     Cls
  510.     Print "Plot line with Bresenham Algorithm"
  511.     Print "based on BRESNHAM.BAS by Kurt Kuzba (4/16/96)."
  512.     Print
  513.     Print ArrayToStringTest(MyArray())
  514.     Do
  515.         Print "Enter coordinate values for "
  516.         Print "line start point x1, y1 (1-32, 1-32)"
  517.         Print "line end   point x2, y2 (1-32, 1-32)"
  518.         Input "ENTER X1,Y1,X2,Y2 OR 0 TO QUIT: "; X1, Y1, X2, Y2
  519.         If X1 > 0 And Y1 > 0 And X2 > 0 And Y2 > 0 Then
  520.             iChar = iChar + 1
  521.             If iChar > 90 Then iChar = 65
  522.  
  523.             Print "X1=" + cstr$(X1)
  524.             Print "Y1=" + cstr$(Y1)
  525.             Print "X2=" + cstr$(X2)
  526.             Print "Y2=" + cstr$(Y2)
  527.  
  528.             PlotLine X1, Y1, X2, Y2, Chr$(iChar), MyArray()
  529.  
  530.             Print "Line plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  531.             Print ArrayToStringTest(MyArray())
  532.  
  533.         Else
  534.             Exit Do
  535.         End If
  536.     Loop
  537. End Sub ' PlotLineTest
  538.  
  539. ' /////////////////////////////////////////////////////////////////////////////
  540. ' 3 shear method testing
  541.  
  542. ' _PUT Rotation Help
  543. ' https://www.qb64.org/forum/index.php?topic=1959.0
  544.  
  545. ' 3 Shear Rotation - rotates without any aliasing(holes)
  546. ' https://www.freebasic.net/forum/viewtopic.php?t=24557
  547.  
  548. ' From: leopardpm
  549. ' Date: Apr 02, 2016 1:21
  550. ' Last edited by leopardpm on Apr 02, 2016 17:18, edited 1 time in total.
  551. '
  552. ' This is just a little 3-shear rotation routine
  553. ' (I am using 3-shear because it leaves no gaps/aliasing)
  554. ' that I was wondering if anyone sees how to make it faster.
  555. ' Obviously, I am just thinking about inside the double loop.
  556.  
  557. ' Thanks again to BasicCoder2 for linking me to this little routine, it is wonderful so far!
  558.  
  559. '''                      roto-zooming algorithm
  560. '''                    coded by Michael S. Nissen
  561. '''                        jernmager@yahoo.dk
  562. '
  563. ''' ===============================================================
  564. ''' Recoded to run on FBC 32/64 bit WIN, Version 1.05.0, 2016, by MrSwiss
  565. ''' Heavy flickering before going Full-Screen on 64 Bit !!!
  566. ''' This seems NOT to be the Case on 32 Bit ...
  567. ''' ===============================================================
  568. '
  569. 'Type Pixel
  570. '  As Single   X, Y
  571. '  As ULong    C
  572. 'End Type
  573. '
  574. '''  dim vars
  575. 'Dim shared as Any Ptr Img_Buffer
  576. '''  write the name of the .bmp image you want to rotozoom here:
  577. '''  (it has to be sqare ie. 100x100 pixels, 760x760 pixels or whatever)
  578. 'Dim As String Img_Name = "phobos.bmp"
  579. 'Dim shared as Integer X_Mid, Y_Mid, scrn_wid, scrn_hgt, P1, P2, P3, P4, C
  580. 'Dim shared as Short Img_Hgt, Img_Wid, Img_Lft, Img_Rgt, Img_Top, Img_Btm, X, Y
  581. 'Dim Shared As Single Cos_Ang, Sin_Ang, Rot_Fac_X, Rot_Fac_Y, Angle = 0, Scale = 1
  582. '
  583. ''' changed Function to Sub (+ recoded arguments list)
  584. 'Sub Calc_rotozoom ( ByRef Cos_Ang As Single, _
  585. '               ByRef Sin_Ang As Single, _
  586. '               ByVal S_Fact  As Single, _
  587. '               ByVal NewAng  As Single )
  588. '  Cos_Ang = Cos(NewAng)*S_Fact
  589. '  Sin_Ang = Sin(NewAng)*S_Fact
  590. 'End Sub
  591. '
  592. '''  full screen
  593. 'ScreenInfo scrn_wid, scrn_hgt
  594. 'screenRes scrn_wid, scrn_hgt, 32,,1
  595. '
  596. '''  dim screenpointer (has to be done after screenres)
  597. 'Dim As ULong Ptr Scrn_Ptr = Screenptr
  598. '
  599. '''  place image in center of screen
  600. 'X_Mid = scrn_wid\2
  601. 'Y_Mid = scrn_hgt\2
  602. 'Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  603. '
  604. '''  find image dimensions
  605. 'Open Img_Name For Binary As #1
  606. 'Get #1, 19, Img_Wid
  607. 'Get #1, 23, Img_Hgt
  608. 'Close #1
  609. '
  610. '''  prepare to dim the array that will hold the image.
  611. 'Img_Rgt = (Img_Wid-1)\2
  612. 'Img_Lft = -Img_Rgt
  613. 'Img_Btm = (Img_Hgt-1)\2
  614. 'Img_Top = -Img_Btm
  615. '
  616. '''  dim array to hold image. Note: pixel (0, 0) is in the center.
  617. 'Dim As Pixel Pixel(Img_Lft to Img_Rgt, Img_Top to Img_Btm)
  618. '
  619. '''  imagecreate sprite and load image to sprite
  620. 'Img_Buffer = ImageCreate (Img_Wid, Img_Hgt)
  621. 'Bload (Img_Name, Img_Buffer)
  622. '
  623. '''  load image from sprite to array with point command
  624. 'For Y = Img_Top to Img_Btm
  625. '  For X = Img_Lft to Img_Rgt
  626. '    With Pixel(X, Y)
  627. '      .X = X_Mid+X
  628. '      .Y = Y_Mid+Y
  629. '      C = Point (X-Img_Top, Y-Img_Lft, Img_buffer)
  630. '      If C <> RGB(255, 0, 255) Then
  631. '        .C = C
  632. '      Else
  633. '        .C = RGB(0, 0, 0)
  634. '      End If
  635. '    End With
  636. '  Next X
  637. 'Next Y
  638. '
  639. '''  we don't need the sprite anymore, kill it
  640. 'ImageDestroy Img_Buffer
  641. 'Img_Buffer = 0
  642. '
  643. '''  main program loop
  644. 'Do
  645. '
  646. '  ''  scale in/out with uparrow/downarrow
  647. '  If Multikey(80) Then
  648. '    Scale *= 1.03
  649. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  650. '  ElseIf Multikey(72) Then
  651. '    Scale *= 0.97
  652. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  653. '  End If
  654. '
  655. '  ''  rotate left/right with leftarrow/rightarrow
  656. '  If Multikey(77) Then
  657. '    Angle -= 0.03
  658. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  659. '  ElseIf Multikey(75) Then
  660. '    Angle += 0.03
  661. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  662. '  End If
  663. '
  664. '  ''  lock screen in order to use screen pointers
  665. '  ScreenLock
  666. '
  667. '    ''  draw pixel in center of image
  668. '    Scrn_Ptr[ X_Mid + Y_Mid * scrn_wid ] = Pixel(0, 0).C
  669. '    ''  draw all other pixels - 4 at a time
  670. '    For Y = Img_Top to 0
  671. '      For X = Img_Lft to -1
  672. '        ''  find pixel positions
  673. '        P1 = (X_Mid+X) + (Y_Mid+Y) * scrn_wid
  674. '        P2 = (X_Mid-X) + (Y_Mid-Y) * scrn_wid
  675. '        P3 = (X_Mid+Y) + (Y_Mid-X) * scrn_wid
  676. '        P4 = (X_Mid-Y) + (Y_Mid+X) * scrn_wid
  677. '        ''  erase old pixels (paint them black)
  678. '        Scrn_Ptr[P1] = 0
  679. '        Scrn_Ptr[P2] = 0
  680. '        Scrn_Ptr[P3] = 0
  681. '        Scrn_Ptr[P4] = 0
  682. '        ''  rotate and zoom
  683. '        Rot_Fac_X = X*Cos_Ang - Y*Sin_Ang
  684. '        Rot_Fac_Y = X*Sin_Ang + Y*Cos_Ang
  685. '        If Rot_Fac_X < Img_Lft Or Rot_Fac_X > Img_Rgt Then Continue For
  686. '        If Rot_Fac_Y < Img_Top Or Rot_Fac_Y > Img_Btm Then Continue For
  687. '        ''  draw new pixels
  688. '        Scrn_Ptr[P1] = Pixel(Rot_Fac_X, Rot_Fac_Y).C
  689. '        Scrn_Ptr[P2] = Pixel(-Rot_Fac_X, -Rot_Fac_Y).C
  690. '        Scrn_Ptr[P3] = Pixel(Rot_Fac_Y, -Rot_Fac_X).C
  691. '        Scrn_Ptr[P4] = Pixel(-Rot_Fac_Y, Rot_Fac_X).C
  692. '      Next X
  693. '    Next Y
  694. '
  695. '  ScreenUnLock
  696. '
  697. '  Sleep 10, 1
  698. 'Loop Until InKey() = Chr(27)
  699.  
  700. ' UPDATES:
  701. ' Fixed bug where values 135, 224, and 314 all resolve to -45 degrees.
  702. ' Fixed bug where an angle of 46-135 degrees caused the image to be flipped wrong.
  703.  
  704. ' TODO:
  705. ' Fix issue where image looks bad at 30, 60, 120, 150, 210, 240, 300, 330 degrees
  706.  
  707. Sub ShearRotate (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  708.     Const Pi = 4 * Atn(1)
  709.  
  710.     Dim angle As Integer
  711.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  712.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  713.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  714.     Dim x As Integer
  715.     Dim y As Integer
  716.     Dim nangle As Integer
  717.     Dim nx As Integer
  718.     Dim ny As Integer
  719.     Dim flipper As Integer
  720.     Dim rotr As Double
  721.     Dim shear1 As Double
  722.     Dim shear2 As Double
  723.     Dim clr As Integer
  724.     Dim y1 As _Byte
  725.     Dim xy1 As _Byte
  726.     Dim fy As _Byte
  727.     Dim fx As _Byte
  728.     Dim in$
  729.     Dim sLine As String
  730.  
  731.     ' initialize new with empty
  732.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  733.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  734.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  735.             NewArray(x, y, 0).origx = x
  736.             NewArray(x, y, 0).origy = y
  737.             NewArray(x, y, 0).c = iEmpty
  738.         Next y
  739.     Next x
  740.  
  741.     ' angle is reversed
  742.     angle = 360 - angle1
  743.  
  744.     ' Shearing each element 3 times in one shot
  745.     nangle = angle
  746.  
  747.     ' this pre-processing portion basically rotates by 90 to get
  748.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  749.     If angle > 45 And angle < 225 Then
  750.         If angle < 135 Then
  751.             nangle = angle - 90
  752.         Else
  753.             nangle = angle - 180
  754.         End If
  755.     End If
  756.     If angle > 135 And angle < 315 Then
  757.         If angle < 225 Then
  758.             nangle = angle - 180
  759.         Else
  760.             nangle = angle - 270
  761.         End If
  762.     End If
  763.     If nangle < 0 Then
  764.         nangle = nangle + 360
  765.     End If
  766.     If nangle > 359 Then
  767.         nangle = nangle - 360
  768.     End If
  769.  
  770.     rotr = nangle * DtoR
  771.     shear1 = Tan(rotr / 2) ' correct way
  772.     shear2 = Sin(rotr)
  773.  
  774.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  775.     ' ***       all resolve to -45 degrees.
  776.     ' ***       Fixed by changing < to <=
  777.  
  778.     'if angle >  45 and angle < 134 then
  779.     If angle > 45 And angle <= 134 Then
  780.         flipper = 1
  781.     ElseIf angle > 134 And angle <= 224 Then
  782.         flipper = 2
  783.     ElseIf angle > 224 And angle <= 314 Then
  784.         ' *** NOTE: this had a bug where this flipper was wrong
  785.         '           Fixed by adding case 7
  786.         'flipper = 3
  787.         flipper = 7
  788.     Else
  789.         flipper = 0
  790.     End If
  791.  
  792.     ' Here is where it needs some optimizing possibly... kinda slow...
  793.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  794.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  795.             Select Case flipper
  796.                 Case 1:
  797.                     nx = -y
  798.                     ny = x
  799.                 Case 2:
  800.                     nx = -x
  801.                     ny = -y
  802.                 Case 3:
  803.                     nx = -y
  804.                     ny = -x
  805.                 Case 4:
  806.                     nx = -x
  807.                     ny = y
  808.                 Case 5:
  809.                     nx = x
  810.                     ny = -y
  811.                 Case 6:
  812.                     nx = y
  813.                     ny = x
  814.                 Case 7:
  815.                     nx = y
  816.                     ny = -x
  817.                 Case Else:
  818.                     nx = x
  819.                     ny = y
  820.             End Select
  821.  
  822.             clr = OldArray(nx, ny, 0).c
  823.  
  824.             y1 = y * shear1
  825.             xy1 = x + y1
  826.             fy = (y - xy1 * shear2)
  827.             fx = xy1 + fy * shear1
  828.  
  829.             If fx >= -16 And fx <= 16 Then
  830.                 If fy >= -16 And fy <= 16 Then
  831.                     NewArray(fx, fy, 0).c = clr
  832.                     NewArray(fx, fy, 0).origx = fx
  833.                     NewArray(fx, fy, 0).origy = fy
  834.                 End If
  835.             End If
  836.         Next x
  837.     Next y
  838. End Sub ' ShearRotate
  839.  
  840. ' /////////////////////////////////////////////////////////////////////////////
  841.  
  842. Sub ShearRotateTest1
  843.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  844.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  845.     Dim sMap As String
  846.     Dim D As Integer
  847.     Dim in$
  848.  
  849.     ' GET A SHAPE TO BE ROTATED
  850.     Cls
  851.     Print "3 shear rotation based on code by leopardpm"
  852.     Print
  853.  
  854.     sMap = TestSprite1$
  855.  
  856.     ' CONVERT SHAPE TO ARRAY
  857.     StringToRotationArray RoArray1(), sMap, "."
  858.     Print "Initial contents of Rotation Array:"
  859.     Print RotationArrayToStringTest(RoArray1())
  860.     Print
  861.  
  862.     ' ROTATE THE SHAPE
  863.     Do
  864.         Print "Type degrees to rotate (0 TO 360) or non-numeric value to quit."
  865.         Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  866.  
  867.         Input "Degrees to rotate (q to quit)? "; in$
  868.         If IsNum%(in$) Then
  869.             D = Val(in$)
  870.             If D >= 0 And D <= 360 Then
  871.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  872.                 Print
  873.                 Print "Rotated by " + cstr$(D) + " degrees:"
  874.                 Print RotationArrayToStringTest(RoArray2())
  875.                 Print
  876.             Else
  877.                 Exit Do
  878.             End If
  879.         Else
  880.             Exit Do
  881.         End If
  882.     Loop
  883. End Sub ' ShearRotateTest1
  884.  
  885. ' /////////////////////////////////////////////////////////////////////////////
  886.  
  887. Sub ShearRotateTest2
  888.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  889.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  890.     Dim sMap As String
  891.     Dim D As Integer
  892.     Dim D1 As Integer
  893.     Dim in$
  894.     Dim bFinished As Integer
  895.  
  896.     ' GET A SHAPE TO BE ROTATED
  897.     Cls
  898.     Print "3 shear rotation based on code by leopardpm"
  899.     sMap = TestSprite1$
  900.  
  901.     ' CONVERT SHAPE TO ARRAY
  902.     StringToRotationArray RoArray1(), sMap, "."
  903.  
  904.     ' GET START ANGLE
  905.     D = 0
  906.     Print
  907.     Print "Rotated by " + cstr$(D) + " degrees:"
  908.     Print RotationArrayToStringTest(RoArray1())
  909.     Print
  910.     Print "Type an angle (-360 to 360) to rotate to, "
  911.     Print "or blank to increase by 1 degree, or q to quit."
  912.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  913.     Print "Hold down <ENTER> to rotate continually."
  914.     Input "Angle (q to quit)? ", in$
  915.     If Len(in$) > 0 Then
  916.         If IsNum%(in$) Then
  917.             D1 = Val(in$)
  918.         Else
  919.             D1 = -500
  920.         End If
  921.     Else
  922.         D1 = 1
  923.     End If
  924.  
  925.     ' ROTATE TO EACH ANGLE
  926.     If D1 >= -360 And D1 <= 360 Then
  927.         bFinished = FALSE
  928.         Do
  929.             ' ROTATE CLOCKWISE
  930.             For D = D1 To 360
  931.                 Cls
  932.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  933.                 Print
  934.                 Print "Rotated by " + cstr$(D) + " degrees:"
  935.                 Print RotationArrayToStringTest(RoArray2())
  936.                 Print
  937.  
  938.                 Print "Type an angle (-360 to 360) to rotate to, "
  939.                 Print "or blank to increase by 1 degree, or q to quit."
  940.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  941.                 Print "Hold down <ENTER> to rotate continually."
  942.                 Input "Angle (q to quit)? ", in$
  943.                 If Len(in$) > 0 Then
  944.                     If IsNum%(in$) Then
  945.                         D = Val(in$)
  946.                         If D >= 0 And D <= 360 Then
  947.                             D = D - 1
  948.                         Else
  949.                             bFinished = TRUE
  950.                             Exit For
  951.                         End If
  952.                     Else
  953.                         bFinished = TRUE
  954.                         Exit For
  955.                     End If
  956.                 End If
  957.             Next D
  958.             If bFinished = TRUE Then Exit Do
  959.  
  960.             ' ROTATE COUNTER-CLOCKWISE
  961.             For D = 360 To D1 Step -1
  962.                 Cls
  963.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  964.                 Print
  965.                 Print "Rotated by " + cstr$(D) + " degrees:"
  966.  
  967.                 Print RotationArrayToStringTest(RoArray2())
  968.                 Print
  969.  
  970.                 Print "Type an angle (0 to 360) to rotate to, "
  971.                 Print "or blank to increase by 1 degree, or q to quit."
  972.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  973.                 Print "Hold down <ENTER> to rotate continually."
  974.                 Input "Angle (q to quit)? ", in$
  975.                 If Len(in$) > 0 Then
  976.                     If IsNum%(in$) Then
  977.                         D = Val(in$)
  978.                         If D >= 0 And D <= 360 Then
  979.                             D = D + 1
  980.                         Else
  981.                             bFinished = TRUE
  982.                             Exit For
  983.                         End If
  984.                     Else
  985.                         bFinished = TRUE
  986.                         Exit For
  987.                     End If
  988.                 End If
  989.             Next D
  990.             If bFinished = TRUE Then Exit Do
  991.         Loop
  992.     End If
  993. End Sub ' ShearRotateTest2
  994.  
  995. ' /////////////////////////////////////////////////////////////////////////////
  996.  
  997. Function TestSprite1$
  998.     Dim m$
  999.     m$ = ""
  1000.     '                   11111111112222222222333
  1001.     '          12345678901234567890123456789012
  1002.     m$ = m$ + "11111111111111111111111111111111" + Chr$(13) ' 1
  1003.     m$ = m$ + "4..............................2" + Chr$(13) ' 2
  1004.     m$ = m$ + "4....##.....#######.....####...2" + Chr$(13) ' 3
  1005.     m$ = m$ + "4...####....##...###...######..2" + Chr$(13) ' 4
  1006.     m$ = m$ + "4..##..##...##...###..##....##.2" + Chr$(13) ' 5
  1007.     m$ = m$ + "4.##....##..#######...##.......2" + Chr$(13) ' 6
  1008.     m$ = m$ + "4.########..#######...##.......2" + Chr$(13) ' 7
  1009.     m$ = m$ + "4.########..##...###..##....##.2" + Chr$(13) ' 8
  1010.     m$ = m$ + "4.##....##..##...###...######..2" + Chr$(13) ' 9
  1011.     m$ = m$ + "4.##....##..#######.....####...2" + Chr$(13) ' 10
  1012.     m$ = m$ + "4..............................2" + Chr$(13) ' 11
  1013.     m$ = m$ + "4..............................2" + Chr$(13) ' 12
  1014.     m$ = m$ + "4..ABBBBBBBBBBBBBBBBBBBBBBBBC..2" + Chr$(13) ' 13
  1015.     m$ = m$ + "4..A...........EE...........C..2" + Chr$(13) ' 14
  1016.     m$ = m$ + "4..A..........FFFF..........C..2" + Chr$(13) ' 15
  1017.     m$ = m$ + "4..A.........GGGGGG.........C..2" + Chr$(13) ' 16
  1018.     m$ = m$ + "4..A........HHHHHHHH........C..2" + Chr$(13) ' 17
  1019.     m$ = m$ + "4..A.......IIIIIIIIII.......C..2" + Chr$(13) ' 18
  1020.     m$ = m$ + "4..A......JJJJJJJJJJJJ......C..2" + Chr$(13) ' 19
  1021.     m$ = m$ + "4..DDDDDDDDDDDDDDDDDDDDDDDDDC..2" + Chr$(13) ' 20
  1022.     m$ = m$ + "4..............................2" + Chr$(13) ' 21
  1023.     m$ = m$ + "4..............................2" + Chr$(13) ' 22
  1024.     m$ = m$ + "4.######....########..########.2" + Chr$(13) ' 23
  1025.     m$ = m$ + "4.#######...########..########.2" + Chr$(13) ' 24
  1026.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 25
  1027.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 26
  1028.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 27
  1029.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 28
  1030.     m$ = m$ + "4.#######...##........##.......2" + Chr$(13) ' 29
  1031.     m$ = m$ + "4.######....########..##.......2" + Chr$(13) ' 30
  1032.     m$ = m$ + "4..............................2" + Chr$(13) ' 31
  1033.     m$ = m$ + "33333333333333333333333333333332" + Chr$(13) ' 32
  1034.     TestSprite1$ = m$
  1035. End Function ' TestSprite1$
  1036.  
  1037. ' /////////////////////////////////////////////////////////////////////////////
  1038.  
  1039. Function TestSprite2$
  1040.     Dim m$
  1041.     m$ = ""
  1042.     '                   11111111112222222222333
  1043.     '          12345678901234567890123456789012
  1044.     m$ = m$ + "...............AA..............." + Chr$(13) ' 1
  1045.     m$ = m$ + "..............//BB.............." + Chr$(13) ' 2
  1046.     m$ = m$ + ".............??..CC............." + Chr$(13) ' 3
  1047.     m$ = m$ + "............==....DD............" + Chr$(13) ' 4
  1048.     m$ = m$ + "...........++......EE..........." + Chr$(13) ' 5
  1049.     m$ = m$ + "..........&&........FF.........." + Chr$(13) ' 6
  1050.     m$ = m$ + ".........zz..........GG........." + Chr$(13) ' 7
  1051.     m$ = m$ + "........yy............HH........" + Chr$(13) ' 8
  1052.     m$ = m$ + ".......xx..............II......." + Chr$(13) ' 9
  1053.     m$ = m$ + "......ww................JJ......" + Chr$(13) ' 10
  1054.     m$ = m$ + ".....vv..................KK....." + Chr$(13) ' 11
  1055.     m$ = m$ + "....uu....................LL...." + Chr$(13) ' 12
  1056.     m$ = m$ + "...tt......DDAAAAAAA.......MM..." + Chr$(13) ' 13
  1057.     m$ = m$ + "..ss.......DDAAAAAAA........NN.." + Chr$(13) ' 14
  1058.     m$ = m$ + ".rr........DD.....BB.........OO." + Chr$(13) ' 15
  1059.     m$ = m$ + "qq.........DD.....BB..........PP" + Chr$(13) ' 16
  1060.     m$ = m$ + "pp.........DD.....BB..........QQ" + Chr$(13) ' 17
  1061.     m$ = m$ + ".oo........DD.....BB.........RR." + Chr$(13) ' 18
  1062.     m$ = m$ + "..nn.......CCCCCCCBB........SS.." + Chr$(13) ' 19
  1063.     m$ = m$ + "...mm......CCCCCCCBB.......TT..." + Chr$(13) ' 20
  1064.     m$ = m$ + "....ll....................UU...." + Chr$(13) ' 21
  1065.     m$ = m$ + ".....kk..................VV....." + Chr$(13) ' 22
  1066.     m$ = m$ + "......jj................WW......" + Chr$(13) ' 23
  1067.     m$ = m$ + ".......ii..............XX......." + Chr$(13) ' 24
  1068.     m$ = m$ + "........hh............YY........" + Chr$(13) ' 25
  1069.     m$ = m$ + ".........gg..........ZZ........." + Chr$(13) ' 26
  1070.     m$ = m$ + "..........ff........@@.........." + Chr$(13) ' 27
  1071.     m$ = m$ + "...........ee......##..........." + Chr$(13) ' 28
  1072.     m$ = m$ + "............dd....$$............" + Chr$(13) ' 29
  1073.     m$ = m$ + ".............cc..%%............." + Chr$(13) ' 30
  1074.     m$ = m$ + "..............bb\\.............." + Chr$(13) ' 31
  1075.     m$ = m$ + "...............aa..............." + Chr$(13) ' 32
  1076.     TestSprite2$ = m$
  1077. End Function ' TestSprite2$
  1078.  
  1079. ' /////////////////////////////////////////////////////////////////////////////
  1080.  
  1081. Function ArrayToString$ (MyArray( 1 To 32 , 1 To 32) As String)
  1082.     Dim MyString As String
  1083.     Dim iY As Integer
  1084.     Dim iX As Integer
  1085.     Dim sLine As String
  1086.     MyString = ""
  1087.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  1088.         sLine = ""
  1089.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  1090.             sLine = sLine + MyArray(iY, iX)
  1091.         Next iX
  1092.         MyString = MyString + sLine + Chr$(13)
  1093.     Next iY
  1094.     ArrayToString$ = MyString
  1095. End Function ' ArrayToString$
  1096.  
  1097. ' /////////////////////////////////////////////////////////////////////////////
  1098.  
  1099. Function ArrayToStringTest$ (MyArray() As String)
  1100.     Dim MyString As String
  1101.     Dim iY As Integer
  1102.     Dim iX As Integer
  1103.     Dim sLine As String
  1104.     MyString = ""
  1105.  
  1106.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  1107.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  1108.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  1109.         sLine = ""
  1110.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  1111.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  1112.             sLine = sLine + MyArray(iY, iX)
  1113.         Next iX
  1114.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  1115.         MyString = MyString + sLine + Chr$(13)
  1116.     Next iY
  1117.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  1118.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  1119.     ArrayToStringTest$ = MyString
  1120. End Function ' ArrayToStringTest$
  1121.  
  1122. ' /////////////////////////////////////////////////////////////////////////////
  1123.  
  1124. Function RotationArrayToStringTest$ (RoArray() As RotationType)
  1125.     Dim MyString As String
  1126.     Dim iY As Integer
  1127.     Dim iX As Integer
  1128.     Dim sLine As String
  1129.     MyString = ""
  1130.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  1131.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  1132.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  1133.     For iY = LBound(RoArray, 1) To UBound(RoArray, 1)
  1134.         sLine = ""
  1135.         sLine = sLine + Right$("    " + cstr$(iY), 3)
  1136.         For iX = LBound(RoArray, 2) To UBound(RoArray, 2)
  1137.             sLine = sLine + Chr$(RoArray(iX, iY, 0).c)
  1138.         Next iX
  1139.         sLine = sLine + Right$("   " + cstr$(iY), 3)
  1140.         MyString = MyString + sLine + Chr$(13)
  1141.     Next iY
  1142.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  1143.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  1144.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  1145.     RotationArrayToStringTest$ = MyString
  1146. End Function ' RotationArrayToStringTest$
  1147.  
  1148. ' /////////////////////////////////////////////////////////////////////////////
  1149. ' 1. split string by line breaks CHR$(13)
  1150. ' 2. split lines up to 1 column per char
  1151. ' 3. count rows, columns
  1152. ' 4. DIM array, making sure array has
  1153. '    a) an _ODD_ number of rows/columns, with a center point
  1154. '    b) index is in cartesian format, where center is (0,0)
  1155. ' 5. populate array with contents of string
  1156.  
  1157. ' dimension #1 = columns
  1158. ' dimension #2 = rows
  1159.  
  1160. Sub StringToRotationArray (RoArray() As RotationType, MyString As String, EmptyChar As String)
  1161.     Dim RoutineName As String: RoutineName = "StringToRotationArray"
  1162.     ReDim arrLines$(0)
  1163.     Dim delim$
  1164.     Dim iRow%
  1165.     Dim iCol%
  1166.     Dim sChar$
  1167.     Dim iColCount As Integer
  1168.     Dim iRowCount As Integer
  1169.     Dim iCount As Integer
  1170.     Dim bAddedRow As Integer: bAddedRow = FALSE
  1171.     Dim bAddedColumn As Integer: bAddedColumn = FALSE
  1172.     Dim iHalf1 As Integer
  1173.     Dim iHalf2 As Integer
  1174.     Dim iFrom1 As Integer
  1175.     Dim iFrom2 As Integer
  1176.     Dim iTo1 As Integer
  1177.     Dim iTo2 As Integer
  1178.     Dim iEmpty As Integer
  1179.     Dim iX As Integer
  1180.     Dim iY As Integer
  1181.  
  1182.     delim$ = Chr$(13)
  1183.     split MyString, delim$, arrLines$()
  1184.  
  1185.     iRowCount = UBound(arrLines$) + 1
  1186.  
  1187.     ' look at all the rows and find the max # of columns used
  1188.     iColCount = 0
  1189.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  1190.  
  1191.         ' count the columns for this row
  1192.         iCount = 0
  1193.         For iCol% = 1 To Len(arrLines$(iRow%))
  1194.             iCount = iCount + 1
  1195.         Next iCol%
  1196.  
  1197.         ' if this row has the most so far, then set that to the max
  1198.         If iCount > iColCount Then
  1199.             iColCount = iCount
  1200.         End If
  1201.     Next iRow%
  1202.  
  1203.     ' adjust columns to be odd
  1204.     If IsEven%(iColCount) Then
  1205.         iColCount = iColCount + 1
  1206.         bAddedColumn = TRUE
  1207.     End If
  1208.  
  1209.     ' calculate array bounds for columns
  1210.     iHalf1 = (iColCount - 1) / 2
  1211.     iFrom1 = 0 - iHalf1
  1212.     iTo1 = iHalf1
  1213.  
  1214.     ' adjust rows to be odd
  1215.     If IsEven%(iRowCount) Then
  1216.         iRowCount = iRowCount + 1
  1217.         bAddedRow = TRUE
  1218.     End If
  1219.  
  1220.     ' calculate array bounds for rows
  1221.     iHalf2 = (iRowCount - 1) / 2
  1222.     iFrom2 = 0 - iHalf2
  1223.     iTo2 = iHalf2
  1224.  
  1225.     ' size array to new bounds
  1226.     ReDim RoArray(iFrom1 To iTo1, iFrom2 To iTo2, 127) As RotationType
  1227.  
  1228.     ' get value for empty
  1229.     If Len(EmptyChar) > 0 Then
  1230.         iEmpty = Asc(EmptyChar)
  1231.     Else
  1232.         iEmpty = 32 ' (use space as default)
  1233.     End If
  1234.  
  1235.     ' clear array
  1236.     For iY = LBound(RoArray, 2) To UBound(RoArray, 2)
  1237.         For iX = LBound(RoArray, 1) To UBound(RoArray, 1)
  1238.             RoArray(iX, iY, 0).c = iEmpty
  1239.             RoArray(iX, iY, 0).origx = iX
  1240.             RoArray(iX, iY, 0).origy = iY
  1241.         Next iX
  1242.     Next iY
  1243.  
  1244.     ' fill array
  1245.     iY = LBound(RoArray, 2) - 1
  1246.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  1247.         iY = iY + 1
  1248.         iX = LBound(RoArray, 1) - 1
  1249.         For iCol% = 1 To Len(arrLines$(iRow%))
  1250.             iX = iX + 1
  1251.             sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  1252.             RoArray(iX, iY, 0).c = Asc(sChar$)
  1253.         Next iCol%
  1254.     Next iRow%
  1255.  
  1256. End Sub ' StringToRotationArray
  1257.  
  1258. ' /////////////////////////////////////////////////////////////////////////////
  1259.  
  1260. Sub StringToArray (MyArray() As String, MyString As String)
  1261.     Dim delim$
  1262.     ReDim arrLines$(0)
  1263.     Dim iRow%
  1264.     Dim iCol%
  1265.     Dim sChar$
  1266.     Dim iDim1 As Integer
  1267.     Dim iDim2 As Integer
  1268.     iDim1 = LBound(MyArray, 1)
  1269.     iDim2 = LBound(MyArray, 2)
  1270.     delim$ = Chr$(13)
  1271.     split MyString, delim$, arrLines$()
  1272.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  1273.         If iRow% <= UBound(MyArray, 2) Then
  1274.             For iCol% = 1 To Len(arrLines$(iRow%))
  1275.                 If iCol% <= UBound(MyArray, 1) Then
  1276.                     sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  1277.  
  1278.                     If Len(sChar$) > 1 Then
  1279.                         sChar$ = Left$(sChar$, 1)
  1280.                     Else
  1281.                         If Len(sChar$) = 0 Then
  1282.                             sChar$ = "."
  1283.                         End If
  1284.                     End If
  1285.                     MyArray(iRow% + iDim1, (iCol% - 1) + iDim2) = sChar$
  1286.                 Else
  1287.                     ' Exit if out of bounds
  1288.                     Exit For
  1289.                 End If
  1290.             Next iCol%
  1291.         Else
  1292.             ' Exit if out of bounds
  1293.             Exit For
  1294.         End If
  1295.     Next iRow%
  1296. End Sub ' StringToArray
  1297.  
  1298. ' /////////////////////////////////////////////////////////////////////////////
  1299.  
  1300. 'SUB ClearArray (MyArray(1 To 32, 1 To 32) AS STRING, MyString As String)
  1301. Sub ClearArray (MyArray() As String, MyString As String)
  1302.     Dim iRow As Integer
  1303.     Dim iCol As Integer
  1304.     Dim sChar$
  1305.     If Len(MyString) = 1 Then
  1306.         sChar$ = MyString
  1307.     Else
  1308.         If Len(MyString) = 0 Then
  1309.             sChar$ = " "
  1310.         Else
  1311.             sChar$ = Left$(MyString, 1)
  1312.         End If
  1313.     End If
  1314.     For iRow = LBound(MyArray, 1) To UBound(MyArray, 1)
  1315.         For iCol = LBound(MyArray, 2) To UBound(MyArray, 2)
  1316.             MyArray(iRow, iCol) = sChar$
  1317.         Next iCol
  1318.     Next iRow
  1319. End Sub ' ClearArray
  1320.  
  1321. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1322. ' BEGIN GENERAL PURPOSE ROUTINES
  1323. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1324.  
  1325. ' /////////////////////////////////////////////////////////////////////////////
  1326.  
  1327. Function cstr$ (myValue)
  1328.     'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
  1329.     cstr$ = _Trim$(Str$(myValue))
  1330. End Function ' cstr$
  1331.  
  1332. Function cstrl$ (myValue As Long)
  1333.     cstrl$ = _Trim$(Str$(myValue))
  1334. End Function ' cstrl$
  1335.  
  1336. ' /////////////////////////////////////////////////////////////////////////////
  1337.  
  1338. Function IIF (Condition, IfTrue, IfFalse)
  1339.     If Condition Then IIF = IfTrue Else IIF = IfFalse
  1340.  
  1341. ' /////////////////////////////////////////////////////////////////////////////
  1342.  
  1343. Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
  1344.     If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
  1345.  
  1346. ' /////////////////////////////////////////////////////////////////////////////
  1347. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  1348.  
  1349. Function IsEven% (n)
  1350.     If n Mod 2 = 0 Then
  1351.         IsEven% = TRUE
  1352.     Else
  1353.         IsEven% = FALSE
  1354.     End If
  1355. End Function ' IsEven%
  1356.  
  1357. ' /////////////////////////////////////////////////////////////////////////////
  1358. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  1359.  
  1360. Function IsOdd% (n)
  1361.     If n Mod 2 = 1 Then
  1362.         IsOdd% = TRUE
  1363.     Else
  1364.         IsOdd% = FALSE
  1365.     End If
  1366. End Function ' IsOdd%
  1367.  
  1368. ' /////////////////////////////////////////////////////////////////////////////
  1369. ' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0
  1370.  
  1371. Function IsNum% (text$)
  1372.     Dim a$
  1373.     Dim b$
  1374.     a$ = _Trim$(text$)
  1375.     b$ = _Trim$(Str$(Val(text$)))
  1376.     If a$ = b$ Then
  1377.         IsNum% = TRUE
  1378.     Else
  1379.         IsNum% = FALSE
  1380.     End If
  1381. End Function ' IsNum%
  1382.  
  1383. ' /////////////////////////////////////////////////////////////////////////////
  1384. ' Split and join strings
  1385. ' https://www.qb64.org/forum/index.php?topic=1073.0
  1386.  
  1387. 'Combine all elements of in$() into a single string with delimiter$ separating the elements.
  1388.  
  1389. Function join$ (in$(), delimiter$)
  1390.     result$ = in$(LBound(in$))
  1391.     For i = LBound(in$) + 1 To UBound(in$)
  1392.         result$ = result$ + delimiter$ + in$(i)
  1393.     Next i
  1394.     join$ = result$
  1395. End Function ' join$
  1396.  
  1397. ' /////////////////////////////////////////////////////////////////////////////
  1398. ' FROM: String Manipulation
  1399. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index_topic_5964-0/
  1400. '
  1401. 'SUMMARY:
  1402. '   Purpose:  A library of custom functions that transform strings.
  1403. '   Author:   Dustinian Camburides (dustinian@gmail.com)
  1404. '   Platform: QB64 (www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there])
  1405. '   Revision: 1.6
  1406. '   Updated:  5/28/2012
  1407.  
  1408. 'SUMMARY:
  1409. '[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
  1410. 'INPUT:
  1411. 'Text: The input string; the text that's being manipulated.
  1412. 'Find: The specified sub-string; the string sought within the [Text] string.
  1413. 'Add: The sub-string that's being added to the [Text] string.
  1414.  
  1415. Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
  1416.     ' VARIABLES:
  1417.     Dim Text2 As String
  1418.     Dim Find2 As String
  1419.     Dim Add2 As String
  1420.     Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
  1421.     Dim strBefore As String ' The characters before the string to be replaced.
  1422.     Dim strAfter As String ' The characters after the string to be replaced.
  1423.  
  1424.     ' INITIALIZE:
  1425.     ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
  1426.     Text2 = Text1
  1427.     Find2 = Find1
  1428.     Add2 = Add1
  1429.  
  1430.     lngLocation = InStr(1, Text2, Find2)
  1431.  
  1432.     ' PROCESSING:
  1433.     ' While [Find2] appears in [Text2]...
  1434.     While lngLocation
  1435.         ' Extract all Text2 before the [Find2] substring:
  1436.         strBefore = Left$(Text2, lngLocation - 1)
  1437.  
  1438.         ' Extract all text after the [Find2] substring:
  1439.         strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
  1440.  
  1441.         ' Return the substring:
  1442.         Text2 = strBefore + Add2 + strAfter
  1443.  
  1444.         ' Locate the next instance of [Find2]:
  1445.         lngLocation = InStr(1, Text2, Find2)
  1446.  
  1447.         ' Next instance of [Find2]...
  1448.     Wend
  1449.  
  1450.     ' OUTPUT:
  1451.     Replace$ = Text2
  1452. End Function ' Replace$
  1453.  
  1454. ' /////////////////////////////////////////////////////////////////////////////
  1455. ' Split and join strings
  1456. ' https://www.qb64.org/forum/index.php?topic=1073.0
  1457. '
  1458. ' FROM luke, QB64 Developer
  1459. ' Date: February 15, 2019, 04:11:07 AM »
  1460. '
  1461. ' Given a string of words separated by spaces (or any other character),
  1462. ' splits it into an array of the words. I've no doubt many people have
  1463. ' written a version of this over the years and no doubt there's a million
  1464. ' ways to do it, but I thought I'd put mine here so we have at least one
  1465. ' version. There's also a join function that does the opposite
  1466. ' array -> single string.
  1467. '
  1468. ' Code is hopefully reasonably self explanatory with comments and a little demo.
  1469. ' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.
  1470.  
  1471. 'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
  1472. 'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
  1473. '
  1474. 'delimiter$ must be one character long.
  1475. 'result$() must have been REDIMmed previously.
  1476.  
  1477. Sub split (in$, delimiter$, result$())
  1478.     ReDim result$(-1)
  1479.     start = 1
  1480.     Do
  1481.         While Mid$(in$, start, 1) = delimiter$
  1482.             start = start + 1
  1483.             If start > Len(in$) Then Exit Sub
  1484.         Wend
  1485.         finish = InStr(start, in$, delimiter$)
  1486.         If finish = 0 Then finish = Len(in$) + 1
  1487.         ReDim _Preserve result$(0 To UBound(result$) + 1)
  1488.         result$(UBound(result$)) = Mid$(in$, start, finish - start)
  1489.         start = finish + 1
  1490.     Loop While start <= Len(in$)
  1491. End Sub ' split
  1492.  
  1493. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1494. ' END GENERAL PURPOSE ROUTINES
  1495. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1496.  
  1497. ' #END
  1498. ' ################################################################################################################################################################
  1499.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: Petr on December 21, 2021, 04:09:35 am
I tried to write text rotation using text commands on a text screen in my own way. It's gratifying that my rendering is as bad as yours. I guess that's the screen resolution. Try to write down the coordinates of individual points and you will see for yourself. They must not be a pair with the same coordinates, but because you rotate in a field (as I understood by a quick look at your program), some characters are printed on top of each other. I am adding a simplified custom version for text rotation. Uncommenting the GoTo command starts the same thing in the graphical design, where it works nicely. What is there otherwise? Coordinate calculation. What is the character ratio - witdht/height in text mode? 1: 1. What is the aspect ratio of the character in graphics mode? For FONT 16 it is 8 pixels wide, 16 pixels high. I guess that's the problem.

Maybe it can really be done better in text mode, if someone can do it, I'll be happy to learn something new.

Code: QB64: [Select]
  1. Screen _NewImage(60, 60, 0) 'text screen 60x60
  2.  
  3. 'TEXT MODE
  4. text$ = "It's a SCREEN resolution?"
  5.  
  6.  
  7. Lenght = Len(text$)
  8.  
  9. Type XY
  10.     X As Integer
  11.     Y As Integer
  12. Dim XY(Lenght) As XY
  13.  
  14. 'GoTo graphic        'uncomment this for view better output
  15.  
  16.     angle = angle + 0.01
  17.     For coordinate = 0 To Lenght
  18.         XY(coordinate).X = 30 + Sin(angle) * coordinate
  19.         XY(coordinate).Y = 30 + Cos(angle) * coordinate
  20.     Next
  21.  
  22.     For PrintIt = 0 To Lenght
  23.         Locate XY(PrintIt).Y, XY(PrintIt).X: Print Mid$(text$, PrintIt, 1)
  24.     Next
  25.     _Limit 15
  26.     Cls
  27.  
  28. 'GRAPHIC MODE
  29. graphic:
  30. Screen _NewImage(800, 800, 256)
  31.  
  32.  
  33.  
  34.     angle = angle + 0.01
  35.     For coordinate = 0 To Lenght
  36.         XY(coordinate).X = 400 + Sin(angle) * coordinate * 16
  37.         XY(coordinate).Y = 400 + Cos(angle) * coordinate * 16
  38.     Next
  39.  
  40.     For PrintIt = 0 To Lenght
  41.         _PrintString (XY(PrintIt).X, XY(PrintIt).Y), Mid$(text$, PrintIt, 1)
  42.     Next
  43.     _Limit 15
  44.     Cls
  45.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: STxAxTIC on December 21, 2021, 04:20:36 am
Just by the looks of things, it's a binning problem. Without digging into the code, I know that rotations are usually done in some kind of polar coordinates, in which case a differential "box" is a weird pie-slice type shape. In regular screen/cartesian coordinates, of course, boxes are just boxes. Point is, I think some letters are drawing directly on top of others in your special cases. Just an armchair speculation.
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 21, 2021, 11:41:26 am
They must not be a pair with the same coordinates, but because you rotate in a field (as I understood by a quick look at your program), some characters are printed on top of each other.

Aha! That totally makes sense.
Thanks for your reply.

I took your example and added a check to see if any characters are missing at a given angle
(code below) - it happens a lot!

Perhaps if we check first to make sure we aren't overwriting a character,
we add it to a "find somewhere for this to go" list and skip it for now,
then at the end, we go through that list, and place each of them in the nearest optimal blank space?
I'm not sure what the logic to determine which is the optimal space would be,
we'd have to play with it...
Anyway, thanks for your reply, that definitely explains it.

Code: QB64: [Select]
  1. ' ################################################################################################################################################################
  2. ' Petr's rotation routine
  3. ' https://www.qb64.org/forum/index.php?topic=4502.msg139260#msg139260
  4.  
  5. ' Changes: missing characters check added by madscijr
  6. ' ################################################################################################################################################################
  7.  
  8. ' boolean constants
  9. Const FALSE = 0
  10. Const TRUE = Not FALSE
  11.  
  12. ' UDTs
  13. Type XY
  14.     X As Integer
  15.     Y As Integer
  16.  
  17. ' global variables
  18. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  19. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  20.  
  21. ' local variables
  22. Dim in$
  23.  
  24. ' start menu
  25. main
  26.  
  27. ' done
  28. Input "Press <ENTER> to continue", in$
  29. System ' return control to the operating system
  30.  
  31. ' /////////////////////////////////////////////////////////////////////////////
  32. ' MAIN MENU
  33.  
  34. Sub main
  35.     Dim in$
  36.  
  37.     Do
  38.         Cls
  39.         Print m_ProgramName$
  40.         Print
  41.         Print "Petr's rotation demo"
  42.         Print
  43.         Print "1. TEXT MODE"
  44.         Print "2. GRAPHIC MODE"
  45.         Print
  46.         Print "What to do? ('q' to exit)"
  47.  
  48.         Input in$: in$ = LCase$(Left$(in$, 1))
  49.  
  50.         If in$ = "1" Then
  51.             PetrRotateTextMode
  52.         ElseIf in$ = "2" Then
  53.             PetrRotateGraphicMode
  54.         End If
  55.  
  56.         _KeyClear
  57.     Loop Until in$ = "q"
  58. End Sub ' main
  59.  
  60. ' /////////////////////////////////////////////////////////////////////////////
  61. ' TEXT MODE
  62.  
  63. Sub PetrRotateTextMode
  64.     Dim text$
  65.     Dim Lenght As Integer
  66.     ReDim XY(-1) As XY
  67.     Dim angle As Single
  68.     Dim coordinate As Integer
  69.     Dim PrintIt As Integer
  70.     Dim chars$
  71.     Dim missing$
  72.     Dim in$
  73.  
  74.     Screen _NewImage(60, 60, 0) ' text screen 60x60
  75.     _ScreenMove 0, 0
  76.  
  77.     text$ = "It's a SCREEN resolution?"
  78.     Lenght = Len(text$)
  79.     ReDim XY(Lenght) As XY
  80.     angle = 0
  81.     missing$ = ""
  82.  
  83.     Cls
  84.     Do
  85.         Cls
  86.         angle = angle + 0.01
  87.         For coordinate = 0 To Lenght
  88.             XY(coordinate).X = 30 + Sin(angle) * coordinate
  89.             XY(coordinate).Y = 30 + Cos(angle) * coordinate
  90.         Next coordinate
  91.         For PrintIt = 0 To Lenght
  92.             Locate XY(PrintIt).Y, XY(PrintIt).X
  93.             Print Mid$(text$, PrintIt, 1)
  94.         Next PrintIt
  95.         chars$ = CharsMissing$(text$, 5, 0, 0, 0)
  96.         missing$ = Replace$(chars$, " ", "")
  97.  
  98.         Locate 1, 1
  99.         Print "rotation angle: " + _Trim$(Str$(angle))
  100.         Print "rotation text : " + Chr$(34) + text$ + Chr$(34)
  101.         Print "chars missing : " + IIFSTR$(Len(missing$) = 0, "(none)", Chr$(34) + chars$ + Chr$(34))
  102.         If Len(missing$) > 0 Then
  103.             Input "PRESS <ENTER> TO CONTINUE OR q TO QUIT"; in$
  104.             If in$ = "q" Then Exit Do
  105.         Else
  106.             Print "PRESS <ESC> TO QUIT"
  107.         End If
  108.  
  109.         _Limit 15
  110.     Loop Until _KeyDown(27) ' leave loop when ESC key pressed
  111.     _KeyClear
  112. End Sub ' PetrRotateTextMode
  113.  
  114. ' /////////////////////////////////////////////////////////////////////////////
  115.  
  116. Function CharsMissing$ (MyString As String, iStartLine1 As Integer, iEndLine1 As Integer, iStartColumn1 As Integer, iEndColumn1 As Integer)
  117.     Dim x As Integer
  118.     Dim y As Integer
  119.     Dim iLen As Integer
  120.     Dim TestString As String
  121.     Dim i154 As Integer
  122.     Dim iPinkFlag As Integer
  123.     Dim iStartLine As Integer
  124.     Dim iEndLine As Integer
  125.     Dim iStartColumn As Integer
  126.     Dim iEndColumn As Integer
  127.  
  128.     If iStartLine1 > 0 And iStartLine1 <= _Height(0) Then
  129.         iStartLine = iStartLine1
  130.     Else
  131.         iStartLine = 1
  132.     End If
  133.     If iEndLine1 > 0 And iEndLine1 <= _Height(0) Then
  134.         iEndLine = iEndLine1
  135.     Else
  136.         iEndLine = _Height(0)
  137.     End If
  138.     If iStartColumn1 > 0 And iStartColumn1 <= _Width(0) Then
  139.         iStartColumn = iStartColumn1
  140.     Else
  141.         iStartColumn = 1
  142.     End If
  143.     If iEndColumn1 > 0 And iEndColumn1 <= _Width(0) Then
  144.         iEndColumn = iEndColumn1
  145.     Else
  146.         iEndColumn = _Width(0)
  147.     End If
  148.  
  149.     TestString = MyString
  150.  
  151.     iLen = Len(MyString)
  152.  
  153.     For x = iStartColumn To iEndColumn
  154.         For y = iStartLine To iEndLine
  155.             'codeorcolor% = SCREEN (row%, column% [, colorflag%])
  156.             i154 = Screen(y, x)
  157.             iPinkFlag = InStr(1, TestString, Chr$(i154))
  158.             If iPinkFlag > 0 Then
  159.                 If iPinkFlag = 1 Then
  160.                     TestString = " " + Right$(TestString, Len(TestString) - 1)
  161.                 ElseIf iPinkFlag = Len(TestString) Then
  162.                     TestString = Left$(TestString, Len(TestString) - 1) + " "
  163.                     'TestString = left$(TestString, len(TestString)-1)
  164.                 Else
  165.                     TestString = Left$(TestString, iPinkFlag - 1) + " " + Right$(TestString, Len(TestString) - iPinkFlag)
  166.                     'TestString = left$(TestString, iPinkFlag-1) + right$(TestString, Len(TestString)-iPinkFlag)
  167.                 End If
  168.             End If
  169.         Next y
  170.     Next x
  171.  
  172.     'CharsMissing$ = Replace$ (TestString, " ", "")
  173.     CharsMissing$ = TestString
  174. End Function ' CharsMissing$
  175.  
  176. ' /////////////////////////////////////////////////////////////////////////////
  177. ' GRAPHIC MODE
  178.  
  179. Sub PetrRotateGraphicMode
  180.     Dim text$
  181.     Dim Lenght As Integer
  182.     ReDim XY(-1) As XY
  183.     Dim angle As Double
  184.     Dim coordinate As Integer
  185.     Dim PrintIt As Integer
  186.  
  187.     Screen _NewImage(800, 800, 256)
  188.     _ScreenMove 0, 0
  189.  
  190.     text$ = "It's a SCREEN resolution?"
  191.     Lenght = Len(text$)
  192.     ReDim XY(Lenght) As XY
  193.     angle = 0
  194.  
  195.     Do
  196.         Cls
  197.         Print "PRESS <ESC> TO QUIT"
  198.         angle = angle + 0.01
  199.         For coordinate = 0 To Lenght
  200.             XY(coordinate).X = 400 + Sin(angle) * coordinate * 16
  201.             XY(coordinate).Y = 400 + Cos(angle) * coordinate * 16
  202.         Next coordinate
  203.         For PrintIt = 0 To Lenght
  204.             _PrintString (XY(PrintIt).X, XY(PrintIt).Y), Mid$(text$, PrintIt, 1)
  205.         Next PrintIt
  206.         _Limit 15
  207.     Loop Until _KeyDown(27) ' leave loop when ESC key pressed
  208.     _KeyClear
  209. End Sub ' PetrRotateGraphicMode
  210.  
  211. ' /////////////////////////////////////////////////////////////////////////////
  212.  
  213. Function cstr$ (myValue)
  214.     'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
  215.     cstr$ = _Trim$(Str$(myValue))
  216. End Function ' cstr$
  217.  
  218. ' /////////////////////////////////////////////////////////////////////////////
  219.  
  220. Function IIF (Condition, IfTrue, IfFalse)
  221.     If Condition Then IIF = IfTrue Else IIF = IfFalse
  222.  
  223. ' /////////////////////////////////////////////////////////////////////////////
  224.  
  225. Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
  226.     If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
  227.  
  228. ' /////////////////////////////////////////////////////////////////////////////
  229. ' FROM: String Manipulation
  230. ' found at abandoned, outdated and now likely malicious qb64 dot net website
  231. ' http://www.qb64.[net]/forum/index_topic_5964-0/
  232. '
  233. 'SUMMARY:
  234. '   Purpose:  A library of custom functions that transform strings.
  235. '   Author:   Dustinian Camburides (dustinian@gmail.com)
  236. '   Platform: QB64 (www.qb64.org)
  237. '   Revision: 1.6
  238. '   Updated:  5/28/2012
  239.  
  240. 'SUMMARY:
  241. '[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
  242. 'INPUT:
  243. 'Text: The input string; the text that's being manipulated.
  244. 'Find: The specified sub-string; the string sought within the [Text] string.
  245. 'Add: The sub-string that's being added to the [Text] string.
  246.  
  247. Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
  248.     ' VARIABLES:
  249.     Dim Text2 As String
  250.     Dim Find2 As String
  251.     Dim Add2 As String
  252.     Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
  253.     Dim strBefore As String ' The characters before the string to be replaced.
  254.     Dim strAfter As String ' The characters after the string to be replaced.
  255.  
  256.     ' INITIALIZE:
  257.     ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
  258.     Text2 = Text1
  259.     Find2 = Find1
  260.     Add2 = Add1
  261.  
  262.     lngLocation = InStr(1, Text2, Find2)
  263.  
  264.     ' PROCESSING:
  265.     ' While [Find2] appears in [Text2]...
  266.     While lngLocation
  267.         ' Extract all Text2 before the [Find2] substring:
  268.         strBefore = Left$(Text2, lngLocation - 1)
  269.  
  270.         ' Extract all text after the [Find2] substring:
  271.         strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
  272.  
  273.         ' Return the substring:
  274.         Text2 = strBefore + Add2 + strAfter
  275.  
  276.         ' Locate the next instance of [Find2]:
  277.         lngLocation = InStr(1, Text2, Find2)
  278.  
  279.         ' Next instance of [Find2]...
  280.     Wend
  281.  
  282.     ' OUTPUT:
  283.     Replace$ = Text2
  284. End Function ' Replace$
  285.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 21, 2021, 11:42:59 am
Just by the looks of things, it's a binning problem. Without digging into the code, I know that rotations are usually done in some kind of polar coordinates, in which case a differential "box" is a weird pie-slice type shape. In regular screen/cartesian coordinates, of course, boxes are just boxes. Point is, I think some letters are drawing directly on top of others in your special cases. Just an armchair speculation.

I think you're right. @Petr replied with a little demo program that illustrates just that.
Thanks for your reply!
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 21, 2021, 02:12:23 pm
Well @Petr and @STxAxTIC, I tried writing some logic to handle the issue you pointed out.
It takes any points that would have overwritten an already occupied point on the screen,
and tries to place them in an adjacent unused space.
This is more of a proof of concept, the logic is simple and surely flawed,
but it seems to produce better looking results than without it?


Before & after #1.
Rotated to 30 degrees.

Old logic (ShearRotateTest2) has many lost points:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

New logic (ShearRotateTest3) has a lot less lost points:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  


Before & after #2 (simpler example!)
Rotated to 30 degrees.

Old logic (ShearRotateTest2) has lost points:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

New logic (ShearRotateTest3) has no lost points:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  


Run the below code and judge for yourself.
You will see menu options
Code: [Select]
6. ShearRotateTest2 (auto advances 0-360 degrees)"
7. ShearRotateTest2 (auto advances 0-360 degrees) (uses Petr's text)"
8. ShearRotateTest3 (tries to correct for missing points)"
9. ShearRotateTest3 (tries to correct for missing points) (uses Petr's text)"

Choose option 6 or 7 for the original "lossy" rotation (the only difference is 7 uses the string from @Petr 's program).
It now counts and displays the # of "lost" points that are overwritten, for the current rotation angle.
You'll see the lost points show up at 30, 60, 120, 150, etc. angles.

Choose option 8 or 9 for the new logic (the only difference is 9 uses the string from @Petr 's program).
It counts and displays the # of "lost" points that were not successfully relocated, for the current rotation angle.
You'll see a lot less lost points now at 30, 60, 120, 150, etc. angles.

The way the current logic works is, it keeps looking for an empty space farther out in the given direction until it either finds one or reaches the boundary of the screen.
So it could theoretically plot a point 2 or more spaces away that are no longer adjacent, yielding some funky looking results.
I think the logic could be improved where, if it doesn't find an empty space immediatly above/below, to the right/left, or diagonally,
it can try looking one space in the opposite directions, and if not, then quit.

Thoughts?



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. ' -----------------------------------------------------------------------------
  18. ' USER DEFINED TYPES
  19. ' -----------------------------------------------------------------------------
  20. Type RotationType
  21.     origx As Integer
  22.     origy As Integer
  23.     'z as integer
  24.     c As Integer
  25. End Type ' RotationType
  26.  
  27. ' -----------------------------------------------------------------------------
  28. ' GLOBAL VARIABLES
  29. ' -----------------------------------------------------------------------------
  30. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  31. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  32. Dim Shared m_bDebug: m_bDebug = TRUE
  33.  
  34. ' =============================================================================
  35. ' BEGIN MAIN PROGRAM
  36. ' =============================================================================
  37. Dim in$
  38.  
  39. ' ****************************************************************************************************************************************************************
  40. ' ACTIVATE DEBUGGING WINDOW
  41. If m_bDebug = TRUE Then
  42.     $Console
  43.     _Delay 4
  44.     _Console On
  45.     _Echo "Started " + m_ProgramName$
  46.     _Echo "Debugging on..."
  47. ' ****************************************************************************************************************************************************************
  48.  
  49. ' -----------------------------------------------------------------------------
  50. ' START THE MENU
  51. main
  52.  
  53. ' -----------------------------------------------------------------------------
  54. ' DONE
  55. Print m_ProgramName$ + " finished."
  56. 'Screen 0
  57. Input "Press <ENTER> to continue", in$
  58.  
  59. ' ****************************************************************************************************************************************************************
  60. ' DEACTIVATE DEBUGGING WINDOW
  61. If m_bDebug = TRUE Then
  62. ' ****************************************************************************************************************************************************************
  63.  
  64. ' -----------------------------------------------------------------------------
  65. ' EXIT
  66. System ' return control to the operating system
  67.  
  68. ' =============================================================================
  69. ' END MAIN PROGRAM
  70. ' =============================================================================
  71.  
  72. ' /////////////////////////////////////////////////////////////////////////////
  73. ' MAIN MENU
  74.  
  75. Sub main
  76.     Dim RoutineName As String: RoutineName = "main"
  77.     Dim in$
  78.  
  79.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  80.     Do
  81.         Cls
  82.         Print m_ProgramName$
  83.         Print
  84.         Print "Some basic 2D plotting"
  85.         Print
  86.         Print "1. PlotPointTest"
  87.         Print "2. PlotSquareTest"
  88.         Print "3. PlotCircleTest"
  89.         Print "4. PlotLineTest"
  90.         Print "5. ShearRotateTest1"
  91.         Print "6. ShearRotateTest2 (auto advances 0-360 degrees)"
  92.         Print "7. ShearRotateTest2 (auto advances 0-360 degrees) (uses Petr's text)"
  93.         Print "8. ShearRotateTest3 (tries to correct for missing points)"
  94.         Print "9. ShearRotateTest3 (tries to correct for missing points) (uses Petr's text)"
  95.         Print
  96.         Print "What to do? ('q' to exit)"
  97.  
  98.         Input in$: in$ = LCase$(Left$(in$, 1))
  99.  
  100.         If in$ = "1" Then
  101.             PlotPointTest
  102.         ElseIf in$ = "2" Then
  103.             PlotSquareTest
  104.         ElseIf in$ = "3" Then
  105.             PlotCircleTest
  106.         ElseIf in$ = "4" Then
  107.             PlotLineTest
  108.         ElseIf in$ = "5" Then
  109.             ShearRotateTest1
  110.         ElseIf in$ = "6" Then
  111.             ShearRotateTest2 TestSprite1$
  112.         ElseIf in$ = "7" Then
  113.             ShearRotateTest2 PetrText1$
  114.         ElseIf in$ = "8" Then
  115.             ShearRotateTest3 TestSprite1$
  116.         ElseIf in$ = "9" Then
  117.             ShearRotateTest3 PetrText1$
  118.         End If
  119.     Loop Until in$ = "q"
  120. End Sub ' main
  121.  
  122. ' /////////////////////////////////////////////////////////////////////////////
  123. ' MyArray(1 To 32, 1 To 32) AS STRING
  124.  
  125. Sub PlotPoint (X As Integer, Y As Integer, S As String, MyArray() As String)
  126.     If (X >= LBound(MyArray, 2)) Then
  127.         If (X <= UBound(MyArray, 2)) Then
  128.             If (Y >= LBound(MyArray, 1)) Then
  129.                 If (Y <= UBound(MyArray, 1)) Then
  130.                     If Len(S) = 1 Then
  131.                         MyArray(Y, X) = S
  132.                     Else
  133.                         If Len(S) > 1 Then
  134.                             MyArray(Y, X) = Left$(S, 1)
  135.                         End If
  136.                     End If
  137.                 End If
  138.             End If
  139.         End If
  140.     End If
  141. End Sub ' PlotPoint
  142.  
  143. ' /////////////////////////////////////////////////////////////////////////////
  144.  
  145. Sub PlotPointTest
  146.     Dim MyArray(1 To 32, 1 To 32) As String
  147.     Dim iX As Integer
  148.     Dim iY As Integer
  149.     Dim in$
  150.     Dim X As Integer
  151.     Dim Y As Integer
  152.     Dim L As Integer
  153.     Dim iChar As Integer
  154.  
  155.     ClearArray MyArray(), "."
  156.     iChar = 64
  157.  
  158.     Cls
  159.     Print "Plot a point."
  160.     Print ArrayToStringTest(MyArray())
  161.     Print
  162.  
  163.     Do
  164.         Print "Type x,y (1-32, 1-32) coordinate to plot point at."
  165.         Input "X,Y OR 0 TO QUIT? "; X, Y
  166.         If X > 0 And Y > 0 Then
  167.             iChar = iChar + 1
  168.             If iChar > 90 Then iChar = 65
  169.  
  170.             Print "X=" + cstr$(X) + ", Y=" + cstr$(Y)
  171.             PlotPoint X, Y, Chr$(iChar), MyArray()
  172.  
  173.             Print "Current point plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  174.             Print ArrayToStringTest(MyArray())
  175.             Print
  176.  
  177.         Else
  178.             Exit Do
  179.         End If
  180.     Loop
  181. End Sub ' PlotPointTest
  182.  
  183. ' /////////////////////////////////////////////////////////////////////////////
  184.  
  185. Sub PlotSquare (X1 As Integer, Y1 As Integer, L As Integer, S As String, MyArray() As String)
  186.     Dim X As Integer
  187.     Dim X2 As Integer
  188.     Dim Y As Integer
  189.     Dim Y2 As Integer
  190.     Dim sChar$
  191.  
  192.     If Len(S) = 1 Then
  193.         sChar$ = S
  194.     Else
  195.         If Len(S) = 0 Then
  196.             sChar$ = " "
  197.         Else
  198.             sChar$ = Left$(S, 1)
  199.         End If
  200.     End If
  201.  
  202.     X2 = (X1 + L) - 1
  203.     Y2 = (Y1 + L) - 1
  204.     For X = X1 To X2
  205.         For Y = Y1 To Y2
  206.             PlotPoint X, Y, sChar$, MyArray()
  207.         Next Y
  208.     Next X
  209. End Sub ' PlotSquare
  210.  
  211. ' /////////////////////////////////////////////////////////////////////////////
  212.  
  213. Sub PlotSquareTest
  214.     Dim MyArray(1 To 32, 1 To 32) As String
  215.     Dim iX As Integer
  216.     Dim iY As Integer
  217.     Dim in$
  218.     Dim X As Integer
  219.     Dim Y As Integer
  220.     Dim L As Integer
  221.     Dim iChar As Integer
  222.  
  223.     ClearArray MyArray(), "."
  224.     iChar = 64
  225.  
  226.     Cls
  227.     Print "Enter parameters to draw a square."
  228.     Print ArrayToStringTest(MyArray())
  229.     Print
  230.     Do
  231.         Print "Type top left x,y (1-32, 1-32) coordinate to plot square,"
  232.         Print "and size (1-32) of square."
  233.         Input "X,Y,L OR 0 TO QUIT? "; X, Y, L
  234.         If X > 0 And Y > 0 And L > 0 Then
  235.             iChar = iChar + 1
  236.             If iChar > 90 Then iChar = 65
  237.  
  238.             Print
  239.             Print "X=" + cstr$(X)
  240.             Print "Y=" + cstr$(Y)
  241.             Print "L=" + cstr$(L)
  242.             Print
  243.             PlotSquare X, Y, L, Chr$(iChar), MyArray()
  244.  
  245.             Print "Square plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  246.             Print ArrayToStringTest(MyArray())
  247.             Print
  248.         Else
  249.             Exit Do
  250.         End If
  251.     Loop
  252. End Sub ' PlotSquareTest
  253.  
  254. ' /////////////////////////////////////////////////////////////////////////////
  255. ' Fast circle drawing in pure Atari BASIC#
  256. ' https://atariwiki.org/wiki/Wiki.jsp?page=Super%20fast%20circle%20routine
  257.  
  258. ' * Magazine: Moj Mikro, 1989/3
  259. ' * Author : Zlatko Bleha
  260. ' * Page : 27 - 31
  261. ' * Atari BASIC listing on disk (tokenized): M8903282.BAS
  262. ' * Atari BASIC listing (listed): M8903282.LST
  263.  
  264. ' Next example is demonstration of implementing mentioned circle algorithm
  265. ' in pure Atari BASIC. This program shows how much faster it is compared to
  266. ' classic program using sine and cosine functions from Atari BASIC
  267. ' (shown in last example).
  268.  
  269. ' Basic Listing M8903282.LST#
  270. '1 REM *******************************
  271. '2 REM PROGRAM  : FAST CIRCLE DRAWING
  272. '3 REM AUTHOR   : ZLATKO BLEHA
  273. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  274. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  275. '6 REM *******************************
  276. '7 REM
  277. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  278. '20 PRINT "ENTER X, Y AND R"
  279. '30 INPUT X,Y,R
  280. '40 IF R=0 THEN PLOT X,Y:END
  281. '50 B=R:C=0:A=R-1
  282. '60 PLOT X+C,Y+B
  283. '70 PLOT X+C,Y-B
  284. '80 PLOT X-C,Y-B
  285. '90 PLOT X-C,Y+B
  286. '100 PLOT X+B,Y+C
  287. '110 PLOT X+B,Y-C
  288. '120 PLOT X-B,Y-C
  289. '130 PLOT X-B,Y+C
  290. '140 C=C+1
  291. '150 A=A+1-C-C
  292. '160 IF A>=0 THEN 190
  293. '170 B=B-1
  294. '180 A=A+B+B
  295. '190 IF B>=C THEN 60
  296.  
  297. ' Use some valid values for coordinates and radius, for example:
  298. ' X=40, Y=40, R=30
  299. ' X=130, Y=90, R=60
  300. ' Slow circle drawing in Atari BASIC#
  301. ' * Magazine: Moj Mikro, 1989/3
  302. ' * Author : Zlatko Bleha
  303. ' * Page : 27 - 31
  304. ' * Atari BASIC listing on disk (tokenized): M8903281.BAS
  305. ' * Atari BASIC listing (listed): M8903281.LST
  306.  
  307. ' This is classic example for drawing circles from Atari BASIC
  308. ' using sine and cosine functions. Unfortunatelly, this is very slow
  309. ' way of doing it and not recommended.
  310. ' Just use routine shown above and everybody will be happy
  311.  
  312. ' Basic Listing M8903281.LST#
  313. '1 REM *******************************
  314. '2 REM PROGRAM  : SLOW CIRCLE DRAWING
  315. '3 REM AUTHOR   : ZLATKO BLEHA
  316. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  317. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  318. '6 REM *******************************
  319. '7 REM
  320. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  321. '20 FOR A=0 TO 6.28 STEP 0.02
  322. '30 X=SIN(A)*50+150
  323. '40 Y=COS(A)*50+80
  324. '50 PLOT X,Y
  325. '60 NEXT A
  326.  
  327. ' Conclusion#
  328. ' Returning back to first program with the fastest way of drawing circles...
  329. ' There is one more thing to note. In case you want to use PLOT subroutine,
  330. ' which is part of the main circle routine, then read following explanation.
  331. ' PLOT routine is written so it can be used easily from Atari BASIC program
  332. ' independently from main circle routine, by using like this:
  333. ' A=USR(30179,POK,X,Y)
  334. '
  335. ' POK   1 (drawing a pixel), 0 (erasing a pixel)
  336. ' X     X coordinate of the pixel
  337. ' Y     Y coordinate of the pixel
  338. '
  339. ' The routine alone is not any faster than normal PLOT command
  340. ' from Atari BASIC, because USR command takes approximately 75%
  341. ' of whole execution. But, used as part of the main circle routine
  342. ' it does not matter anymore, because it is integrated in one larger
  343. ' entity. There the execution is very fast, with no overhead.
  344. ' PLOT routine is here for you to examine anyway.
  345. ' You never know if you will maybe need it in the future.
  346.  
  347. ' More on plotting circles:
  348. '     Drawing a circle in BASIC - fast
  349. '     https://www.cpcwiki.eu/forum/programming/drawing-a-circle-in-basic-fast/
  350.  
  351. ' X,Y     = center point of circle
  352. ' R       = radius
  353. ' S       = char to draw
  354. ' MyArray = 2D string array to plot circle in
  355.  
  356. Sub PlotCircle (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  357.     Dim A As Integer
  358.     Dim B As Integer
  359.     Dim C As Integer
  360.     Dim S2 As String
  361.  
  362.     If Len(S) = 1 Then
  363.         S2 = S
  364.     Else
  365.         If Len(S) = 0 Then
  366.             S2 = " "
  367.         Else
  368.             S2 = Left$(S, 1)
  369.         End If
  370.     End If
  371.  
  372.     If R > 0 Then
  373.         B = R
  374.         C = 0
  375.         A = R - 1
  376.         Do
  377.             PlotPoint X + C, Y + B, S2, MyArray()
  378.             PlotPoint X + C, Y - B, S2, MyArray()
  379.             PlotPoint X - C, Y - B, S2, MyArray()
  380.             PlotPoint X - C, Y + B, S2, MyArray()
  381.             PlotPoint X + B, Y + C, S2, MyArray()
  382.             PlotPoint X + B, Y - C, S2, MyArray()
  383.             PlotPoint X - B, Y - C, S2, MyArray()
  384.             PlotPoint X - B, Y + C, S2, MyArray()
  385.             C = C + 1
  386.             A = A + 1 - C - C
  387.             If A < 0 Then ' IF A>=0 THEN 190
  388.                 B = B - 1
  389.                 A = A + B + B
  390.             End If
  391.             If B < C Then Exit Do ' 190 IF B>=C THEN 60
  392.         Loop
  393.     End If
  394. End Sub ' PlotCircle
  395.  
  396. ' /////////////////////////////////////////////////////////////////////////////
  397.  
  398. Sub PlotCircleTest
  399.     Dim MyArray(1 To 32, 1 To 32) As String
  400.     Dim iX As Integer
  401.     Dim iY As Integer
  402.     Dim in$
  403.     Dim X As Integer
  404.     Dim Y As Integer
  405.     Dim R As Integer
  406.     Dim iChar As Integer
  407.  
  408.     ClearArray MyArray(), "."
  409.     iChar = 64
  410.  
  411.     Cls
  412.     Print "Plot a raster circle"
  413.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  414.     Print
  415.     Print "Enter parameters to draw a circle."
  416.     Print ArrayToStringTest(MyArray())
  417.     Print
  418.  
  419.     Do
  420.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  421.         Print "and radius (1-32) of circle."
  422.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  423.         If X > 0 And Y > 0 And R > 0 Then
  424.             iChar = iChar + 1
  425.             If iChar > 90 Then iChar = 65
  426.  
  427.             Print "X=" + cstr$(X)
  428.             Print "Y=" + cstr$(Y)
  429.             Print "R=" + cstr$(R)
  430.  
  431.             PlotCircle X, Y, R, Chr$(iChar), MyArray()
  432.  
  433.             Print "Circle plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  434.             Print ArrayToStringTest(MyArray())
  435.             Print
  436.         Else
  437.             Exit Do
  438.         End If
  439.     Loop
  440.  
  441. End Sub ' PlotCircleTest
  442.  
  443. ' /////////////////////////////////////////////////////////////////////////////
  444. ' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
  445. ' From: http://www.thedubber.altervista.org/qbsrc.htm
  446.  
  447. Sub PlotLine (x1%, y1%, x2%, y2%, c$, MyArray() As String)
  448.     Dim iLoop%
  449.     Dim steep%: steep% = 0
  450.     Dim ev%: ev% = 0
  451.     Dim sx%
  452.     Dim sy%
  453.     Dim dx%
  454.     Dim dy%
  455.  
  456.     If (x2% - x1%) > 0 Then
  457.         sx% = 1
  458.     Else
  459.         sx% = -1
  460.     End If
  461.  
  462.     dx% = Abs(x2% - x1%)
  463.     If (y2% - y1%) > 0 Then
  464.         sy% = 1
  465.     Else
  466.         sy% = -1
  467.     End If
  468.  
  469.     dy% = Abs(y2% - y1%)
  470.     If (dy% > dx%) Then
  471.         steep% = 1
  472.         Swap x1%, y1%
  473.         Swap dx%, dy%
  474.         Swap sx%, sy%
  475.     End If
  476.  
  477.     ev% = 2 * dy% - dx%
  478.     For iLoop% = 0 To dx% - 1
  479.         If steep% = 1 Then
  480.             ''PSET (y1%, x1%), c%:
  481.             'LOCATE y1%, x1%
  482.             'PRINT c$;
  483.             PlotPoint y1%, x1%, c$, MyArray()
  484.         Else
  485.             ''PSET (x1%, y1%), c%
  486.             'LOCATE x1%, y1%
  487.             'PRINT c$;
  488.             PlotPoint x1%, y1%, c$, MyArray()
  489.         End If
  490.  
  491.         While ev% >= 0
  492.             y1% = y1% + sy%
  493.             ev% = ev% - 2 * dx%
  494.         Wend
  495.         x1% = x1% + sx%
  496.         ev% = ev% + 2 * dy%
  497.     Next iLoop%
  498.     ''PSET (x2%, y2%), c%
  499.     'LOCATE x2%, y2%
  500.     'PRINT c$;
  501.     PlotPoint x2%, y2%, c$, MyArray()
  502. End Sub ' PlotLine
  503.  
  504. ' /////////////////////////////////////////////////////////////////////////////
  505.  
  506. Sub PlotLineTest
  507.     Dim MyArray(1 To 32, 1 To 32) As String
  508.     Dim in$
  509.     Dim X1 As Integer
  510.     Dim Y1 As Integer
  511.     Dim X2 As Integer
  512.     Dim Y2 As Integer
  513.     Dim iChar As Integer
  514.  
  515.     ClearArray MyArray(), "."
  516.     iChar = 64
  517.  
  518.     Cls
  519.     Print "Plot line with Bresenham Algorithm"
  520.     Print "based on BRESNHAM.BAS by Kurt Kuzba (4/16/96)."
  521.     Print
  522.     Print ArrayToStringTest(MyArray())
  523.     Do
  524.         Print "Enter coordinate values for "
  525.         Print "line start point x1, y1 (1-32, 1-32)"
  526.         Print "line end   point x2, y2 (1-32, 1-32)"
  527.         Input "ENTER X1,Y1,X2,Y2 OR 0 TO QUIT: "; X1, Y1, X2, Y2
  528.         If X1 > 0 And Y1 > 0 And X2 > 0 And Y2 > 0 Then
  529.             iChar = iChar + 1
  530.             If iChar > 90 Then iChar = 65
  531.  
  532.             Print "X1=" + cstr$(X1)
  533.             Print "Y1=" + cstr$(Y1)
  534.             Print "X2=" + cstr$(X2)
  535.             Print "Y2=" + cstr$(Y2)
  536.  
  537.             PlotLine X1, Y1, X2, Y2, Chr$(iChar), MyArray()
  538.  
  539.             Print "Line plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  540.             Print ArrayToStringTest(MyArray())
  541.  
  542.         Else
  543.             Exit Do
  544.         End If
  545.     Loop
  546. End Sub ' PlotLineTest
  547.  
  548. ' /////////////////////////////////////////////////////////////////////////////
  549. ' 3 shear method testing
  550.  
  551. ' _PUT Rotation Help
  552. ' https://www.qb64.org/forum/index.php?topic=1959.0
  553.  
  554. ' 3 Shear Rotation - rotates without any aliasing(holes)
  555. ' https://www.freebasic.net/forum/viewtopic.php?t=24557
  556.  
  557. ' From: leopardpm
  558. ' Date: Apr 02, 2016 1:21
  559. ' Last edited by leopardpm on Apr 02, 2016 17:18, edited 1 time in total.
  560. '
  561. ' This is just a little 3-shear rotation routine
  562. ' (I am using 3-shear because it leaves no gaps/aliasing)
  563. ' that I was wondering if anyone sees how to make it faster.
  564. ' Obviously, I am just thinking about inside the double loop.
  565.  
  566. ' Thanks again to BasicCoder2 for linking me to this little routine, it is wonderful so far!
  567.  
  568. '''                      roto-zooming algorithm
  569. '''                    coded by Michael S. Nissen
  570. '''                        jernmager@yahoo.dk
  571. '
  572. ''' ===============================================================
  573. ''' Recoded to run on FBC 32/64 bit WIN, Version 1.05.0, 2016, by MrSwiss
  574. ''' Heavy flickering before going Full-Screen on 64 Bit !!!
  575. ''' This seems NOT to be the Case on 32 Bit ...
  576. ''' ===============================================================
  577. '
  578. 'Type Pixel
  579. '  As Single   X, Y
  580. '  As ULong    C
  581. 'End Type
  582. '
  583. '''  dim vars
  584. 'Dim shared as Any Ptr Img_Buffer
  585. '''  write the name of the .bmp image you want to rotozoom here:
  586. '''  (it has to be sqare ie. 100x100 pixels, 760x760 pixels or whatever)
  587. 'Dim As String Img_Name = "phobos.bmp"
  588. 'Dim shared as Integer X_Mid, Y_Mid, scrn_wid, scrn_hgt, P1, P2, P3, P4, C
  589. 'Dim shared as Short Img_Hgt, Img_Wid, Img_Lft, Img_Rgt, Img_Top, Img_Btm, X, Y
  590. 'Dim Shared As Single Cos_Ang, Sin_Ang, Rot_Fac_X, Rot_Fac_Y, Angle = 0, Scale = 1
  591. '
  592. ''' changed Function to Sub (+ recoded arguments list)
  593. 'Sub Calc_rotozoom ( ByRef Cos_Ang As Single, _
  594. '               ByRef Sin_Ang As Single, _
  595. '               ByVal S_Fact  As Single, _
  596. '               ByVal NewAng  As Single )
  597. '  Cos_Ang = Cos(NewAng)*S_Fact
  598. '  Sin_Ang = Sin(NewAng)*S_Fact
  599. 'End Sub
  600. '
  601. '''  full screen
  602. 'ScreenInfo scrn_wid, scrn_hgt
  603. 'screenRes scrn_wid, scrn_hgt, 32,,1
  604. '
  605. '''  dim screenpointer (has to be done after screenres)
  606. 'Dim As ULong Ptr Scrn_Ptr = Screenptr
  607. '
  608. '''  place image in center of screen
  609. 'X_Mid = scrn_wid\2
  610. 'Y_Mid = scrn_hgt\2
  611. 'Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  612. '
  613. '''  find image dimensions
  614. 'Open Img_Name For Binary As #1
  615. 'Get #1, 19, Img_Wid
  616. 'Get #1, 23, Img_Hgt
  617. 'Close #1
  618. '
  619. '''  prepare to dim the array that will hold the image.
  620. 'Img_Rgt = (Img_Wid-1)\2
  621. 'Img_Lft = -Img_Rgt
  622. 'Img_Btm = (Img_Hgt-1)\2
  623. 'Img_Top = -Img_Btm
  624. '
  625. '''  dim array to hold image. Note: pixel (0, 0) is in the center.
  626. 'Dim As Pixel Pixel(Img_Lft to Img_Rgt, Img_Top to Img_Btm)
  627. '
  628. '''  imagecreate sprite and load image to sprite
  629. 'Img_Buffer = ImageCreate (Img_Wid, Img_Hgt)
  630. 'Bload (Img_Name, Img_Buffer)
  631. '
  632. '''  load image from sprite to array with point command
  633. 'For Y = Img_Top to Img_Btm
  634. '  For X = Img_Lft to Img_Rgt
  635. '    With Pixel(X, Y)
  636. '      .X = X_Mid+X
  637. '      .Y = Y_Mid+Y
  638. '      C = Point (X-Img_Top, Y-Img_Lft, Img_buffer)
  639. '      If C <> RGB(255, 0, 255) Then
  640. '        .C = C
  641. '      Else
  642. '        .C = RGB(0, 0, 0)
  643. '      End If
  644. '    End With
  645. '  Next X
  646. 'Next Y
  647. '
  648. '''  we don't need the sprite anymore, kill it
  649. 'ImageDestroy Img_Buffer
  650. 'Img_Buffer = 0
  651. '
  652. '''  main program loop
  653. 'Do
  654. '
  655. '  ''  scale in/out with uparrow/downarrow
  656. '  If Multikey(80) Then
  657. '    Scale *= 1.03
  658. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  659. '  ElseIf Multikey(72) Then
  660. '    Scale *= 0.97
  661. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  662. '  End If
  663. '
  664. '  ''  rotate left/right with leftarrow/rightarrow
  665. '  If Multikey(77) Then
  666. '    Angle -= 0.03
  667. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  668. '  ElseIf Multikey(75) Then
  669. '    Angle += 0.03
  670. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  671. '  End If
  672. '
  673. '  ''  lock screen in order to use screen pointers
  674. '  ScreenLock
  675. '
  676. '    ''  draw pixel in center of image
  677. '    Scrn_Ptr[ X_Mid + Y_Mid * scrn_wid ] = Pixel(0, 0).C
  678. '    ''  draw all other pixels - 4 at a time
  679. '    For Y = Img_Top to 0
  680. '      For X = Img_Lft to -1
  681. '        ''  find pixel positions
  682. '        P1 = (X_Mid+X) + (Y_Mid+Y) * scrn_wid
  683. '        P2 = (X_Mid-X) + (Y_Mid-Y) * scrn_wid
  684. '        P3 = (X_Mid+Y) + (Y_Mid-X) * scrn_wid
  685. '        P4 = (X_Mid-Y) + (Y_Mid+X) * scrn_wid
  686. '        ''  erase old pixels (paint them black)
  687. '        Scrn_Ptr[P1] = 0
  688. '        Scrn_Ptr[P2] = 0
  689. '        Scrn_Ptr[P3] = 0
  690. '        Scrn_Ptr[P4] = 0
  691. '        ''  rotate and zoom
  692. '        Rot_Fac_X = X*Cos_Ang - Y*Sin_Ang
  693. '        Rot_Fac_Y = X*Sin_Ang + Y*Cos_Ang
  694. '        If Rot_Fac_X < Img_Lft Or Rot_Fac_X > Img_Rgt Then Continue For
  695. '        If Rot_Fac_Y < Img_Top Or Rot_Fac_Y > Img_Btm Then Continue For
  696. '        ''  draw new pixels
  697. '        Scrn_Ptr[P1] = Pixel(Rot_Fac_X, Rot_Fac_Y).C
  698. '        Scrn_Ptr[P2] = Pixel(-Rot_Fac_X, -Rot_Fac_Y).C
  699. '        Scrn_Ptr[P3] = Pixel(Rot_Fac_Y, -Rot_Fac_X).C
  700. '        Scrn_Ptr[P4] = Pixel(-Rot_Fac_Y, Rot_Fac_X).C
  701. '      Next X
  702. '    Next Y
  703. '
  704. '  ScreenUnLock
  705. '
  706. '  Sleep 10, 1
  707. 'Loop Until InKey() = Chr(27)
  708.  
  709. ' UPDATES:
  710. ' Fixed bug where values 135, 224, and 314 all resolve to -45 degrees.
  711. ' Fixed bug where an angle of 46-135 degrees caused the image to be flipped wrong.
  712.  
  713. ' TODO:
  714. ' Fix issue where image looks bad at 30, 60, 120, 150, 210, 240, 300, 330 degrees
  715.  
  716. Sub ShearRotate (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  717.     Const Pi = 4 * Atn(1)
  718.  
  719.     Dim angle As Integer
  720.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  721.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  722.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  723.     Dim x As Integer
  724.     Dim y As Integer
  725.     Dim nangle As Integer
  726.     Dim nx As Integer
  727.     Dim ny As Integer
  728.     Dim flipper As Integer
  729.     Dim rotr As Double
  730.     Dim shear1 As Double
  731.     Dim shear2 As Double
  732.     Dim clr As Integer
  733.     Dim y1 As _Byte
  734.     Dim xy1 As _Byte
  735.     Dim fy As _Byte
  736.     Dim fx As _Byte
  737.     Dim in$
  738.     Dim sLine As String
  739.  
  740.     ' initialize new with empty
  741.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  742.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  743.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  744.             NewArray(x, y, 0).origx = x
  745.             NewArray(x, y, 0).origy = y
  746.             NewArray(x, y, 0).c = iEmpty
  747.         Next y
  748.     Next x
  749.  
  750.     ' angle is reversed
  751.     angle = 360 - angle1
  752.  
  753.     ' Shearing each element 3 times in one shot
  754.     nangle = angle
  755.  
  756.     ' this pre-processing portion basically rotates by 90 to get
  757.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  758.     If angle > 45 And angle < 225 Then
  759.         If angle < 135 Then
  760.             nangle = angle - 90
  761.         Else
  762.             nangle = angle - 180
  763.         End If
  764.     End If
  765.     If angle > 135 And angle < 315 Then
  766.         If angle < 225 Then
  767.             nangle = angle - 180
  768.         Else
  769.             nangle = angle - 270
  770.         End If
  771.     End If
  772.     If nangle < 0 Then
  773.         nangle = nangle + 360
  774.     End If
  775.     If nangle > 359 Then
  776.         nangle = nangle - 360
  777.     End If
  778.  
  779.     rotr = nangle * DtoR
  780.     shear1 = Tan(rotr / 2) ' correct way
  781.     shear2 = Sin(rotr)
  782.  
  783.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  784.     ' ***       all resolve to -45 degrees.
  785.     ' ***       Fixed by changing < to <=
  786.  
  787.     'if angle >  45 and angle < 134 then
  788.     If angle > 45 And angle <= 134 Then
  789.         flipper = 1
  790.     ElseIf angle > 134 And angle <= 224 Then
  791.         flipper = 2
  792.     ElseIf angle > 224 And angle <= 314 Then
  793.         ' *** NOTE: this had a bug where this flipper was wrong
  794.         '           Fixed by adding case 7
  795.         'flipper = 3
  796.         flipper = 7
  797.     Else
  798.         flipper = 0
  799.     End If
  800.  
  801.     ' Here is where it needs some optimizing possibly... kinda slow...
  802.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  803.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  804.             Select Case flipper
  805.                 Case 1:
  806.                     nx = -y
  807.                     ny = x
  808.                 Case 2:
  809.                     nx = -x
  810.                     ny = -y
  811.                 Case 3:
  812.                     nx = -y
  813.                     ny = -x
  814.                 Case 4:
  815.                     nx = -x
  816.                     ny = y
  817.                 Case 5:
  818.                     nx = x
  819.                     ny = -y
  820.                 Case 6:
  821.                     nx = y
  822.                     ny = x
  823.                 Case 7:
  824.                     nx = y
  825.                     ny = -x
  826.                 Case Else:
  827.                     nx = x
  828.                     ny = y
  829.             End Select
  830.  
  831.             clr = OldArray(nx, ny, 0).c
  832.  
  833.             y1 = y * shear1
  834.             xy1 = x + y1
  835.             fy = (y - xy1 * shear2)
  836.             fx = xy1 + fy * shear1
  837.  
  838.             If fx >= -16 And fx <= 16 Then
  839.                 If fy >= -16 And fy <= 16 Then
  840.                     NewArray(fx, fy, 0).c = clr
  841.                     NewArray(fx, fy, 0).origx = fx
  842.                     NewArray(fx, fy, 0).origy = fy
  843.                 End If
  844.             End If
  845.         Next x
  846.     Next y
  847. End Sub ' ShearRotate
  848.  
  849. ' /////////////////////////////////////////////////////////////////////////////
  850. ' Same as ShearRotate, except adds iOverwriteCount parameter,
  851. ' and counts how many points are overwriting existing points,
  852. ' and return that value byref in parameter iOverwriteCount.
  853.  
  854. Sub ShearRotate1 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iOverwriteCount As Integer)
  855.     Const Pi = 4 * Atn(1)
  856.  
  857.     Dim angle As Integer
  858.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  859.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  860.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  861.     Dim x As Integer
  862.     Dim y As Integer
  863.     Dim nangle As Integer
  864.     Dim nx As Integer
  865.     Dim ny As Integer
  866.     Dim flipper As Integer
  867.     Dim rotr As Double
  868.     Dim shear1 As Double
  869.     Dim shear2 As Double
  870.     Dim clr As Integer
  871.     Dim y1 As _Byte
  872.     Dim xy1 As _Byte
  873.     Dim fy As _Byte
  874.     Dim fx As _Byte
  875.     Dim in$
  876.     Dim sLine As String
  877.  
  878.     ' initialize new with empty
  879.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  880.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  881.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  882.             NewArray(x, y, 0).origx = x
  883.             NewArray(x, y, 0).origy = y
  884.             NewArray(x, y, 0).c = iEmpty
  885.         Next y
  886.     Next x
  887.  
  888.     ' angle is reversed
  889.     angle = 360 - angle1
  890.  
  891.     ' Shearing each element 3 times in one shot
  892.     nangle = angle
  893.  
  894.     ' this pre-processing portion basically rotates by 90 to get
  895.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  896.     If angle > 45 And angle < 225 Then
  897.         If angle < 135 Then
  898.             nangle = angle - 90
  899.         Else
  900.             nangle = angle - 180
  901.         End If
  902.     End If
  903.     If angle > 135 And angle < 315 Then
  904.         If angle < 225 Then
  905.             nangle = angle - 180
  906.         Else
  907.             nangle = angle - 270
  908.         End If
  909.     End If
  910.     If nangle < 0 Then
  911.         nangle = nangle + 360
  912.     End If
  913.     If nangle > 359 Then
  914.         nangle = nangle - 360
  915.     End If
  916.  
  917.     rotr = nangle * DtoR
  918.     shear1 = Tan(rotr / 2) ' correct way
  919.     shear2 = Sin(rotr)
  920.  
  921.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  922.     ' ***       all resolve to -45 degrees.
  923.     ' ***       Fixed by changing < to <=
  924.  
  925.     'if angle >  45 and angle < 134 then
  926.     If angle > 45 And angle <= 134 Then
  927.         flipper = 1
  928.     ElseIf angle > 134 And angle <= 224 Then
  929.         flipper = 2
  930.     ElseIf angle > 224 And angle <= 314 Then
  931.         ' *** NOTE: this had a bug where this flipper was wrong
  932.         '           Fixed by adding case 7
  933.         'flipper = 3
  934.         flipper = 7
  935.     Else
  936.         flipper = 0
  937.     End If
  938.  
  939.     ' Here is where it needs some optimizing possibly... kinda slow...
  940.     iOverwriteCount = 0
  941.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  942.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  943.             Select Case flipper
  944.                 Case 1:
  945.                     nx = -y
  946.                     ny = x
  947.                 Case 2:
  948.                     nx = -x
  949.                     ny = -y
  950.                 Case 3:
  951.                     nx = -y
  952.                     ny = -x
  953.                 Case 4:
  954.                     nx = -x
  955.                     ny = y
  956.                 Case 5:
  957.                     nx = x
  958.                     ny = -y
  959.                 Case 6:
  960.                     nx = y
  961.                     ny = x
  962.                 Case 7:
  963.                     nx = y
  964.                     ny = -x
  965.                 Case Else:
  966.                     nx = x
  967.                     ny = y
  968.             End Select
  969.  
  970.             clr = OldArray(nx, ny, 0).c
  971.  
  972.             y1 = y * shear1
  973.             xy1 = x + y1
  974.             fy = (y - xy1 * shear2)
  975.             fx = xy1 + fy * shear1
  976.  
  977.             If fx >= -16 And fx <= 16 Then
  978.                 If fy >= -16 And fy <= 16 Then
  979.  
  980.                     ' count points that will be overwritten
  981.                     If NewArray(fx, fy, 0).c <> iEmpty Then
  982.                         iOverwriteCount = iOverwriteCount + 1
  983.                     End If
  984.  
  985.                     NewArray(fx, fy, 0).c = clr
  986.                     NewArray(fx, fy, 0).origx = fx
  987.                     NewArray(fx, fy, 0).origy = fy
  988.                 End If
  989.             End If
  990.         Next x
  991.     Next y
  992. End Sub ' ShearRotate1
  993.  
  994. ' /////////////////////////////////////////////////////////////////////////////
  995. ' Tries to fix the problem of 2 points resolving to the same coordinate
  996. ' (one overwrites the other, which becomes "lost")
  997.  
  998. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  999.  
  1000. Sub ShearRotate2 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iMissing As Integer)
  1001.     Const Pi = 4 * Atn(1)
  1002.  
  1003.     Dim angle As Integer
  1004.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  1005.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  1006.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  1007.     Dim x As Integer
  1008.     Dim y As Integer
  1009.     Dim nangle As Integer
  1010.     Dim nx As Integer
  1011.     Dim ny As Integer
  1012.     Dim flipper As Integer
  1013.     Dim rotr As Double
  1014.     Dim shear1 As Double
  1015.     Dim shear2 As Double
  1016.     Dim clr As Integer
  1017.     Dim y1 As _Byte
  1018.     Dim xy1 As _Byte
  1019.     Dim fy As _Byte
  1020.     Dim fx As _Byte
  1021.     Dim in$
  1022.     Dim sLine As String
  1023.     ReDim arrLost(-1) As RotationType
  1024.     Dim iLoop As Integer
  1025.     Dim bFound As Integer
  1026.  
  1027.     ' initialize new with empty
  1028.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  1029.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1030.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1031.             NewArray(x, y, 0).origx = x
  1032.             NewArray(x, y, 0).origy = y
  1033.             NewArray(x, y, 0).c = iEmpty
  1034.         Next y
  1035.     Next x
  1036.  
  1037.     ' angle is reversed
  1038.     angle = 360 - angle1
  1039.  
  1040.     ' Shearing each element 3 times in one shot
  1041.     nangle = angle
  1042.  
  1043.     ' this pre-processing portion basically rotates by 90 to get
  1044.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  1045.     If angle > 45 And angle < 225 Then
  1046.         If angle < 135 Then
  1047.             nangle = angle - 90
  1048.         Else
  1049.             nangle = angle - 180
  1050.         End If
  1051.     End If
  1052.     If angle > 135 And angle < 315 Then
  1053.         If angle < 225 Then
  1054.             nangle = angle - 180
  1055.         Else
  1056.             nangle = angle - 270
  1057.         End If
  1058.     End If
  1059.     If nangle < 0 Then
  1060.         nangle = nangle + 360
  1061.     End If
  1062.     If nangle > 359 Then
  1063.         nangle = nangle - 360
  1064.     End If
  1065.  
  1066.     rotr = nangle * DtoR
  1067.     shear1 = Tan(rotr / 2) ' correct way
  1068.     shear2 = Sin(rotr)
  1069.  
  1070.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  1071.     ' ***       all resolve to -45 degrees.
  1072.     ' ***       Fixed by changing < to <=
  1073.  
  1074.     'if angle >  45 and angle < 134 then
  1075.     If angle > 45 And angle <= 134 Then
  1076.         flipper = 1
  1077.     ElseIf angle > 134 And angle <= 224 Then
  1078.         flipper = 2
  1079.     ElseIf angle > 224 And angle <= 314 Then
  1080.         ' *** NOTE: this had a bug where this flipper was wrong
  1081.         '           Fixed by adding case 7
  1082.         'flipper = 3
  1083.         flipper = 7
  1084.     Else
  1085.         flipper = 0
  1086.     End If
  1087.  
  1088.     ' Here is where it needs some optimizing possibly... kinda slow...
  1089.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1090.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1091.             Select Case flipper
  1092.                 Case 1:
  1093.                     nx = -y
  1094.                     ny = x
  1095.                 Case 2:
  1096.                     nx = -x
  1097.                     ny = -y
  1098.                 Case 3:
  1099.                     nx = -y
  1100.                     ny = -x
  1101.                 Case 4:
  1102.                     nx = -x
  1103.                     ny = y
  1104.                 Case 5:
  1105.                     nx = x
  1106.                     ny = -y
  1107.                 Case 6:
  1108.                     nx = y
  1109.                     ny = x
  1110.                 Case 7:
  1111.                     nx = y
  1112.                     ny = -x
  1113.                 Case Else:
  1114.                     nx = x
  1115.                     ny = y
  1116.             End Select
  1117.  
  1118.             clr = OldArray(nx, ny, 0).c
  1119.  
  1120.             y1 = y * shear1
  1121.             xy1 = x + y1
  1122.             fy = (y - xy1 * shear2)
  1123.             fx = xy1 + fy * shear1
  1124.  
  1125.             If fx >= -16 And fx <= 16 Then
  1126.                 If fy >= -16 And fy <= 16 Then
  1127.                     ' only draw here if this spot is empty
  1128.                     If NewArray(fx, fy, 0).c = iEmpty Then
  1129.                         NewArray(fx, fy, 0).c = clr
  1130.                         NewArray(fx, fy, 0).origx = fx
  1131.                         NewArray(fx, fy, 0).origy = fy
  1132.                     Else
  1133.                         ' don't draw, but save it to a list to handle later
  1134.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  1135.                         arrLost(UBound(arrLost)).c = clr
  1136.                         arrLost(UBound(arrLost)).origx = fx
  1137.                         arrLost(UBound(arrLost)).origy = fy
  1138.                     End If
  1139.                 End If
  1140.             End If
  1141.         Next x
  1142.     Next y
  1143.  
  1144.     ' try to place any points that would have overwritten to a spot nearby
  1145.     ' can nearby be determined by the angle of rotation?
  1146.     ' perhaps if we divide the screen up into 4 zones:
  1147.     '
  1148.     ' --------------------------------------
  1149.     '|                   |                  |
  1150.     '| zone 4            | zone 1           |
  1151.     '| 271-359 degrees)  | (1-89 degrees)   |
  1152.     '|--------------------------------------|
  1153.     '|                   |                  |
  1154.     '| zone 3            | zone 2           |
  1155.     '| (181-269 degrees) | (91-179 degrees) |
  1156.     '|                   |                  |
  1157.     ' --------------------------------------
  1158.  
  1159.     ' in zone   search direction (y,x)
  1160.     ' -------   ----------------------
  1161.     ' 1         up   + right
  1162.     ' 2         down + right
  1163.     ' 3         down + left
  1164.     ' 4         up   + left
  1165.  
  1166.     iMissing = 0
  1167.     For iLoop = 0 To UBound(arrLost)
  1168.         bFound = FindEmptyShearRotationPoint%(arrLost(iLoop), angle1, iEmpty, x, y, NewArray())
  1169.         If bFound = TRUE Then
  1170.             If m_bDebug = TRUE Then
  1171.                 _Echo "Plotted  missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  1172.             End If
  1173.         Else
  1174.             iMissing = iMissing + 1
  1175.             If m_bDebug = TRUE Then
  1176.                 _Echo "Detected missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  1177.             End If
  1178.         End If
  1179.     Next iLoop
  1180.  
  1181. End Sub ' ShearRotate2
  1182.  
  1183. ' /////////////////////////////////////////////////////////////////////////////
  1184. ' Receives
  1185. ' FindMe (RotationType) = contains the starting location (.origx, .origy) to start looking from, and the value (.c) to write
  1186. ' angle1 (Integer) = angle we were rotating to, to determine direction to look in
  1187. ' iEmpty (Integer) = value to test against for empty
  1188. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  1189. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  1190. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  1191.  
  1192. ' Returns
  1193. ' FALSE if no empty spot was found
  1194. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  1195.  
  1196. Function FindEmptyShearRotationPoint% (FindMe As RotationType, angle1 As Integer, iEmpty As Integer, destX As Integer, destY As Integer, NewArray() As RotationType)
  1197.     Dim bResult As Integer: bResult = FALSE
  1198.     Dim x As Integer
  1199.     Dim y As Integer
  1200.     Dim dirX As Integer
  1201.     Dim dirY As Integer
  1202.  
  1203.     destX = 0
  1204.     destY = 0
  1205.  
  1206.     ' Choose search direction depending on the angle
  1207.     If angle1 > 0 And angle1 < 90 Then
  1208.         dirX = 1
  1209.         dirY = -1
  1210.     ElseIf angle1 > 90 And angle1 < 180 Then
  1211.         dirX = 1
  1212.         dirY = 1
  1213.     ElseIf angle1 > 180 And angle1 < 270 Then
  1214.         dirX = -1
  1215.         dirY = 1
  1216.     ElseIf angle1 > 270 And angle1 < 360 Then
  1217.         dirX = -1
  1218.         dirY = -1
  1219.     Else
  1220.         dirX = 0
  1221.         dirY = 0
  1222.     End If
  1223.  
  1224.     If dirX <> 0 Then
  1225.         x = FindMe.origx
  1226.         y = FindMe.origy
  1227.         Do
  1228.             ' quit if we're out of bounds
  1229.             If x < LBound(NewArray, 1) Then Exit Do
  1230.             If x > UBound(NewArray, 1) Then Exit Do
  1231.             If y < LBound(NewArray, 2) Then Exit Do
  1232.             If y > UBound(NewArray, 2) Then Exit Do
  1233.  
  1234.             ' look along y axis for a blank spot
  1235.             destX = x
  1236.             destY = y + dirY
  1237.             If destX >= LBound(NewArray, 1) Then
  1238.                 If destX <= UBound(NewArray, 1) Then
  1239.                     If destY >= LBound(NewArray, 2) Then
  1240.                         If destY <= UBound(NewArray, 2) Then
  1241.                             If NewArray(destX, destY, 0).c = iEmpty Then
  1242.                                 NewArray(destX, destY, 0).c = FindMe.c
  1243.                                 bResult = TRUE
  1244.                                 Exit Do
  1245.                             End If
  1246.                         End If
  1247.                     End If
  1248.                 End If
  1249.             End If
  1250.  
  1251.             ' look along x axis for a blank spot
  1252.             destX = x + dirX
  1253.             destY = y
  1254.             If destX >= LBound(NewArray, 1) Then
  1255.                 If destX <= UBound(NewArray, 1) Then
  1256.                     If destY >= LBound(NewArray, 2) Then
  1257.                         If destY <= UBound(NewArray, 2) Then
  1258.                             If NewArray(x + dirX, y, 0).c = iEmpty Then
  1259.                                 NewArray(destX, destY, 0).c = FindMe.c
  1260.                                 bResult = TRUE
  1261.                                 Exit Do
  1262.                             End If
  1263.                         End If
  1264.                     End If
  1265.                 End If
  1266.             End If
  1267.  
  1268.             ' look diagonally for a blank spot
  1269.             destX = x + dirX
  1270.             destY = y + dirY
  1271.             If destX >= LBound(NewArray, 1) Then
  1272.                 If destX <= UBound(NewArray, 1) Then
  1273.                     If destY >= LBound(NewArray, 2) Then
  1274.                         If destY <= UBound(NewArray, 2) Then
  1275.                             If NewArray(x + dirX, y + dirY, 0).c = iEmpty Then
  1276.                                 NewArray(destX, destY, 0).c = FindMe.c
  1277.                                 bResult = TRUE
  1278.                                 Exit Do
  1279.                             End If
  1280.                         End If
  1281.                     End If
  1282.                 End If
  1283.             End If
  1284.  
  1285.             ' Keep looking
  1286.             x = x + dirX
  1287.             y = y + dirY
  1288.         Loop
  1289.     End If
  1290.  
  1291.     ' Return result
  1292.     FindEmptyShearRotationPoint% = bResult
  1293. End Function ' FindEmptyShearRotationPoint%
  1294.  
  1295. ' /////////////////////////////////////////////////////////////////////////////
  1296.  
  1297. Sub ShearRotateTest1
  1298.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  1299.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  1300.     Dim sMap As String
  1301.     Dim D As Integer
  1302.     Dim in$
  1303.  
  1304.     ' GET A SHAPE TO BE ROTATED
  1305.     Cls
  1306.     Print "3 shear rotation based on code by leopardpm"
  1307.     Print
  1308.  
  1309.     sMap = TestSprite1$
  1310.  
  1311.     ' CONVERT SHAPE TO ARRAY
  1312.     StringToRotationArray RoArray1(), sMap, "."
  1313.     Print "Initial contents of Rotation Array:"
  1314.     Print RotationArrayToStringTest(RoArray1())
  1315.     Print
  1316.  
  1317.     ' ROTATE THE SHAPE
  1318.     Do
  1319.         Print "Type degrees to rotate (0 TO 360) or non-numeric value to quit."
  1320.         Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1321.  
  1322.         Input "Degrees to rotate (q to quit)? "; in$
  1323.         If IsNum%(in$) Then
  1324.             D = Val(in$)
  1325.             If D >= 0 And D <= 360 Then
  1326.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  1327.                 Print
  1328.                 Print "Rotated by " + cstr$(D) + " degrees:"
  1329.                 Print RotationArrayToStringTest(RoArray2())
  1330.                 Print
  1331.             Else
  1332.                 Exit Do
  1333.             End If
  1334.         Else
  1335.             Exit Do
  1336.         End If
  1337.     Loop
  1338. End Sub ' ShearRotateTest1
  1339.  
  1340. ' /////////////////////////////////////////////////////////////////////////////
  1341. ' Now receives parameter sMap
  1342. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  1343.  
  1344. ' e.g. ShearRotateTest2 TestSprite1$
  1345.  
  1346. Sub ShearRotateTest2 (sMap As String)
  1347.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  1348.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  1349.     'Dim sMap As String
  1350.     Dim D As Integer
  1351.     Dim D1 As Integer
  1352.     Dim in$
  1353.     Dim bFinished As Integer
  1354.     Dim iOverwriteCount As Integer
  1355.  
  1356.     ' GET A SHAPE TO BE ROTATED
  1357.     Cls
  1358.     Print "3 shear rotation based on code by leopardpm"
  1359.     'sMap = TestSprite1$
  1360.  
  1361.     ' CONVERT SHAPE TO ARRAY
  1362.     StringToRotationArray RoArray1(), sMap, "."
  1363.  
  1364.     ' GET START ANGLE
  1365.     D = 0
  1366.     Print
  1367.     Print "Rotated by " + cstr$(D) + " degrees:"
  1368.     Print RotationArrayToStringTest(RoArray1())
  1369.     Print
  1370.     Print "Type an angle (-360 to 360) to rotate to, "
  1371.     Print "or blank to increase by 1 degree, or q to quit."
  1372.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1373.     Print "Hold down <ENTER> to rotate continually."
  1374.     Input "Angle (q to quit)? ", in$
  1375.     If Len(in$) > 0 Then
  1376.         If IsNum%(in$) Then
  1377.             D1 = Val(in$)
  1378.         Else
  1379.             D1 = -500
  1380.         End If
  1381.     Else
  1382.         D1 = 1
  1383.     End If
  1384.  
  1385.     ' ROTATE TO EACH ANGLE
  1386.     If D1 >= -360 And D1 <= 360 Then
  1387.         bFinished = FALSE
  1388.         Do
  1389.             ' ROTATE CLOCKWISE
  1390.             For D = D1 To 360
  1391.                 Cls
  1392.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  1393.                 Print
  1394.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  1395.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  1396.  
  1397.                 Print RotationArrayToStringTest(RoArray2())
  1398.                 Print
  1399.  
  1400.                 Print "Type an angle (-360 to 360) to rotate to, "
  1401.                 Print "or blank to increase by 1 degree, or q to quit."
  1402.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1403.                 Print "Hold down <ENTER> to rotate continually."
  1404.                 Input "Angle (q to quit)? ", in$
  1405.                 If Len(in$) > 0 Then
  1406.                     If IsNum%(in$) Then
  1407.                         D = Val(in$)
  1408.                         If D >= 0 And D <= 360 Then
  1409.                             D = D - 1
  1410.                         Else
  1411.                             bFinished = TRUE
  1412.                             Exit For
  1413.                         End If
  1414.                     Else
  1415.                         bFinished = TRUE
  1416.                         Exit For
  1417.                     End If
  1418.                 End If
  1419.             Next D
  1420.             If bFinished = TRUE Then Exit Do
  1421.  
  1422.             ' ROTATE COUNTER-CLOCKWISE
  1423.             For D = 360 To D1 Step -1
  1424.                 Cls
  1425.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  1426.                 Print
  1427.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  1428.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  1429.  
  1430.                 Print RotationArrayToStringTest(RoArray2())
  1431.                 Print
  1432.  
  1433.                 Print "Type an angle (0 to 360) to rotate to, "
  1434.                 Print "or blank to increase by 1 degree, or q to quit."
  1435.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1436.                 Print "Hold down <ENTER> to rotate continually."
  1437.                 Input "Angle (q to quit)? ", in$
  1438.                 If Len(in$) > 0 Then
  1439.                     If IsNum%(in$) Then
  1440.                         D = Val(in$)
  1441.                         If D >= 0 And D <= 360 Then
  1442.                             D = D + 1
  1443.                         Else
  1444.                             bFinished = TRUE
  1445.                             Exit For
  1446.                         End If
  1447.                     Else
  1448.                         bFinished = TRUE
  1449.                         Exit For
  1450.                     End If
  1451.                 End If
  1452.             Next D
  1453.             If bFinished = TRUE Then Exit Do
  1454.         Loop
  1455.     End If
  1456. End Sub ' ShearRotateTest2
  1457.  
  1458. ' /////////////////////////////////////////////////////////////////////////////
  1459. ' Tries to correct for missing points.
  1460.  
  1461. ' Receives parameter sMap
  1462. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  1463.  
  1464. ' e.g. ShearRotateTest3 TestSprite1$
  1465.  
  1466. Sub ShearRotateTest3 (sMap As String)
  1467.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  1468.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  1469.     'Dim sMap As String
  1470.     Dim D As Integer
  1471.     Dim D1 As Integer
  1472.     Dim in$
  1473.     Dim bFinished As Integer
  1474.     Dim iMissing As Integer
  1475.  
  1476.     ' GET A SHAPE TO BE ROTATED
  1477.     Cls
  1478.     Print "3 shear rotation based on code by leopardpm"
  1479.     'sMap = TestSprite1$
  1480.  
  1481.     ' CONVERT SHAPE TO ARRAY
  1482.     StringToRotationArray RoArray1(), sMap, "."
  1483.  
  1484.     ' GET START ANGLE
  1485.     D = 0
  1486.     Print
  1487.     Print "Rotated by " + cstr$(D) + " degrees:"
  1488.     Print RotationArrayToStringTest(RoArray1())
  1489.     Print
  1490.     Print "Type an angle (-360 to 360) to rotate to, "
  1491.     Print "or blank to increase by 1 degree, or q to quit."
  1492.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1493.     Print "Hold down <ENTER> to rotate continually."
  1494.     Input "Angle (q to quit)? ", in$
  1495.     If Len(in$) > 0 Then
  1496.         If IsNum%(in$) Then
  1497.             D1 = Val(in$)
  1498.         Else
  1499.             D1 = -500
  1500.         End If
  1501.     Else
  1502.         D1 = 1
  1503.     End If
  1504.  
  1505.     ' ROTATE TO EACH ANGLE
  1506.     If D1 >= -360 And D1 <= 360 Then
  1507.         bFinished = FALSE
  1508.         Do
  1509.             ' ROTATE CLOCKWISE
  1510.             For D = D1 To 360
  1511.                 Cls
  1512.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  1513.                 Print
  1514.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  1515.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  1516.  
  1517.                 Print RotationArrayToStringTest(RoArray2())
  1518.                 Print
  1519.  
  1520.                 Print "Type an angle (-360 to 360) to rotate to, "
  1521.                 Print "or blank to increase by 1 degree, or q to quit."
  1522.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1523.                 Print "Hold down <ENTER> to rotate continually."
  1524.                 Input "Angle (q to quit)? ", in$
  1525.                 If Len(in$) > 0 Then
  1526.                     If IsNum%(in$) Then
  1527.                         D = Val(in$)
  1528.                         If D >= 0 And D <= 360 Then
  1529.                             D = D - 1
  1530.                         Else
  1531.                             bFinished = TRUE
  1532.                             Exit For
  1533.                         End If
  1534.                     Else
  1535.                         bFinished = TRUE
  1536.                         Exit For
  1537.                     End If
  1538.                 End If
  1539.             Next D
  1540.             If bFinished = TRUE Then Exit Do
  1541.  
  1542.             ' ROTATE COUNTER-CLOCKWISE
  1543.             For D = 360 To D1 Step -1
  1544.                 Cls
  1545.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  1546.                 Print
  1547.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  1548.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  1549.  
  1550.                 Print RotationArrayToStringTest(RoArray2())
  1551.                 Print
  1552.  
  1553.                 Print "Type an angle (0 to 360) to rotate to, "
  1554.                 Print "or blank to increase by 1 degree, or q to quit."
  1555.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1556.                 Print "Hold down <ENTER> to rotate continually."
  1557.                 Input "Angle (q to quit)? ", in$
  1558.                 If Len(in$) > 0 Then
  1559.                     If IsNum%(in$) Then
  1560.                         D = Val(in$)
  1561.                         If D >= 0 And D <= 360 Then
  1562.                             D = D + 1
  1563.                         Else
  1564.                             bFinished = TRUE
  1565.                             Exit For
  1566.                         End If
  1567.                     Else
  1568.                         bFinished = TRUE
  1569.                         Exit For
  1570.                     End If
  1571.                 End If
  1572.             Next D
  1573.             If bFinished = TRUE Then Exit Do
  1574.         Loop
  1575.     End If
  1576. End Sub ' ShearRotateTest3
  1577.  
  1578. ' /////////////////////////////////////////////////////////////////////////////
  1579.  
  1580. Function TestSprite1$
  1581.     Dim m$
  1582.     m$ = ""
  1583.     '                   11111111112222222222333
  1584.     '          12345678901234567890123456789012
  1585.     m$ = m$ + "11111111111111111111111111111111" + Chr$(13) ' 1
  1586.     m$ = m$ + "4..............................2" + Chr$(13) ' 2
  1587.     m$ = m$ + "4....##.....#######.....####...2" + Chr$(13) ' 3
  1588.     m$ = m$ + "4...####....##...###...######..2" + Chr$(13) ' 4
  1589.     m$ = m$ + "4..##..##...##...###..##....##.2" + Chr$(13) ' 5
  1590.     m$ = m$ + "4.##....##..#######...##.......2" + Chr$(13) ' 6
  1591.     m$ = m$ + "4.########..#######...##.......2" + Chr$(13) ' 7
  1592.     m$ = m$ + "4.########..##...###..##....##.2" + Chr$(13) ' 8
  1593.     m$ = m$ + "4.##....##..##...###...######..2" + Chr$(13) ' 9
  1594.     m$ = m$ + "4.##....##..#######.....####...2" + Chr$(13) ' 10
  1595.     m$ = m$ + "4..............................2" + Chr$(13) ' 11
  1596.     m$ = m$ + "4..............................2" + Chr$(13) ' 12
  1597.     m$ = m$ + "4..ABBBBBBBBBBBBBBBBBBBBBBBBC..2" + Chr$(13) ' 13
  1598.     m$ = m$ + "4..A...........EE...........C..2" + Chr$(13) ' 14
  1599.     m$ = m$ + "4..A..........FFFF..........C..2" + Chr$(13) ' 15
  1600.     m$ = m$ + "4..A.........GGGGGG.........C..2" + Chr$(13) ' 16
  1601.     m$ = m$ + "4..A........HHHHHHHH........C..2" + Chr$(13) ' 17
  1602.     m$ = m$ + "4..A.......IIIIIIIIII.......C..2" + Chr$(13) ' 18
  1603.     m$ = m$ + "4..A......JJJJJJJJJJJJ......C..2" + Chr$(13) ' 19
  1604.     m$ = m$ + "4..DDDDDDDDDDDDDDDDDDDDDDDDDC..2" + Chr$(13) ' 20
  1605.     m$ = m$ + "4..............................2" + Chr$(13) ' 21
  1606.     m$ = m$ + "4..............................2" + Chr$(13) ' 22
  1607.     m$ = m$ + "4.######....########..########.2" + Chr$(13) ' 23
  1608.     m$ = m$ + "4.#######...########..########.2" + Chr$(13) ' 24
  1609.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 25
  1610.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 26
  1611.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 27
  1612.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 28
  1613.     m$ = m$ + "4.#######...##........##.......2" + Chr$(13) ' 29
  1614.     m$ = m$ + "4.######....########..##.......2" + Chr$(13) ' 30
  1615.     m$ = m$ + "4..............................2" + Chr$(13) ' 31
  1616.     m$ = m$ + "33333333333333333333333333333332" + Chr$(13) ' 32
  1617.     TestSprite1$ = m$
  1618. End Function ' TestSprite1$
  1619.  
  1620. ' /////////////////////////////////////////////////////////////////////////////
  1621.  
  1622. Function TestSprite2$
  1623.     Dim m$
  1624.     m$ = ""
  1625.     '                   11111111112222222222333
  1626.     '          12345678901234567890123456789012
  1627.     m$ = m$ + "...............AA..............." + Chr$(13) ' 1
  1628.     m$ = m$ + "..............//BB.............." + Chr$(13) ' 2
  1629.     m$ = m$ + ".............??..CC............." + Chr$(13) ' 3
  1630.     m$ = m$ + "............==....DD............" + Chr$(13) ' 4
  1631.     m$ = m$ + "...........++......EE..........." + Chr$(13) ' 5
  1632.     m$ = m$ + "..........&&........FF.........." + Chr$(13) ' 6
  1633.     m$ = m$ + ".........zz..........GG........." + Chr$(13) ' 7
  1634.     m$ = m$ + "........yy............HH........" + Chr$(13) ' 8
  1635.     m$ = m$ + ".......xx..............II......." + Chr$(13) ' 9
  1636.     m$ = m$ + "......ww................JJ......" + Chr$(13) ' 10
  1637.     m$ = m$ + ".....vv..................KK....." + Chr$(13) ' 11
  1638.     m$ = m$ + "....uu....................LL...." + Chr$(13) ' 12
  1639.     m$ = m$ + "...tt......DDAAAAAAA.......MM..." + Chr$(13) ' 13
  1640.     m$ = m$ + "..ss.......DDAAAAAAA........NN.." + Chr$(13) ' 14
  1641.     m$ = m$ + ".rr........DD.....BB.........OO." + Chr$(13) ' 15
  1642.     m$ = m$ + "qq.........DD.....BB..........PP" + Chr$(13) ' 16
  1643.     m$ = m$ + "pp.........DD.....BB..........QQ" + Chr$(13) ' 17
  1644.     m$ = m$ + ".oo........DD.....BB.........RR." + Chr$(13) ' 18
  1645.     m$ = m$ + "..nn.......CCCCCCCBB........SS.." + Chr$(13) ' 19
  1646.     m$ = m$ + "...mm......CCCCCCCBB.......TT..." + Chr$(13) ' 20
  1647.     m$ = m$ + "....ll....................UU...." + Chr$(13) ' 21
  1648.     m$ = m$ + ".....kk..................VV....." + Chr$(13) ' 22
  1649.     m$ = m$ + "......jj................WW......" + Chr$(13) ' 23
  1650.     m$ = m$ + ".......ii..............XX......." + Chr$(13) ' 24
  1651.     m$ = m$ + "........hh............YY........" + Chr$(13) ' 25
  1652.     m$ = m$ + ".........gg..........ZZ........." + Chr$(13) ' 26
  1653.     m$ = m$ + "..........ff........@@.........." + Chr$(13) ' 27
  1654.     m$ = m$ + "...........ee......##..........." + Chr$(13) ' 28
  1655.     m$ = m$ + "............dd....$$............" + Chr$(13) ' 29
  1656.     m$ = m$ + ".............cc..%%............." + Chr$(13) ' 30
  1657.     m$ = m$ + "..............bb\\.............." + Chr$(13) ' 31
  1658.     m$ = m$ + "...............aa..............." + Chr$(13) ' 32
  1659.     TestSprite2$ = m$
  1660. End Function ' TestSprite2$
  1661.  
  1662. ' /////////////////////////////////////////////////////////////////////////////
  1663.  
  1664. Function PetrText1$
  1665.     Dim m$
  1666.     m$ = ""
  1667.     '                   11111111112222222222333
  1668.     '          12345678901234567890123456789012
  1669.     m$ = m$ + "................................" + Chr$(13) ' 1
  1670.     m$ = m$ + "................................" + Chr$(13) ' 2
  1671.     m$ = m$ + "................................" + Chr$(13) ' 3
  1672.     m$ = m$ + "................................" + Chr$(13) ' 4
  1673.     m$ = m$ + "................................" + Chr$(13) ' 5
  1674.     m$ = m$ + "................................" + Chr$(13) ' 6
  1675.     m$ = m$ + "................................" + Chr$(13) ' 7
  1676.     m$ = m$ + "................................" + Chr$(13) ' 8
  1677.     m$ = m$ + "................................" + Chr$(13) ' 9
  1678.     m$ = m$ + "................................" + Chr$(13) ' 10
  1679.     m$ = m$ + "................................" + Chr$(13) ' 11
  1680.     m$ = m$ + "................................" + Chr$(13) ' 12
  1681.     m$ = m$ + "................................" + Chr$(13) ' 13
  1682.     m$ = m$ + "................................" + Chr$(13) ' 14
  1683.     m$ = m$ + "....It's a SCREEN resolution?..." + Chr$(13) ' 15
  1684.     m$ = m$ + "................................" + Chr$(13) ' 16
  1685.     m$ = m$ + "................................" + Chr$(13) ' 17
  1686.     m$ = m$ + "................................" + Chr$(13) ' 18
  1687.     m$ = m$ + "................................" + Chr$(13) ' 19
  1688.     m$ = m$ + "................................" + Chr$(13) ' 20
  1689.     m$ = m$ + "................................" + Chr$(13) ' 21
  1690.     m$ = m$ + "................................" + Chr$(13) ' 22
  1691.     m$ = m$ + "................................" + Chr$(13) ' 23
  1692.     m$ = m$ + "................................" + Chr$(13) ' 24
  1693.     m$ = m$ + "................................" + Chr$(13) ' 25
  1694.     m$ = m$ + "................................" + Chr$(13) ' 26
  1695.     m$ = m$ + "................................" + Chr$(13) ' 27
  1696.     m$ = m$ + "................................" + Chr$(13) ' 28
  1697.     m$ = m$ + "................................" + Chr$(13) ' 29
  1698.     m$ = m$ + "................................" + Chr$(13) ' 30
  1699.     m$ = m$ + "................................" + Chr$(13) ' 31
  1700.     m$ = m$ + "................................" + Chr$(13) ' 32
  1701.     PetrText1$ = m$
  1702. End Function ' PetrText1$
  1703.  
  1704. ' /////////////////////////////////////////////////////////////////////////////
  1705.  
  1706. Function ArrayToString$ (MyArray( 1 To 32 , 1 To 32) As String)
  1707.     Dim MyString As String
  1708.     Dim iY As Integer
  1709.     Dim iX As Integer
  1710.     Dim sLine As String
  1711.     MyString = ""
  1712.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  1713.         sLine = ""
  1714.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  1715.             sLine = sLine + MyArray(iY, iX)
  1716.         Next iX
  1717.         MyString = MyString + sLine + Chr$(13)
  1718.     Next iY
  1719.     ArrayToString$ = MyString
  1720. End Function ' ArrayToString$
  1721.  
  1722. ' /////////////////////////////////////////////////////////////////////////////
  1723.  
  1724. Function ArrayToStringTest$ (MyArray() As String)
  1725.     Dim MyString As String
  1726.     Dim iY As Integer
  1727.     Dim iX As Integer
  1728.     Dim sLine As String
  1729.     MyString = ""
  1730.  
  1731.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  1732.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  1733.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  1734.         sLine = ""
  1735.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  1736.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  1737.             sLine = sLine + MyArray(iY, iX)
  1738.         Next iX
  1739.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  1740.         MyString = MyString + sLine + Chr$(13)
  1741.     Next iY
  1742.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  1743.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  1744.     ArrayToStringTest$ = MyString
  1745. End Function ' ArrayToStringTest$
  1746.  
  1747. ' /////////////////////////////////////////////////////////////////////////////
  1748.  
  1749. Function RotationArrayToStringTest$ (RoArray() As RotationType)
  1750.     Dim MyString As String
  1751.     Dim iY As Integer
  1752.     Dim iX As Integer
  1753.     Dim sLine As String
  1754.     MyString = ""
  1755.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  1756.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  1757.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  1758.     For iY = LBound(RoArray, 1) To UBound(RoArray, 1)
  1759.         sLine = ""
  1760.         sLine = sLine + Right$("    " + cstr$(iY), 3)
  1761.         For iX = LBound(RoArray, 2) To UBound(RoArray, 2)
  1762.             sLine = sLine + Chr$(RoArray(iX, iY, 0).c)
  1763.         Next iX
  1764.         sLine = sLine + Right$("   " + cstr$(iY), 3)
  1765.         MyString = MyString + sLine + Chr$(13)
  1766.     Next iY
  1767.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  1768.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  1769.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  1770.     RotationArrayToStringTest$ = MyString
  1771. End Function ' RotationArrayToStringTest$
  1772.  
  1773. ' /////////////////////////////////////////////////////////////////////////////
  1774. ' 1. split string by line breaks CHR$(13)
  1775. ' 2. split lines up to 1 column per char
  1776. ' 3. count rows, columns
  1777. ' 4. DIM array, making sure array has
  1778. '    a) an _ODD_ number of rows/columns, with a center point
  1779. '    b) index is in cartesian format, where center is (0,0)
  1780. ' 5. populate array with contents of string
  1781.  
  1782. ' dimension #1 = columns
  1783. ' dimension #2 = rows
  1784.  
  1785. Sub StringToRotationArray (RoArray() As RotationType, MyString As String, EmptyChar As String)
  1786.     Dim RoutineName As String: RoutineName = "StringToRotationArray"
  1787.     ReDim arrLines$(0)
  1788.     Dim delim$
  1789.     Dim iRow%
  1790.     Dim iCol%
  1791.     Dim sChar$
  1792.     Dim iColCount As Integer
  1793.     Dim iRowCount As Integer
  1794.     Dim iCount As Integer
  1795.     Dim bAddedRow As Integer: bAddedRow = FALSE
  1796.     Dim bAddedColumn As Integer: bAddedColumn = FALSE
  1797.     Dim iHalf1 As Integer
  1798.     Dim iHalf2 As Integer
  1799.     Dim iFrom1 As Integer
  1800.     Dim iFrom2 As Integer
  1801.     Dim iTo1 As Integer
  1802.     Dim iTo2 As Integer
  1803.     Dim iEmpty As Integer
  1804.     Dim iX As Integer
  1805.     Dim iY As Integer
  1806.  
  1807.     delim$ = Chr$(13)
  1808.     split MyString, delim$, arrLines$()
  1809.  
  1810.     iRowCount = UBound(arrLines$) + 1
  1811.  
  1812.     ' look at all the rows and find the max # of columns used
  1813.     iColCount = 0
  1814.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  1815.  
  1816.         ' count the columns for this row
  1817.         iCount = 0
  1818.         For iCol% = 1 To Len(arrLines$(iRow%))
  1819.             iCount = iCount + 1
  1820.         Next iCol%
  1821.  
  1822.         ' if this row has the most so far, then set that to the max
  1823.         If iCount > iColCount Then
  1824.             iColCount = iCount
  1825.         End If
  1826.     Next iRow%
  1827.  
  1828.     ' adjust columns to be odd
  1829.     If IsEven%(iColCount) Then
  1830.         iColCount = iColCount + 1
  1831.         bAddedColumn = TRUE
  1832.     End If
  1833.  
  1834.     ' calculate array bounds for columns
  1835.     iHalf1 = (iColCount - 1) / 2
  1836.     iFrom1 = 0 - iHalf1
  1837.     iTo1 = iHalf1
  1838.  
  1839.     ' adjust rows to be odd
  1840.     If IsEven%(iRowCount) Then
  1841.         iRowCount = iRowCount + 1
  1842.         bAddedRow = TRUE
  1843.     End If
  1844.  
  1845.     ' calculate array bounds for rows
  1846.     iHalf2 = (iRowCount - 1) / 2
  1847.     iFrom2 = 0 - iHalf2
  1848.     iTo2 = iHalf2
  1849.  
  1850.     ' size array to new bounds
  1851.     ReDim RoArray(iFrom1 To iTo1, iFrom2 To iTo2, 127) As RotationType
  1852.  
  1853.     ' get value for empty
  1854.     If Len(EmptyChar) > 0 Then
  1855.         iEmpty = Asc(EmptyChar)
  1856.     Else
  1857.         iEmpty = 32 ' (use space as default)
  1858.     End If
  1859.  
  1860.     ' clear array
  1861.     For iY = LBound(RoArray, 2) To UBound(RoArray, 2)
  1862.         For iX = LBound(RoArray, 1) To UBound(RoArray, 1)
  1863.             RoArray(iX, iY, 0).c = iEmpty
  1864.             RoArray(iX, iY, 0).origx = iX
  1865.             RoArray(iX, iY, 0).origy = iY
  1866.         Next iX
  1867.     Next iY
  1868.  
  1869.     ' fill array
  1870.     iY = LBound(RoArray, 2) - 1
  1871.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  1872.         iY = iY + 1
  1873.         iX = LBound(RoArray, 1) - 1
  1874.         For iCol% = 1 To Len(arrLines$(iRow%))
  1875.             iX = iX + 1
  1876.             sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  1877.             RoArray(iX, iY, 0).c = Asc(sChar$)
  1878.         Next iCol%
  1879.     Next iRow%
  1880.  
  1881. End Sub ' StringToRotationArray
  1882.  
  1883. ' /////////////////////////////////////////////////////////////////////////////
  1884.  
  1885. Sub StringToArray (MyArray() As String, MyString As String)
  1886.     Dim delim$
  1887.     ReDim arrLines$(0)
  1888.     Dim iRow%
  1889.     Dim iCol%
  1890.     Dim sChar$
  1891.     Dim iDim1 As Integer
  1892.     Dim iDim2 As Integer
  1893.     iDim1 = LBound(MyArray, 1)
  1894.     iDim2 = LBound(MyArray, 2)
  1895.     delim$ = Chr$(13)
  1896.     split MyString, delim$, arrLines$()
  1897.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  1898.         If iRow% <= UBound(MyArray, 2) Then
  1899.             For iCol% = 1 To Len(arrLines$(iRow%))
  1900.                 If iCol% <= UBound(MyArray, 1) Then
  1901.                     sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  1902.  
  1903.                     If Len(sChar$) > 1 Then
  1904.                         sChar$ = Left$(sChar$, 1)
  1905.                     Else
  1906.                         If Len(sChar$) = 0 Then
  1907.                             sChar$ = "."
  1908.                         End If
  1909.                     End If
  1910.                     MyArray(iRow% + iDim1, (iCol% - 1) + iDim2) = sChar$
  1911.                 Else
  1912.                     ' Exit if out of bounds
  1913.                     Exit For
  1914.                 End If
  1915.             Next iCol%
  1916.         Else
  1917.             ' Exit if out of bounds
  1918.             Exit For
  1919.         End If
  1920.     Next iRow%
  1921. End Sub ' StringToArray
  1922.  
  1923. ' /////////////////////////////////////////////////////////////////////////////
  1924.  
  1925. 'SUB ClearArray (MyArray(1 To 32, 1 To 32) AS STRING, MyString As String)
  1926. Sub ClearArray (MyArray() As String, MyString As String)
  1927.     Dim iRow As Integer
  1928.     Dim iCol As Integer
  1929.     Dim sChar$
  1930.     If Len(MyString) = 1 Then
  1931.         sChar$ = MyString
  1932.     Else
  1933.         If Len(MyString) = 0 Then
  1934.             sChar$ = " "
  1935.         Else
  1936.             sChar$ = Left$(MyString, 1)
  1937.         End If
  1938.     End If
  1939.     For iRow = LBound(MyArray, 1) To UBound(MyArray, 1)
  1940.         For iCol = LBound(MyArray, 2) To UBound(MyArray, 2)
  1941.             MyArray(iRow, iCol) = sChar$
  1942.         Next iCol
  1943.     Next iRow
  1944. End Sub ' ClearArray
  1945.  
  1946. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1947. ' BEGIN GENERAL PURPOSE ROUTINES
  1948. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  1949.  
  1950. ' /////////////////////////////////////////////////////////////////////////////
  1951.  
  1952. Function cstr$ (myValue)
  1953.     'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
  1954.     cstr$ = _Trim$(Str$(myValue))
  1955. End Function ' cstr$
  1956.  
  1957. Function cstrl$ (myValue As Long)
  1958.     cstrl$ = _Trim$(Str$(myValue))
  1959. End Function ' cstrl$
  1960.  
  1961. ' /////////////////////////////////////////////////////////////////////////////
  1962.  
  1963. Function IIF (Condition, IfTrue, IfFalse)
  1964.     If Condition Then IIF = IfTrue Else IIF = IfFalse
  1965.  
  1966. ' /////////////////////////////////////////////////////////////////////////////
  1967.  
  1968. Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
  1969.     If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
  1970.  
  1971. ' /////////////////////////////////////////////////////////////////////////////
  1972. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  1973.  
  1974. Function IsEven% (n)
  1975.     If n Mod 2 = 0 Then
  1976.         IsEven% = TRUE
  1977.     Else
  1978.         IsEven% = FALSE
  1979.     End If
  1980. End Function ' IsEven%
  1981.  
  1982. ' /////////////////////////////////////////////////////////////////////////////
  1983. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  1984.  
  1985. Function IsOdd% (n)
  1986.     If n Mod 2 = 1 Then
  1987.         IsOdd% = TRUE
  1988.     Else
  1989.         IsOdd% = FALSE
  1990.     End If
  1991. End Function ' IsOdd%
  1992.  
  1993. ' /////////////////////////////////////////////////////////////////////////////
  1994. ' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0
  1995.  
  1996. Function IsNum% (text$)
  1997.     Dim a$
  1998.     Dim b$
  1999.     a$ = _Trim$(text$)
  2000.     b$ = _Trim$(Str$(Val(text$)))
  2001.     If a$ = b$ Then
  2002.         IsNum% = TRUE
  2003.     Else
  2004.         IsNum% = FALSE
  2005.     End If
  2006. End Function ' IsNum%
  2007.  
  2008. ' /////////////////////////////////////////////////////////////////////////////
  2009. ' Split and join strings
  2010. ' https://www.qb64.org/forum/index.php?topic=1073.0
  2011.  
  2012. 'Combine all elements of in$() into a single string with delimiter$ separating the elements.
  2013.  
  2014. Function join$ (in$(), delimiter$)
  2015.     result$ = in$(LBound(in$))
  2016.     For i = LBound(in$) + 1 To UBound(in$)
  2017.         result$ = result$ + delimiter$ + in$(i)
  2018.     Next i
  2019.     join$ = result$
  2020. End Function ' join$
  2021.  
  2022. ' /////////////////////////////////////////////////////////////////////////////
  2023. ' FROM: String Manipulation
  2024. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index_topic_5964-0/
  2025. '
  2026. 'SUMMARY:
  2027. '   Purpose:  A library of custom functions that transform strings.
  2028. '   Author:   Dustinian Camburides (dustinian@gmail.com)
  2029. '   Platform: QB64 (www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there])
  2030. '   Revision: 1.6
  2031. '   Updated:  5/28/2012
  2032.  
  2033. 'SUMMARY:
  2034. '[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
  2035. 'INPUT:
  2036. 'Text: The input string; the text that's being manipulated.
  2037. 'Find: The specified sub-string; the string sought within the [Text] string.
  2038. 'Add: The sub-string that's being added to the [Text] string.
  2039.  
  2040. Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
  2041.     ' VARIABLES:
  2042.     Dim Text2 As String
  2043.     Dim Find2 As String
  2044.     Dim Add2 As String
  2045.     Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
  2046.     Dim strBefore As String ' The characters before the string to be replaced.
  2047.     Dim strAfter As String ' The characters after the string to be replaced.
  2048.  
  2049.     ' INITIALIZE:
  2050.     ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
  2051.     Text2 = Text1
  2052.     Find2 = Find1
  2053.     Add2 = Add1
  2054.  
  2055.     lngLocation = InStr(1, Text2, Find2)
  2056.  
  2057.     ' PROCESSING:
  2058.     ' While [Find2] appears in [Text2]...
  2059.     While lngLocation
  2060.         ' Extract all Text2 before the [Find2] substring:
  2061.         strBefore = Left$(Text2, lngLocation - 1)
  2062.  
  2063.         ' Extract all text after the [Find2] substring:
  2064.         strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
  2065.  
  2066.         ' Return the substring:
  2067.         Text2 = strBefore + Add2 + strAfter
  2068.  
  2069.         ' Locate the next instance of [Find2]:
  2070.         lngLocation = InStr(1, Text2, Find2)
  2071.  
  2072.         ' Next instance of [Find2]...
  2073.     Wend
  2074.  
  2075.     ' OUTPUT:
  2076.     Replace$ = Text2
  2077. End Function ' Replace$
  2078.  
  2079. ' /////////////////////////////////////////////////////////////////////////////
  2080. ' Split and join strings
  2081. ' https://www.qb64.org/forum/index.php?topic=1073.0
  2082. '
  2083. ' FROM luke, QB64 Developer
  2084. ' Date: February 15, 2019, 04:11:07 AM »
  2085. '
  2086. ' Given a string of words separated by spaces (or any other character),
  2087. ' splits it into an array of the words. I've no doubt many people have
  2088. ' written a version of this over the years and no doubt there's a million
  2089. ' ways to do it, but I thought I'd put mine here so we have at least one
  2090. ' version. There's also a join function that does the opposite
  2091. ' array -> single string.
  2092. '
  2093. ' Code is hopefully reasonably self explanatory with comments and a little demo.
  2094. ' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.
  2095.  
  2096. 'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
  2097. 'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
  2098. '
  2099. 'delimiter$ must be one character long.
  2100. 'result$() must have been REDIMmed previously.
  2101.  
  2102. Sub split (in$, delimiter$, result$())
  2103.     ReDim result$(-1)
  2104.     start = 1
  2105.     Do
  2106.         While Mid$(in$, start, 1) = delimiter$
  2107.             start = start + 1
  2108.             If start > Len(in$) Then Exit Sub
  2109.         Wend
  2110.         finish = InStr(start, in$, delimiter$)
  2111.         If finish = 0 Then finish = Len(in$) + 1
  2112.         ReDim _Preserve result$(0 To UBound(result$) + 1)
  2113.         result$(UBound(result$)) = Mid$(in$, start, finish - start)
  2114.         start = finish + 1
  2115.     Loop While start <= Len(in$)
  2116. End Sub ' split
  2117.  
  2118. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2119. ' END GENERAL PURPOSE ROUTINES
  2120. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2121.  
  2122. ' #END
  2123. ' ################################################################################################################################################################
  2124.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: STxAxTIC on December 22, 2021, 09:56:04 pm
Hello,

So I played with this a little bit last night, and then deleted my response because I hated it. I hate it a little less today so lemme give this a try... So consider a problematic angle like 30 degrees. Of course the argument applies for all the bad angles, but let me just use 30 for a second.

To get a good view for 30, calculate the view for the two neighboring angles, namely 29 and 31. Also of course calculate what the view at 30 *should* be - the skeletal, bony snapshot of your image. To hang meat on those bones, we can borrow from 29 and 31. First you can run a check to see at which points 29 and 31 overlap. With that info, you can certainly lay those shared points over your view of 30. Basically you've done the binary AND of 29 an 31. Feel* me? If so, in this lingo, you can also do the OR of 29 and 31 to get more points to send to 30. Of course if you just use a pure OR, then the view of 30 will just be the blurred sum of 29 and 31. You want to avoid that, and there are a number of ways to proceed, but...

Tell me if this ballpark feels right. It should do better than a pathfinding-like solution. If it's too much work, then what you've got should basically work but it might add weird fuzz where you dont want it.

Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 23, 2021, 12:12:17 pm
So I played with this a little bit last night, and then deleted my response because I hated it. I hate it a little less today so lemme give this a try...

What's to hate?  You're just thinking through the problem, it's fine. Thanks for your response!

So consider a problematic angle like 30 degrees. Of course the argument applies for all the bad angles, but let me just use 30 for a second.

To get a good view for 30, calculate the view for the two neighboring angles, namely 29 and 31. Also of course calculate what the view at 30 *should* be - the skeletal, bony snapshot of your image. To hang meat on those bones, we can borrow from 29 and 31.

First you can run a check to see at which points 29 and 31 overlap. With that info, you can certainly lay those shared points over your view of 30. Basically you've done the binary AND of 29 an 31. Fee me?

Interesting approach...

If so, in this lingo, you can also do the OR of 29 and 31 to get more points to send to 30. Of course if you just use a pure OR, then the view of 30 will just be the blurred sum of 29 and 31. You want to avoid that, and there are a number of ways to proceed, but...

This is where it gets fuzzy... What ways might you suggest to avoid just getting the blurred sum of 29 and 31?

Tell me if this ballpark feels right. It should do better than a pathfinding-like solution. If it's too much work, then what you've got should basically work but it might add weird fuzz where you dont want it.

Your idea definitely has me thinking. The pathfinding version I posted could definitely be made smarter.

There are 2 questions here -
1. how can we get it to render a more accurate result, and
2. how can we do it more efficiently and save processing cycles?

Thanks again for your response and the interesting ideas!
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 23, 2021, 12:17:36 pm
@Petr and @STxAxTIC

Here is the latest code, I just added in circle fill and ellipse routines by @SMcNeill and @bplus.
I want to add a "fill" routine too, which I have not ever tried before.
I saw this thread that might provide the method
https://qb64forum.alephc.xyz//index.php?topic=1914.0 (https://qb64forum.alephc.xyz//index.php?topic=1914.0)

Anyway, here is the latest version...

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. ' -----------------------------------------------------------------------------
  18. ' USER DEFINED TYPES
  19. ' -----------------------------------------------------------------------------
  20. Type RotationType
  21.     origx As Integer
  22.     origy As Integer
  23.     'z as integer
  24.     c As Integer
  25. End Type ' RotationType
  26.  
  27. ' -----------------------------------------------------------------------------
  28. ' GLOBAL VARIABLES
  29. ' -----------------------------------------------------------------------------
  30. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  31. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  32. Dim Shared m_bDebug: m_bDebug = TRUE
  33.  
  34. ' =============================================================================
  35. ' BEGIN MAIN PROGRAM
  36. ' =============================================================================
  37. Dim in$
  38.  
  39. ' ****************************************************************************************************************************************************************
  40. ' ACTIVATE DEBUGGING WINDOW
  41. If m_bDebug = TRUE Then
  42.     $Console
  43.     _Delay 4
  44.     _Console On
  45.     _Echo "Started " + m_ProgramName$
  46.     _Echo "Debugging on..."
  47. ' ****************************************************************************************************************************************************************
  48.  
  49. ' -----------------------------------------------------------------------------
  50. ' START THE MENU
  51. main
  52.  
  53. ' -----------------------------------------------------------------------------
  54. ' DONE
  55. Print m_ProgramName$ + " finished."
  56. 'Screen 0
  57. Input "Press <ENTER> to continue", in$
  58.  
  59. ' ****************************************************************************************************************************************************************
  60. ' DEACTIVATE DEBUGGING WINDOW
  61. If m_bDebug = TRUE Then
  62. ' ****************************************************************************************************************************************************************
  63.  
  64. ' -----------------------------------------------------------------------------
  65. ' EXIT
  66. System ' return control to the operating system
  67.  
  68. ' =============================================================================
  69. ' END MAIN PROGRAM
  70. ' =============================================================================
  71.  
  72. ' /////////////////////////////////////////////////////////////////////////////
  73. ' MAIN MENU
  74.  
  75. Sub main
  76.     Dim RoutineName As String: RoutineName = "main"
  77.     Dim in$
  78.  
  79.     Screen _NewImage(1280, 1024, 32): _ScreenMove 0, 0
  80.     Do
  81.         Cls
  82.         Print m_ProgramName$
  83.         Print
  84.         Print "Some basic 2D plotting"
  85.         Print
  86.         Print " 1. PlotPointTest"
  87.         Print " 2. PlotSquareTest"
  88.         Print " 3. PlotCircleTest"
  89.         Print " 4. CircleFillTest"
  90.         Print " 5. EllipseTest"
  91.         Print " 6. EllipseFillTest"
  92.         Print " 7. PlotLineTest"
  93.         Print " 8. ShearRotateTest1"
  94.         Print " 9. ShearRotateTest2 (auto advances 0-360 degrees)"
  95.         Print "10. ShearRotateTest2 (auto advances 0-360 degrees) (uses Petr's text)"
  96.         Print "11. ShearRotateTest3 (tries to correct for missing points)"
  97.         Print "12. ShearRotateTest3 (tries to correct for missing points) (uses Petr's text)"
  98.         Print
  99.         Print "What to do? ('q' to exit)"
  100.  
  101.         Input in$: in$ = LCase$(_Trim$(in$))
  102.  
  103.         If in$ = "1" Then
  104.             PlotPointTest
  105.         ElseIf in$ = "2" Then
  106.             PlotSquareTest
  107.         ElseIf in$ = "3" Then
  108.             PlotCircleTest
  109.         ElseIf in$ = "4" Then
  110.             CircleFillTest
  111.         ElseIf in$ = "5" Then
  112.             EllipseTest
  113.         ElseIf in$ = "6" Then
  114.             EllipseFillTest
  115.         ElseIf in$ = "7" Then
  116.             PlotLineTest
  117.         ElseIf in$ = "8" Then
  118.             ShearRotateTest1
  119.         ElseIf in$ = "9" Then
  120.             ShearRotateTest2 TestSprite1$
  121.         ElseIf in$ = "10" Then
  122.             ShearRotateTest2 PetrText1$
  123.         ElseIf in$ = "11" Then
  124.             ShearRotateTest3 TestSprite1$
  125.         ElseIf in$ = "12" Then
  126.             ShearRotateTest3 PetrText1$
  127.         End If
  128.     Loop Until in$ = "q"
  129. End Sub ' main
  130.  
  131. ' /////////////////////////////////////////////////////////////////////////////
  132. ' MyArray(1 To 32, 1 To 32) AS STRING
  133.  
  134. Sub PlotPoint (X As Integer, Y As Integer, S As String, MyArray() As String)
  135.     If (X >= LBound(MyArray, 2)) Then
  136.         If (X <= UBound(MyArray, 2)) Then
  137.             If (Y >= LBound(MyArray, 1)) Then
  138.                 If (Y <= UBound(MyArray, 1)) Then
  139.                     If Len(S) = 1 Then
  140.                         MyArray(Y, X) = S
  141.                     Else
  142.                         If Len(S) > 1 Then
  143.                             MyArray(Y, X) = Left$(S, 1)
  144.                         End If
  145.                     End If
  146.                 End If
  147.             End If
  148.         End If
  149.     End If
  150. End Sub ' PlotPoint
  151.  
  152. ' /////////////////////////////////////////////////////////////////////////////
  153.  
  154. Sub PlotPointTest
  155.     Dim MyArray(1 To 32, 1 To 32) As String
  156.     Dim iX As Integer
  157.     Dim iY As Integer
  158.     Dim in$
  159.     Dim X As Integer
  160.     Dim Y As Integer
  161.     Dim L As Integer
  162.     Dim iChar As Integer
  163.  
  164.     ClearArray MyArray(), "."
  165.     iChar = 64
  166.  
  167.     Cls
  168.     Print "Plot a point."
  169.     Print ArrayToStringTest(MyArray())
  170.     Print
  171.  
  172.     Do
  173.         Print "Type x,y (1-32, 1-32) coordinate to plot point at."
  174.         Input "X,Y OR 0 TO QUIT? "; X, Y
  175.         If X > 0 And Y > 0 Then
  176.             iChar = iChar + 1
  177.             If iChar > 90 Then iChar = 65
  178.  
  179.             Print "X=" + cstr$(X) + ", Y=" + cstr$(Y)
  180.             PlotPoint X, Y, Chr$(iChar), MyArray()
  181.  
  182.             Print "Current point plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  183.             Print ArrayToStringTest(MyArray())
  184.             Print
  185.  
  186.         Else
  187.             Exit Do
  188.         End If
  189.     Loop
  190. End Sub ' PlotPointTest
  191.  
  192. ' /////////////////////////////////////////////////////////////////////////////
  193.  
  194. Sub PlotSquare (X1 As Integer, Y1 As Integer, L As Integer, S As String, MyArray() As String)
  195.     Dim X As Integer
  196.     Dim X2 As Integer
  197.     Dim Y As Integer
  198.     Dim Y2 As Integer
  199.     Dim sChar$
  200.  
  201.     If Len(S) = 1 Then
  202.         sChar$ = S
  203.     Else
  204.         If Len(S) = 0 Then
  205.             sChar$ = " "
  206.         Else
  207.             sChar$ = Left$(S, 1)
  208.         End If
  209.     End If
  210.  
  211.     X2 = (X1 + L) - 1
  212.     Y2 = (Y1 + L) - 1
  213.     For X = X1 To X2
  214.         For Y = Y1 To Y2
  215.             PlotPoint X, Y, sChar$, MyArray()
  216.         Next Y
  217.     Next X
  218. End Sub ' PlotSquare
  219.  
  220. ' /////////////////////////////////////////////////////////////////////////////
  221.  
  222. Sub PlotSquareTest
  223.     Dim MyArray(1 To 32, 1 To 32) As String
  224.     Dim iX As Integer
  225.     Dim iY As Integer
  226.     Dim in$
  227.     Dim X As Integer
  228.     Dim Y As Integer
  229.     Dim L As Integer
  230.     Dim iChar As Integer
  231.  
  232.     ClearArray MyArray(), "."
  233.     iChar = 64
  234.  
  235.     Cls
  236.     Print "Enter parameters to draw a square."
  237.     Print ArrayToStringTest(MyArray())
  238.     Print
  239.     Do
  240.         Print "Type top left x,y (1-32, 1-32) coordinate to plot square,"
  241.         Print "and size (1-32) of square."
  242.         Input "X,Y,L OR 0 TO QUIT? "; X, Y, L
  243.         If X > 0 And Y > 0 And L > 0 Then
  244.             iChar = iChar + 1
  245.             If iChar > 90 Then iChar = 65
  246.  
  247.             Print
  248.             Print "X=" + cstr$(X)
  249.             Print "Y=" + cstr$(Y)
  250.             Print "L=" + cstr$(L)
  251.             Print
  252.             PlotSquare X, Y, L, Chr$(iChar), MyArray()
  253.  
  254.             Print "Square plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  255.             Print ArrayToStringTest(MyArray())
  256.             Print
  257.         Else
  258.             Exit Do
  259.         End If
  260.     Loop
  261. End Sub ' PlotSquareTest
  262.  
  263. ' /////////////////////////////////////////////////////////////////////////////
  264. ' Fast circle drawing in pure Atari BASIC#
  265. ' https://atariwiki.org/wiki/Wiki.jsp?page=Super%20fast%20circle%20routine
  266.  
  267. ' * Magazine: Moj Mikro, 1989/3
  268. ' * Author : Zlatko Bleha
  269. ' * Page : 27 - 31
  270. ' * Atari BASIC listing on disk (tokenized): M8903282.BAS
  271. ' * Atari BASIC listing (listed): M8903282.LST
  272.  
  273. ' Next example is demonstration of implementing mentioned circle algorithm
  274. ' in pure Atari BASIC. This program shows how much faster it is compared to
  275. ' classic program using sine and cosine functions from Atari BASIC
  276. ' (shown in last example).
  277.  
  278. ' Basic Listing M8903282.LST#
  279. '1 REM *******************************
  280. '2 REM PROGRAM  : FAST CIRCLE DRAWING
  281. '3 REM AUTHOR   : ZLATKO BLEHA
  282. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  283. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  284. '6 REM *******************************
  285. '7 REM
  286. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  287. '20 PRINT "ENTER X, Y AND R"
  288. '30 INPUT X,Y,R
  289. '40 IF R=0 THEN PLOT X,Y:END
  290. '50 B=R:C=0:A=R-1
  291. '60 PLOT X+C,Y+B
  292. '70 PLOT X+C,Y-B
  293. '80 PLOT X-C,Y-B
  294. '90 PLOT X-C,Y+B
  295. '100 PLOT X+B,Y+C
  296. '110 PLOT X+B,Y-C
  297. '120 PLOT X-B,Y-C
  298. '130 PLOT X-B,Y+C
  299. '140 C=C+1
  300. '150 A=A+1-C-C
  301. '160 IF A>=0 THEN 190
  302. '170 B=B-1
  303. '180 A=A+B+B
  304. '190 IF B>=C THEN 60
  305.  
  306. ' Use some valid values for coordinates and radius, for example:
  307. ' X=40, Y=40, R=30
  308. ' X=130, Y=90, R=60
  309. ' Slow circle drawing in Atari BASIC#
  310. ' * Magazine: Moj Mikro, 1989/3
  311. ' * Author : Zlatko Bleha
  312. ' * Page : 27 - 31
  313. ' * Atari BASIC listing on disk (tokenized): M8903281.BAS
  314. ' * Atari BASIC listing (listed): M8903281.LST
  315.  
  316. ' This is classic example for drawing circles from Atari BASIC
  317. ' using sine and cosine functions. Unfortunatelly, this is very slow
  318. ' way of doing it and not recommended.
  319. ' Just use routine shown above and everybody will be happy
  320.  
  321. ' Basic Listing M8903281.LST#
  322. '1 REM *******************************
  323. '2 REM PROGRAM  : SLOW CIRCLE DRAWING
  324. '3 REM AUTHOR   : ZLATKO BLEHA
  325. '4 REM PUBLISHER: MOJ MIKRO MAGAZINE
  326. '5 REM ISSUE NO.: 1989, NO.3, PAGE 29
  327. '6 REM *******************************
  328. '7 REM
  329. '10 GRAPHICS 8:SETCOLOR 2,0,0:COLOR 3
  330. '20 FOR A=0 TO 6.28 STEP 0.02
  331. '30 X=SIN(A)*50+150
  332. '40 Y=COS(A)*50+80
  333. '50 PLOT X,Y
  334. '60 NEXT A
  335.  
  336. ' Conclusion#
  337. ' Returning back to first program with the fastest way of drawing circles...
  338. ' There is one more thing to note. In case you want to use PLOT subroutine,
  339. ' which is part of the main circle routine, then read following explanation.
  340. ' PLOT routine is written so it can be used easily from Atari BASIC program
  341. ' independently from main circle routine, by using like this:
  342. ' A=USR(30179,POK,X,Y)
  343. '
  344. ' POK   1 (drawing a pixel), 0 (erasing a pixel)
  345. ' X     X coordinate of the pixel
  346. ' Y     Y coordinate of the pixel
  347. '
  348. ' The routine alone is not any faster than normal PLOT command
  349. ' from Atari BASIC, because USR command takes approximately 75%
  350. ' of whole execution. But, used as part of the main circle routine
  351. ' it does not matter anymore, because it is integrated in one larger
  352. ' entity. There the execution is very fast, with no overhead.
  353. ' PLOT routine is here for you to examine anyway.
  354. ' You never know if you will maybe need it in the future.
  355.  
  356. ' More on plotting circles:
  357. '     Drawing a circle in BASIC - fast
  358. '     https://www.cpcwiki.eu/forum/programming/drawing-a-circle-in-basic-fast/
  359.  
  360. ' X,Y     = center point of circle
  361. ' R       = radius
  362. ' S       = char to draw
  363. ' MyArray = 2D string array to plot circle in
  364.  
  365. Sub PlotCircle (X As Integer, Y As Integer, R As Integer, S As String, MyArray() As String)
  366.     Dim A As Integer
  367.     Dim B As Integer
  368.     Dim C As Integer
  369.     Dim S2 As String
  370.  
  371.     If Len(S) = 1 Then
  372.         S2 = S
  373.     Else
  374.         If Len(S) = 0 Then
  375.             S2 = " "
  376.         Else
  377.             S2 = Left$(S, 1)
  378.         End If
  379.     End If
  380.  
  381.     If R > 0 Then
  382.         B = R
  383.         C = 0
  384.         A = R - 1
  385.         Do
  386.             PlotPoint X + C, Y + B, S2, MyArray()
  387.             PlotPoint X + C, Y - B, S2, MyArray()
  388.             PlotPoint X - C, Y - B, S2, MyArray()
  389.             PlotPoint X - C, Y + B, S2, MyArray()
  390.             PlotPoint X + B, Y + C, S2, MyArray()
  391.             PlotPoint X + B, Y - C, S2, MyArray()
  392.             PlotPoint X - B, Y - C, S2, MyArray()
  393.             PlotPoint X - B, Y + C, S2, MyArray()
  394.             C = C + 1
  395.             A = A + 1 - C - C
  396.             If A < 0 Then ' IF A>=0 THEN 190
  397.                 B = B - 1
  398.                 A = A + B + B
  399.             End If
  400.             If B < C Then Exit Do ' 190 IF B>=C THEN 60
  401.         Loop
  402.     End If
  403. End Sub ' PlotCircle
  404.  
  405. ' /////////////////////////////////////////////////////////////////////////////
  406.  
  407. Sub PlotCircleTest
  408.     Dim MyArray(1 To 32, 1 To 32) As String
  409.     Dim iX As Integer
  410.     Dim iY As Integer
  411.     Dim in$
  412.     Dim X As Integer
  413.     Dim Y As Integer
  414.     Dim R As Integer
  415.     Dim iChar As Integer
  416.  
  417.     ClearArray MyArray(), "."
  418.     iChar = 64
  419.  
  420.     Cls
  421.     Print "Plot a raster circle"
  422.     Print "Based on Fast circle drawing in pure Atari BASIC by Zlatko Bleha."
  423.     Print
  424.     Print "Enter parameters to draw a circle."
  425.     Print ArrayToStringTest(MyArray())
  426.     Print
  427.  
  428.     Do
  429.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  430.         Print "and radius (1-32) of circle."
  431.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  432.         If X > 0 And Y > 0 And R > 0 Then
  433.             iChar = iChar + 1
  434.             If iChar > 90 Then iChar = 65
  435.  
  436.             Print "X=" + cstr$(X)
  437.             Print "Y=" + cstr$(Y)
  438.             Print "R=" + cstr$(R)
  439.  
  440.             PlotCircle X, Y, R, Chr$(iChar), MyArray()
  441.  
  442.             Print "Circle plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  443.             Print ArrayToStringTest(MyArray())
  444.             Print
  445.         Else
  446.             Exit Do
  447.         End If
  448.     Loop
  449.  
  450. End Sub ' PlotCircleTest
  451.  
  452. ' /////////////////////////////////////////////////////////////////////////////
  453. ' Re: Is this fast enough as general circle fill?
  454. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg1913#msg1913
  455.  
  456. ' From: SMcNeill
  457. ' Date: « Reply #30 on: June 26, 2018, 03:34:18 pm »
  458. '
  459. ' Sometimes, computers do things that are completely counter-intuitive to us, and
  460. ' we find ourselves having to step back as programmers and simply say, "WOW!!"
  461. ' Here's a perfect example of that:
  462. ' Here we look at two different circle fill routines -- one, which I'd assume to
  463. ' be faster, which precalculates the offset needed to find the endpoints for each
  464. ' line which composes a circle, and another, which is the same old CircleFill
  465. ' program which I've shared countless times over the years with people on various
  466. ' QB64 forums.
  467. '
  468. ' When all is said and done though, CircleFill is STILL even faster than
  469. ' CircleFillFast, which pregenerates those end-points for us!
  470.  
  471. Sub CircleFill (CX As Integer, CY As Integer, R As Integer, S As String, MyArray() As String)
  472.     Dim Radius As Integer
  473.     Dim RadiusError As Integer
  474.     Dim X As Integer
  475.     Dim Y As Integer
  476.     Dim iLoopX As Integer
  477.     Dim iLoopY As Integer
  478.  
  479.     Radius = Abs(R)
  480.     RadiusError = -Radius
  481.     X = Radius
  482.     Y = 0
  483.  
  484.     If Radius = 0 Then
  485.         'PSET (CX, CY), C
  486.         PlotPoint CX, CY, S, MyArray()
  487.         Exit Sub
  488.     End If
  489.  
  490.     ' Draw the middle span here so we don't draw it twice in the main loop,
  491.     ' which would be a problem with blending turned on.
  492.     'LINE (CX - X, CY)-(CX + X, CY), C, BF
  493.     For iLoopX = CX - X To CX + X
  494.         PlotPoint iLoopX, CY, S, MyArray()
  495.     Next iLoopX
  496.  
  497.     While X > Y
  498.         RadiusError = RadiusError + Y * 2 + 1
  499.         If RadiusError >= 0 Then
  500.             If X <> Y + 1 Then
  501.                 'LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  502.                 iLoopY = CY - X
  503.                 For iLoopX = CX - Y To CX + Y
  504.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  505.                 Next iLoopX
  506.  
  507.                 'LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  508.                 iLoopY = CY + X
  509.                 For iLoopX = CX - Y To CX + Y
  510.                     PlotPoint iLoopX, iLoopY, S, MyArray()
  511.                 Next iLoopX
  512.             End If
  513.             X = X - 1
  514.             RadiusError = RadiusError - X * 2
  515.         End If
  516.         Y = Y + 1
  517.         'LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  518.         iLoopY = CY - Y
  519.         For iLoopX = CX - X To CX + X
  520.             PlotPoint iLoopX, iLoopY, S, MyArray()
  521.         Next iLoopX
  522.  
  523.         'LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  524.         iLoopY = CY + Y
  525.         For iLoopX = CX - X To CX + X
  526.             PlotPoint iLoopX, iLoopY, S, MyArray()
  527.         Next iLoopX
  528.     Wend
  529. End Sub ' CircleFill
  530.  
  531. ' /////////////////////////////////////////////////////////////////////////////
  532.  
  533. Sub CircleFillTest
  534.     Dim MyArray(1 To 32, 1 To 32) As String
  535.     Dim iX As Integer
  536.     Dim iY As Integer
  537.     Dim in$
  538.     Dim X As Integer
  539.     Dim Y As Integer
  540.     Dim R As Integer
  541.     Dim iChar As Integer
  542.  
  543.     ClearArray MyArray(), "."
  544.     iChar = 64
  545.  
  546.     Cls
  547.     Print "Plot a filled circle"
  548.     Print "Based on CircleFill by SMcNeill."
  549.     Print
  550.     Print "Enter parameters to draw a circle."
  551.     Print ArrayToStringTest(MyArray())
  552.     Print
  553.  
  554.     Do
  555.         Print "Type center point x,y (1-32, 1-32) coordinate to plot circle,"
  556.         Print "and radius (1-32) of circle."
  557.         Input "X,Y,R OR 0 TO QUIT: "; X, Y, R
  558.         If X > 0 And Y > 0 And R > 0 Then
  559.             iChar = iChar + 1
  560.             If iChar > 90 Then iChar = 65
  561.  
  562.             Print "X=" + cstr$(X)
  563.             Print "Y=" + cstr$(Y)
  564.             Print "R=" + cstr$(R)
  565.  
  566.             'PlotCircle X, Y, R, Chr$(iChar), MyArray()
  567.             CircleFill X, Y, R, Chr$(iChar), MyArray()
  568.  
  569.             Print "Circle plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  570.             Print ArrayToStringTest(MyArray())
  571.             Print
  572.         Else
  573.             Exit Do
  574.         End If
  575.     Loop
  576.  
  577. End Sub ' CircleFillTest
  578.  
  579. ' /////////////////////////////////////////////////////////////////////////////
  580. ' Re: Is this fast enough as general circle fill?
  581. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  582.  
  583. ' From: bplus
  584. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  585.  
  586. Sub Ellipse (CX As Integer, CY As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String)
  587.     Dim scale As Single
  588.     Dim xs As Integer
  589.     Dim x As Integer
  590.     Dim y As Integer
  591.     Dim lastx As Integer
  592.     Dim lasty As Integer
  593.     Dim iLoopX As Integer
  594.     Dim iLoopY As Integer
  595.  
  596.     scale = yRadius / xRadius
  597.     xs = xRadius * xRadius
  598.  
  599.     'PSET (CX, CY - yRadius)
  600.     PlotPoint CX, CY - yRadius, S, MyArray()
  601.  
  602.     'PSET (CX, CY + yRadius)
  603.     PlotPoint CX, CY + yRadius, S, MyArray()
  604.  
  605.     lastx = 0: lasty = yRadius
  606.     For x = 1 To xRadius
  607.         y = scale * Sqr(xs - x * x)
  608.         'LINE (CX + lastx, CY - lasty)-(CX + x, CY - y)
  609.         PlotLine CX + lastx, CY - lasty, CX + x, CY - y, S, MyArray()
  610.  
  611.         'LINE (CX + lastx, CY + lasty)-(CX + x, CY + y)
  612.         PlotLine CX + lastx, CY + lasty, CX + x, CY + y, S, MyArray()
  613.  
  614.         'LINE (CX - lastx, CY - lasty)-(CX - x, CY - y)
  615.         PlotLine CX - lastx, CY - lasty, CX - x, CY - y, S, MyArray()
  616.  
  617.         'LINE (CX - lastx, CY + lasty)-(CX - x, CY + y)
  618.         PlotLine CX - lastx, CY + lasty, CX - x, CY + y, S, MyArray()
  619.  
  620.         lastx = x
  621.         lasty = y
  622.     Next x
  623. End Sub ' Ellipse
  624.  
  625. ' /////////////////////////////////////////////////////////////////////////////
  626.  
  627. Sub EllipseTest
  628.     Dim MyArray(1 To 32, 1 To 32) As String
  629.     Dim iX As Integer
  630.     Dim iY As Integer
  631.     Dim in$
  632.     Dim X As Integer
  633.     Dim Y As Integer
  634.     Dim RX As Integer
  635.     Dim RY As Integer
  636.     Dim iChar As Integer
  637.  
  638.     ClearArray MyArray(), "."
  639.     iChar = 64
  640.  
  641.     Cls
  642.     Print "Plot an ellipse"
  643.     Print "Based on ellipse by bplus."
  644.     Print
  645.     Print "Enter parameters to draw an ellipse."
  646.     Print ArrayToStringTest(MyArray())
  647.     Print
  648.  
  649.     Do
  650.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  651.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  652.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  653.         If X > 0 And Y > 0 And RX > 0 And RY > 0 Then
  654.             iChar = iChar + 1
  655.             If iChar > 90 Then iChar = 65
  656.  
  657.             Print "X =" + cstr$(X)
  658.             Print "Y =" + cstr$(Y)
  659.             Print "RX=" + cstr$(RX)
  660.             Print "RY=" + cstr$(RY)
  661.  
  662.             Ellipse X, Y, RX, RY, Chr$(iChar), MyArray()
  663.  
  664.             Print "Ellipse plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  665.             Print ArrayToStringTest(MyArray())
  666.             Print
  667.         Else
  668.             Exit Do
  669.         End If
  670.     Loop
  671.  
  672. End Sub ' EllipseTest
  673.  
  674. ' /////////////////////////////////////////////////////////////////////////////
  675. ' Re: Is this fast enough as general circle fill?
  676. ' https://qb64forum.alephc.xyz/index.php?topic=298.msg3588#msg3588
  677.  
  678. ' From: bplus
  679. ' Date: « Reply #59 on: August 30, 2018, 09:18:34 am »
  680. '
  681. ' Here is my ellipse and filled ellipse routines, no where near
  682. ' Steve's level of performance. The speed is cut in half at
  683. ' least because you probably have to do a whole quadrants worth
  684. ' of calculations (ellipse not as symmetric as circle).
  685. '
  686. ' But I am sure this code can be optimized more than it is:
  687.  
  688. Sub EllipseFill (CX As Integer, CY As Integer, xRadius As Integer, yRadius As Integer, S As String, MyArray() As String)
  689.     Dim scale As Single
  690.     Dim x As Integer
  691.     Dim y As Integer
  692.     Dim iLoopX As Integer
  693.     Dim iLoopY As Integer
  694.  
  695.     scale = yRadius / xRadius
  696.  
  697.     'LINE (CX, CY - yRadius)-(CX, CY + yRadius), , BF
  698.     For iLoopY = CY - yRadius To CY + yRadius
  699.         PlotPoint CX, iLoopY, S, MyArray()
  700.     Next iLoopY
  701.  
  702.     For x = 1 To xRadius
  703.         y = scale * Sqr(xRadius * xRadius - x * x)
  704.  
  705.         'LINE (CX + x, CY - y)-(CX + x, CY + y), , BF
  706.         iLoopX = CX + x
  707.         For iLoopY = CY - y To CY + y
  708.             PlotPoint iLoopX, iLoopY, S, MyArray()
  709.         Next iLoopY
  710.  
  711.         'LINE (CX - x, CY - y)-(CX - x, CY + y), , BF
  712.         iLoopX = CX - x
  713.         For iLoopY = CY - y To CY + y
  714.             PlotPoint iLoopX, iLoopY, S, MyArray()
  715.         Next iLoopY
  716.     Next x
  717. End Sub ' EllipseFill
  718.  
  719. ' /////////////////////////////////////////////////////////////////////////////
  720.  
  721. Sub EllipseFillTest
  722.     Dim MyArray(1 To 32, 1 To 32) As String
  723.     Dim iX As Integer
  724.     Dim iY As Integer
  725.     Dim in$
  726.     Dim X As Integer
  727.     Dim Y As Integer
  728.     Dim RX As Integer
  729.     Dim RY As Integer
  730.     Dim iChar As Integer
  731.  
  732.     ClearArray MyArray(), "."
  733.     iChar = 64
  734.  
  735.     Cls
  736.     Print "Plot a filled ellipse"
  737.     Print "Based on fellipse by bplus."
  738.     Print
  739.     Print "Enter parameters to draw an ellipse."
  740.     Print ArrayToStringTest(MyArray())
  741.     Print
  742.  
  743.     Do
  744.         Print "Type center point x,y (1-32, 1-32) coordinate to plot ellipse,"
  745.         Print "and x radius (1-32) and y radius (1-32) of ellipse."
  746.         Input "X,Y,RX,RY OR 0 TO QUIT: "; X, Y, RX, RY
  747.         If X > 0 And Y > 0 And RX > 0 And RY > 0 Then
  748.             iChar = iChar + 1
  749.             If iChar > 90 Then iChar = 65
  750.  
  751.             Print "X =" + cstr$(X)
  752.             Print "Y =" + cstr$(Y)
  753.             Print "RX=" + cstr$(RX)
  754.             Print "RY=" + cstr$(RY)
  755.  
  756.             EllipseFill X, Y, RX, RY, Chr$(iChar), MyArray()
  757.  
  758.             Print "Ellipse plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  759.             Print ArrayToStringTest(MyArray())
  760.             Print
  761.         Else
  762.             Exit Do
  763.         End If
  764.     Loop
  765.  
  766. End Sub ' EllipseFillTest
  767.  
  768. ' /////////////////////////////////////////////////////////////////////////////
  769. ' Based on "BRESNHAM.BAS" by Kurt Kuzba. (4/16/96)
  770. ' From: http://www.thedubber.altervista.org/qbsrc.htm
  771.  
  772. Sub PlotLine (x1%, y1%, x2%, y2%, c$, MyArray() As String)
  773.     Dim iLoop%
  774.     Dim steep%: steep% = 0
  775.     Dim ev%: ev% = 0
  776.     Dim sx%
  777.     Dim sy%
  778.     Dim dx%
  779.     Dim dy%
  780.  
  781.     If (x2% - x1%) > 0 Then
  782.         sx% = 1
  783.     Else
  784.         sx% = -1
  785.     End If
  786.  
  787.     dx% = Abs(x2% - x1%)
  788.     If (y2% - y1%) > 0 Then
  789.         sy% = 1
  790.     Else
  791.         sy% = -1
  792.     End If
  793.  
  794.     dy% = Abs(y2% - y1%)
  795.     If (dy% > dx%) Then
  796.         steep% = 1
  797.         Swap x1%, y1%
  798.         Swap dx%, dy%
  799.         Swap sx%, sy%
  800.     End If
  801.  
  802.     ev% = 2 * dy% - dx%
  803.     For iLoop% = 0 To dx% - 1
  804.         If steep% = 1 Then
  805.             ''PSET (y1%, x1%), c%:
  806.             'LOCATE y1%, x1%
  807.             'PRINT c$;
  808.             PlotPoint y1%, x1%, c$, MyArray()
  809.         Else
  810.             ''PSET (x1%, y1%), c%
  811.             'LOCATE x1%, y1%
  812.             'PRINT c$;
  813.             PlotPoint x1%, y1%, c$, MyArray()
  814.         End If
  815.  
  816.         While ev% >= 0
  817.             y1% = y1% + sy%
  818.             ev% = ev% - 2 * dx%
  819.         Wend
  820.         x1% = x1% + sx%
  821.         ev% = ev% + 2 * dy%
  822.     Next iLoop%
  823.     ''PSET (x2%, y2%), c%
  824.     'LOCATE x2%, y2%
  825.     'PRINT c$;
  826.     PlotPoint x2%, y2%, c$, MyArray()
  827. End Sub ' PlotLine
  828.  
  829. ' /////////////////////////////////////////////////////////////////////////////
  830.  
  831. Sub PlotLineTest
  832.     Dim MyArray(1 To 32, 1 To 32) As String
  833.     Dim in$
  834.     Dim X1 As Integer
  835.     Dim Y1 As Integer
  836.     Dim X2 As Integer
  837.     Dim Y2 As Integer
  838.     Dim iChar As Integer
  839.  
  840.     ClearArray MyArray(), "."
  841.     iChar = 64
  842.  
  843.     Cls
  844.     Print "Plot line with Bresenham Algorithm"
  845.     Print "based on BRESNHAM.BAS by Kurt Kuzba (4/16/96)."
  846.     Print
  847.     Print ArrayToStringTest(MyArray())
  848.     Do
  849.         Print "Enter coordinate values for "
  850.         Print "line start point x1, y1 (1-32, 1-32)"
  851.         Print "line end   point x2, y2 (1-32, 1-32)"
  852.         Input "ENTER X1,Y1,X2,Y2 OR 0 TO QUIT: "; X1, Y1, X2, Y2
  853.         If X1 > 0 And Y1 > 0 And X2 > 0 And Y2 > 0 Then
  854.             iChar = iChar + 1
  855.             If iChar > 90 Then iChar = 65
  856.  
  857.             Print "X1=" + cstr$(X1)
  858.             Print "Y1=" + cstr$(Y1)
  859.             Print "X2=" + cstr$(X2)
  860.             Print "Y2=" + cstr$(Y2)
  861.  
  862.             PlotLine X1, Y1, X2, Y2, Chr$(iChar), MyArray()
  863.  
  864.             Print "Line plotted, drawn with " + Chr$(34) + Chr$(iChar) + Chr$(34) + ":"
  865.             Print ArrayToStringTest(MyArray())
  866.  
  867.         Else
  868.             Exit Do
  869.         End If
  870.     Loop
  871. End Sub ' PlotLineTest
  872.  
  873. ' /////////////////////////////////////////////////////////////////////////////
  874. ' 3 shear method testing
  875.  
  876. ' _PUT Rotation Help
  877. ' https://www.qb64.org/forum/index.php?topic=1959.0
  878.  
  879. ' 3 Shear Rotation - rotates without any aliasing(holes)
  880. ' https://www.freebasic.net/forum/viewtopic.php?t=24557
  881.  
  882. ' From: leopardpm
  883. ' Date: Apr 02, 2016 1:21
  884. ' Last edited by leopardpm on Apr 02, 2016 17:18, edited 1 time in total.
  885. '
  886. ' This is just a little 3-shear rotation routine
  887. ' (I am using 3-shear because it leaves no gaps/aliasing)
  888. ' that I was wondering if anyone sees how to make it faster.
  889. ' Obviously, I am just thinking about inside the double loop.
  890.  
  891. ' Thanks again to BasicCoder2 for linking me to this little routine, it is wonderful so far!
  892.  
  893. '''                      roto-zooming algorithm
  894. '''                    coded by Michael S. Nissen
  895. '''                        jernmager@yahoo.dk
  896. '
  897. ''' ===============================================================
  898. ''' Recoded to run on FBC 32/64 bit WIN, Version 1.05.0, 2016, by MrSwiss
  899. ''' Heavy flickering before going Full-Screen on 64 Bit !!!
  900. ''' This seems NOT to be the Case on 32 Bit ...
  901. ''' ===============================================================
  902. '
  903. 'Type Pixel
  904. '  As Single   X, Y
  905. '  As ULong    C
  906. 'End Type
  907. '
  908. '''  dim vars
  909. 'Dim shared as Any Ptr Img_Buffer
  910. '''  write the name of the .bmp image you want to rotozoom here:
  911. '''  (it has to be sqare ie. 100x100 pixels, 760x760 pixels or whatever)
  912. 'Dim As String Img_Name = "phobos.bmp"
  913. 'Dim shared as Integer X_Mid, Y_Mid, scrn_wid, scrn_hgt, P1, P2, P3, P4, C
  914. 'Dim shared as Short Img_Hgt, Img_Wid, Img_Lft, Img_Rgt, Img_Top, Img_Btm, X, Y
  915. 'Dim Shared As Single Cos_Ang, Sin_Ang, Rot_Fac_X, Rot_Fac_Y, Angle = 0, Scale = 1
  916. '
  917. ''' changed Function to Sub (+ recoded arguments list)
  918. 'Sub Calc_rotozoom ( ByRef Cos_Ang As Single, _
  919. '               ByRef Sin_Ang As Single, _
  920. '               ByVal S_Fact  As Single, _
  921. '               ByVal NewAng  As Single )
  922. '  Cos_Ang = Cos(NewAng)*S_Fact
  923. '  Sin_Ang = Sin(NewAng)*S_Fact
  924. 'End Sub
  925. '
  926. '''  full screen
  927. 'ScreenInfo scrn_wid, scrn_hgt
  928. 'screenRes scrn_wid, scrn_hgt, 32,,1
  929. '
  930. '''  dim screenpointer (has to be done after screenres)
  931. 'Dim As ULong Ptr Scrn_Ptr = Screenptr
  932. '
  933. '''  place image in center of screen
  934. 'X_Mid = scrn_wid\2
  935. 'Y_Mid = scrn_hgt\2
  936. 'Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  937. '
  938. '''  find image dimensions
  939. 'Open Img_Name For Binary As #1
  940. 'Get #1, 19, Img_Wid
  941. 'Get #1, 23, Img_Hgt
  942. 'Close #1
  943. '
  944. '''  prepare to dim the array that will hold the image.
  945. 'Img_Rgt = (Img_Wid-1)\2
  946. 'Img_Lft = -Img_Rgt
  947. 'Img_Btm = (Img_Hgt-1)\2
  948. 'Img_Top = -Img_Btm
  949. '
  950. '''  dim array to hold image. Note: pixel (0, 0) is in the center.
  951. 'Dim As Pixel Pixel(Img_Lft to Img_Rgt, Img_Top to Img_Btm)
  952. '
  953. '''  imagecreate sprite and load image to sprite
  954. 'Img_Buffer = ImageCreate (Img_Wid, Img_Hgt)
  955. 'Bload (Img_Name, Img_Buffer)
  956. '
  957. '''  load image from sprite to array with point command
  958. 'For Y = Img_Top to Img_Btm
  959. '  For X = Img_Lft to Img_Rgt
  960. '    With Pixel(X, Y)
  961. '      .X = X_Mid+X
  962. '      .Y = Y_Mid+Y
  963. '      C = Point (X-Img_Top, Y-Img_Lft, Img_buffer)
  964. '      If C <> RGB(255, 0, 255) Then
  965. '        .C = C
  966. '      Else
  967. '        .C = RGB(0, 0, 0)
  968. '      End If
  969. '    End With
  970. '  Next X
  971. 'Next Y
  972. '
  973. '''  we don't need the sprite anymore, kill it
  974. 'ImageDestroy Img_Buffer
  975. 'Img_Buffer = 0
  976. '
  977. '''  main program loop
  978. 'Do
  979. '
  980. '  ''  scale in/out with uparrow/downarrow
  981. '  If Multikey(80) Then
  982. '    Scale *= 1.03
  983. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  984. '  ElseIf Multikey(72) Then
  985. '    Scale *= 0.97
  986. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  987. '  End If
  988. '
  989. '  ''  rotate left/right with leftarrow/rightarrow
  990. '  If Multikey(77) Then
  991. '    Angle -= 0.03
  992. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  993. '  ElseIf Multikey(75) Then
  994. '    Angle += 0.03
  995. '    Calc_rotozoom(Cos_Ang, Sin_Ang, Scale, Angle)
  996. '  End If
  997. '
  998. '  ''  lock screen in order to use screen pointers
  999. '  ScreenLock
  1000. '
  1001. '    ''  draw pixel in center of image
  1002. '    Scrn_Ptr[ X_Mid + Y_Mid * scrn_wid ] = Pixel(0, 0).C
  1003. '    ''  draw all other pixels - 4 at a time
  1004. '    For Y = Img_Top to 0
  1005. '      For X = Img_Lft to -1
  1006. '        ''  find pixel positions
  1007. '        P1 = (X_Mid+X) + (Y_Mid+Y) * scrn_wid
  1008. '        P2 = (X_Mid-X) + (Y_Mid-Y) * scrn_wid
  1009. '        P3 = (X_Mid+Y) + (Y_Mid-X) * scrn_wid
  1010. '        P4 = (X_Mid-Y) + (Y_Mid+X) * scrn_wid
  1011. '        ''  erase old pixels (paint them black)
  1012. '        Scrn_Ptr[P1] = 0
  1013. '        Scrn_Ptr[P2] = 0
  1014. '        Scrn_Ptr[P3] = 0
  1015. '        Scrn_Ptr[P4] = 0
  1016. '        ''  rotate and zoom
  1017. '        Rot_Fac_X = X*Cos_Ang - Y*Sin_Ang
  1018. '        Rot_Fac_Y = X*Sin_Ang + Y*Cos_Ang
  1019. '        If Rot_Fac_X < Img_Lft Or Rot_Fac_X > Img_Rgt Then Continue For
  1020. '        If Rot_Fac_Y < Img_Top Or Rot_Fac_Y > Img_Btm Then Continue For
  1021. '        ''  draw new pixels
  1022. '        Scrn_Ptr[P1] = Pixel(Rot_Fac_X, Rot_Fac_Y).C
  1023. '        Scrn_Ptr[P2] = Pixel(-Rot_Fac_X, -Rot_Fac_Y).C
  1024. '        Scrn_Ptr[P3] = Pixel(Rot_Fac_Y, -Rot_Fac_X).C
  1025. '        Scrn_Ptr[P4] = Pixel(-Rot_Fac_Y, Rot_Fac_X).C
  1026. '      Next X
  1027. '    Next Y
  1028. '
  1029. '  ScreenUnLock
  1030. '
  1031. '  Sleep 10, 1
  1032. 'Loop Until InKey() = Chr(27)
  1033.  
  1034. ' UPDATES:
  1035. ' Fixed bug where values 135, 224, and 314 all resolve to -45 degrees.
  1036. ' Fixed bug where an angle of 46-135 degrees caused the image to be flipped wrong.
  1037.  
  1038. ' TODO:
  1039. ' Fix issue where image looks bad at 30, 60, 120, 150, 210, 240, 300, 330 degrees
  1040.  
  1041. Sub ShearRotate (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer)
  1042.     Const Pi = 4 * Atn(1)
  1043.  
  1044.     Dim angle As Integer
  1045.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  1046.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  1047.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  1048.     Dim x As Integer
  1049.     Dim y As Integer
  1050.     Dim nangle As Integer
  1051.     Dim nx As Integer
  1052.     Dim ny As Integer
  1053.     Dim flipper As Integer
  1054.     Dim rotr As Double
  1055.     Dim shear1 As Double
  1056.     Dim shear2 As Double
  1057.     Dim clr As Integer
  1058.     Dim y1 As _Byte
  1059.     Dim xy1 As _Byte
  1060.     Dim fy As _Byte
  1061.     Dim fx As _Byte
  1062.     Dim in$
  1063.     Dim sLine As String
  1064.  
  1065.     ' initialize new with empty
  1066.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  1067.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1068.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1069.             NewArray(x, y, 0).origx = x
  1070.             NewArray(x, y, 0).origy = y
  1071.             NewArray(x, y, 0).c = iEmpty
  1072.         Next y
  1073.     Next x
  1074.  
  1075.     ' angle is reversed
  1076.     angle = 360 - angle1
  1077.  
  1078.     ' Shearing each element 3 times in one shot
  1079.     nangle = angle
  1080.  
  1081.     ' this pre-processing portion basically rotates by 90 to get
  1082.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  1083.     If angle > 45 And angle < 225 Then
  1084.         If angle < 135 Then
  1085.             nangle = angle - 90
  1086.         Else
  1087.             nangle = angle - 180
  1088.         End If
  1089.     End If
  1090.     If angle > 135 And angle < 315 Then
  1091.         If angle < 225 Then
  1092.             nangle = angle - 180
  1093.         Else
  1094.             nangle = angle - 270
  1095.         End If
  1096.     End If
  1097.     If nangle < 0 Then
  1098.         nangle = nangle + 360
  1099.     End If
  1100.     If nangle > 359 Then
  1101.         nangle = nangle - 360
  1102.     End If
  1103.  
  1104.     rotr = nangle * DtoR
  1105.     shear1 = Tan(rotr / 2) ' correct way
  1106.     shear2 = Sin(rotr)
  1107.  
  1108.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  1109.     ' ***       all resolve to -45 degrees.
  1110.     ' ***       Fixed by changing < to <=
  1111.  
  1112.     'if angle >  45 and angle < 134 then
  1113.     If angle > 45 And angle <= 134 Then
  1114.         flipper = 1
  1115.     ElseIf angle > 134 And angle <= 224 Then
  1116.         flipper = 2
  1117.     ElseIf angle > 224 And angle <= 314 Then
  1118.         ' *** NOTE: this had a bug where this flipper was wrong
  1119.         '           Fixed by adding case 7
  1120.         'flipper = 3
  1121.         flipper = 7
  1122.     Else
  1123.         flipper = 0
  1124.     End If
  1125.  
  1126.     ' Here is where it needs some optimizing possibly... kinda slow...
  1127.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1128.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1129.             Select Case flipper
  1130.                 Case 1:
  1131.                     nx = -y
  1132.                     ny = x
  1133.                 Case 2:
  1134.                     nx = -x
  1135.                     ny = -y
  1136.                 Case 3:
  1137.                     nx = -y
  1138.                     ny = -x
  1139.                 Case 4:
  1140.                     nx = -x
  1141.                     ny = y
  1142.                 Case 5:
  1143.                     nx = x
  1144.                     ny = -y
  1145.                 Case 6:
  1146.                     nx = y
  1147.                     ny = x
  1148.                 Case 7:
  1149.                     nx = y
  1150.                     ny = -x
  1151.                 Case Else:
  1152.                     nx = x
  1153.                     ny = y
  1154.             End Select
  1155.  
  1156.             clr = OldArray(nx, ny, 0).c
  1157.  
  1158.             y1 = y * shear1
  1159.             xy1 = x + y1
  1160.             fy = (y - xy1 * shear2)
  1161.             fx = xy1 + fy * shear1
  1162.  
  1163.             If fx >= -16 And fx <= 16 Then
  1164.                 If fy >= -16 And fy <= 16 Then
  1165.                     NewArray(fx, fy, 0).c = clr
  1166.                     NewArray(fx, fy, 0).origx = fx
  1167.                     NewArray(fx, fy, 0).origy = fy
  1168.                 End If
  1169.             End If
  1170.         Next x
  1171.     Next y
  1172. End Sub ' ShearRotate
  1173.  
  1174. ' /////////////////////////////////////////////////////////////////////////////
  1175. ' Same as ShearRotate, except adds iOverwriteCount parameter,
  1176. ' and counts how many points are overwriting existing points,
  1177. ' and return that value byref in parameter iOverwriteCount.
  1178.  
  1179. Sub ShearRotate1 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iOverwriteCount As Integer)
  1180.     Const Pi = 4 * Atn(1)
  1181.  
  1182.     Dim angle As Integer
  1183.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  1184.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  1185.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  1186.     Dim x As Integer
  1187.     Dim y As Integer
  1188.     Dim nangle As Integer
  1189.     Dim nx As Integer
  1190.     Dim ny As Integer
  1191.     Dim flipper As Integer
  1192.     Dim rotr As Double
  1193.     Dim shear1 As Double
  1194.     Dim shear2 As Double
  1195.     Dim clr As Integer
  1196.     Dim y1 As _Byte
  1197.     Dim xy1 As _Byte
  1198.     Dim fy As _Byte
  1199.     Dim fx As _Byte
  1200.     Dim in$
  1201.     Dim sLine As String
  1202.  
  1203.     ' initialize new with empty
  1204.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  1205.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1206.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1207.             NewArray(x, y, 0).origx = x
  1208.             NewArray(x, y, 0).origy = y
  1209.             NewArray(x, y, 0).c = iEmpty
  1210.         Next y
  1211.     Next x
  1212.  
  1213.     ' angle is reversed
  1214.     angle = 360 - angle1
  1215.  
  1216.     ' Shearing each element 3 times in one shot
  1217.     nangle = angle
  1218.  
  1219.     ' this pre-processing portion basically rotates by 90 to get
  1220.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  1221.     If angle > 45 And angle < 225 Then
  1222.         If angle < 135 Then
  1223.             nangle = angle - 90
  1224.         Else
  1225.             nangle = angle - 180
  1226.         End If
  1227.     End If
  1228.     If angle > 135 And angle < 315 Then
  1229.         If angle < 225 Then
  1230.             nangle = angle - 180
  1231.         Else
  1232.             nangle = angle - 270
  1233.         End If
  1234.     End If
  1235.     If nangle < 0 Then
  1236.         nangle = nangle + 360
  1237.     End If
  1238.     If nangle > 359 Then
  1239.         nangle = nangle - 360
  1240.     End If
  1241.  
  1242.     rotr = nangle * DtoR
  1243.     shear1 = Tan(rotr / 2) ' correct way
  1244.     shear2 = Sin(rotr)
  1245.  
  1246.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  1247.     ' ***       all resolve to -45 degrees.
  1248.     ' ***       Fixed by changing < to <=
  1249.  
  1250.     'if angle >  45 and angle < 134 then
  1251.     If angle > 45 And angle <= 134 Then
  1252.         flipper = 1
  1253.     ElseIf angle > 134 And angle <= 224 Then
  1254.         flipper = 2
  1255.     ElseIf angle > 224 And angle <= 314 Then
  1256.         ' *** NOTE: this had a bug where this flipper was wrong
  1257.         '           Fixed by adding case 7
  1258.         'flipper = 3
  1259.         flipper = 7
  1260.     Else
  1261.         flipper = 0
  1262.     End If
  1263.  
  1264.     ' Here is where it needs some optimizing possibly... kinda slow...
  1265.     iOverwriteCount = 0
  1266.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1267.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1268.             Select Case flipper
  1269.                 Case 1:
  1270.                     nx = -y
  1271.                     ny = x
  1272.                 Case 2:
  1273.                     nx = -x
  1274.                     ny = -y
  1275.                 Case 3:
  1276.                     nx = -y
  1277.                     ny = -x
  1278.                 Case 4:
  1279.                     nx = -x
  1280.                     ny = y
  1281.                 Case 5:
  1282.                     nx = x
  1283.                     ny = -y
  1284.                 Case 6:
  1285.                     nx = y
  1286.                     ny = x
  1287.                 Case 7:
  1288.                     nx = y
  1289.                     ny = -x
  1290.                 Case Else:
  1291.                     nx = x
  1292.                     ny = y
  1293.             End Select
  1294.  
  1295.             clr = OldArray(nx, ny, 0).c
  1296.  
  1297.             y1 = y * shear1
  1298.             xy1 = x + y1
  1299.             fy = (y - xy1 * shear2)
  1300.             fx = xy1 + fy * shear1
  1301.  
  1302.             If fx >= -16 And fx <= 16 Then
  1303.                 If fy >= -16 And fy <= 16 Then
  1304.  
  1305.                     ' count points that will be overwritten
  1306.                     If NewArray(fx, fy, 0).c <> iEmpty Then
  1307.                         iOverwriteCount = iOverwriteCount + 1
  1308.                     End If
  1309.  
  1310.                     NewArray(fx, fy, 0).c = clr
  1311.                     NewArray(fx, fy, 0).origx = fx
  1312.                     NewArray(fx, fy, 0).origy = fy
  1313.                 End If
  1314.             End If
  1315.         Next x
  1316.     Next y
  1317. End Sub ' ShearRotate1
  1318.  
  1319. ' /////////////////////////////////////////////////////////////////////////////
  1320. ' Tries to fix the problem of 2 points resolving to the same coordinate
  1321. ' (one overwrites the other, which becomes "lost")
  1322.  
  1323. ' Returns # points missing (that could not be corrected) in iMissing parameter.
  1324.  
  1325. Sub ShearRotate2 (OldArray() As RotationType, NewArray() As RotationType, angle1 As Integer, iEmpty As Integer, iMissing As Integer)
  1326.     Const Pi = 4 * Atn(1)
  1327.  
  1328.     Dim angle As Integer
  1329.     Dim TwoPi As Double: TwoPi = 8 * Atn(1)
  1330.     Dim RtoD As Double: RtoD = 180 / Pi ' radians * RtoD = degrees
  1331.     Dim DtoR As Double: DtoR = Pi / 180 ' degrees * DtoR = radians
  1332.     Dim x As Integer
  1333.     Dim y As Integer
  1334.     Dim nangle As Integer
  1335.     Dim nx As Integer
  1336.     Dim ny As Integer
  1337.     Dim flipper As Integer
  1338.     Dim rotr As Double
  1339.     Dim shear1 As Double
  1340.     Dim shear2 As Double
  1341.     Dim clr As Integer
  1342.     Dim y1 As _Byte
  1343.     Dim xy1 As _Byte
  1344.     Dim fy As _Byte
  1345.     Dim fx As _Byte
  1346.     Dim in$
  1347.     Dim sLine As String
  1348.     ReDim arrLost(-1) As RotationType
  1349.     Dim iLoop As Integer
  1350.     Dim bFound As Integer
  1351.  
  1352.     ' initialize new with empty
  1353.     ReDim NewArray(LBound(OldArray, 1) To UBound(OldArray, 1), LBound(OldArray, 2) To UBound(OldArray, 2), 127) As RotationType
  1354.     For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1355.         For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1356.             NewArray(x, y, 0).origx = x
  1357.             NewArray(x, y, 0).origy = y
  1358.             NewArray(x, y, 0).c = iEmpty
  1359.         Next y
  1360.     Next x
  1361.  
  1362.     ' angle is reversed
  1363.     angle = 360 - angle1
  1364.  
  1365.     ' Shearing each element 3 times in one shot
  1366.     nangle = angle
  1367.  
  1368.     ' this pre-processing portion basically rotates by 90 to get
  1369.     ' between -45 and 45 degrees, where the 3-shear routine works correctly...
  1370.     If angle > 45 And angle < 225 Then
  1371.         If angle < 135 Then
  1372.             nangle = angle - 90
  1373.         Else
  1374.             nangle = angle - 180
  1375.         End If
  1376.     End If
  1377.     If angle > 135 And angle < 315 Then
  1378.         If angle < 225 Then
  1379.             nangle = angle - 180
  1380.         Else
  1381.             nangle = angle - 270
  1382.         End If
  1383.     End If
  1384.     If nangle < 0 Then
  1385.         nangle = nangle + 360
  1386.     End If
  1387.     If nangle > 359 Then
  1388.         nangle = nangle - 360
  1389.     End If
  1390.  
  1391.     rotr = nangle * DtoR
  1392.     shear1 = Tan(rotr / 2) ' correct way
  1393.     shear2 = Sin(rotr)
  1394.  
  1395.     ' *** NOTE: this had a bug where the values 135, 224, and 314
  1396.     ' ***       all resolve to -45 degrees.
  1397.     ' ***       Fixed by changing < to <=
  1398.  
  1399.     'if angle >  45 and angle < 134 then
  1400.     If angle > 45 And angle <= 134 Then
  1401.         flipper = 1
  1402.     ElseIf angle > 134 And angle <= 224 Then
  1403.         flipper = 2
  1404.     ElseIf angle > 224 And angle <= 314 Then
  1405.         ' *** NOTE: this had a bug where this flipper was wrong
  1406.         '           Fixed by adding case 7
  1407.         'flipper = 3
  1408.         flipper = 7
  1409.     Else
  1410.         flipper = 0
  1411.     End If
  1412.  
  1413.     ' Here is where it needs some optimizing possibly... kinda slow...
  1414.     For y = LBound(NewArray, 2) To UBound(NewArray, 2)
  1415.         For x = LBound(NewArray, 1) To UBound(NewArray, 1)
  1416.             Select Case flipper
  1417.                 Case 1:
  1418.                     nx = -y
  1419.                     ny = x
  1420.                 Case 2:
  1421.                     nx = -x
  1422.                     ny = -y
  1423.                 Case 3:
  1424.                     nx = -y
  1425.                     ny = -x
  1426.                 Case 4:
  1427.                     nx = -x
  1428.                     ny = y
  1429.                 Case 5:
  1430.                     nx = x
  1431.                     ny = -y
  1432.                 Case 6:
  1433.                     nx = y
  1434.                     ny = x
  1435.                 Case 7:
  1436.                     nx = y
  1437.                     ny = -x
  1438.                 Case Else:
  1439.                     nx = x
  1440.                     ny = y
  1441.             End Select
  1442.  
  1443.             clr = OldArray(nx, ny, 0).c
  1444.  
  1445.             y1 = y * shear1
  1446.             xy1 = x + y1
  1447.             fy = (y - xy1 * shear2)
  1448.             fx = xy1 + fy * shear1
  1449.  
  1450.             If fx >= -16 And fx <= 16 Then
  1451.                 If fy >= -16 And fy <= 16 Then
  1452.                     ' only draw here if this spot is empty
  1453.                     If NewArray(fx, fy, 0).c = iEmpty Then
  1454.                         NewArray(fx, fy, 0).c = clr
  1455.                         NewArray(fx, fy, 0).origx = fx
  1456.                         NewArray(fx, fy, 0).origy = fy
  1457.                     Else
  1458.                         ' don't draw, but save it to a list to handle later
  1459.                         ReDim _Preserve arrLost(0 To UBound(arrLost) + 1) As RotationType
  1460.                         arrLost(UBound(arrLost)).c = clr
  1461.                         arrLost(UBound(arrLost)).origx = fx
  1462.                         arrLost(UBound(arrLost)).origy = fy
  1463.                     End If
  1464.                 End If
  1465.             End If
  1466.         Next x
  1467.     Next y
  1468.  
  1469.     ' try to place any points that would have overwritten to a spot nearby
  1470.     ' can nearby be determined by the angle of rotation?
  1471.     ' perhaps if we divide the screen up into 4 zones:
  1472.     '
  1473.     ' --------------------------------------
  1474.     '|                   |                  |
  1475.     '| zone 4            | zone 1           |
  1476.     '| 271-359 degrees)  | (1-89 degrees)   |
  1477.     '|--------------------------------------|
  1478.     '|                   |                  |
  1479.     '| zone 3            | zone 2           |
  1480.     '| (181-269 degrees) | (91-179 degrees) |
  1481.     '|                   |                  |
  1482.     ' --------------------------------------
  1483.  
  1484.     ' in zone   search direction (y,x)
  1485.     ' -------   ----------------------
  1486.     ' 1         up   + right
  1487.     ' 2         down + right
  1488.     ' 3         down + left
  1489.     ' 4         up   + left
  1490.  
  1491.     iMissing = 0
  1492.     For iLoop = 0 To UBound(arrLost)
  1493.         bFound = FindEmptyShearRotationPoint%(arrLost(iLoop), angle1, iEmpty, x, y, NewArray())
  1494.         If bFound = TRUE Then
  1495.             If m_bDebug = TRUE Then
  1496.                 _Echo "Plotted  missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " to (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  1497.             End If
  1498.         Else
  1499.             iMissing = iMissing + 1
  1500.             If m_bDebug = TRUE Then
  1501.                 _Echo "Detected missing point " + Chr$(34) + Chr$(arrLost(iLoop).c) + Chr$(34) + " at (x=" + cstr$(x) + ", y=" + cstr$(y) + ")"
  1502.             End If
  1503.         End If
  1504.     Next iLoop
  1505.  
  1506. End Sub ' ShearRotate2
  1507.  
  1508. ' /////////////////////////////////////////////////////////////////////////////
  1509. ' Receives
  1510. ' FindMe (RotationType) = contains the starting location (.origx, .origy) to start looking from, and the value (.c) to write
  1511. ' angle1 (Integer) = angle we were rotating to, to determine direction to look in
  1512. ' iEmpty (Integer) = value to test against for empty
  1513. ' destX (Integer) = if an empty spot is found, returns the x location here byref
  1514. ' destY (Integer) = if an empty spot is found, returns the y location here byref
  1515. ' NewArray() (RotationType array (x,y,127) ) = array representing the screen to search in and plot to
  1516.  
  1517. ' Returns
  1518. ' FALSE if no empty spot was found
  1519. ' TRUE if an empty spot was found, and x,y location returned byref in destX,destY parameters
  1520.  
  1521. Function FindEmptyShearRotationPoint% (FindMe As RotationType, angle1 As Integer, iEmpty As Integer, destX As Integer, destY As Integer, NewArray() As RotationType)
  1522.     Dim bResult As Integer: bResult = FALSE
  1523.     Dim x As Integer
  1524.     Dim y As Integer
  1525.     Dim dirX As Integer
  1526.     Dim dirY As Integer
  1527.  
  1528.     destX = 0
  1529.     destY = 0
  1530.  
  1531.     ' Choose search direction depending on the angle
  1532.     If angle1 > 0 And angle1 < 90 Then
  1533.         dirX = 1
  1534.         dirY = -1
  1535.     ElseIf angle1 > 90 And angle1 < 180 Then
  1536.         dirX = 1
  1537.         dirY = 1
  1538.     ElseIf angle1 > 180 And angle1 < 270 Then
  1539.         dirX = -1
  1540.         dirY = 1
  1541.     ElseIf angle1 > 270 And angle1 < 360 Then
  1542.         dirX = -1
  1543.         dirY = -1
  1544.     Else
  1545.         dirX = 0
  1546.         dirY = 0
  1547.     End If
  1548.  
  1549.     If dirX <> 0 Then
  1550.         x = FindMe.origx
  1551.         y = FindMe.origy
  1552.         Do
  1553.             ' quit if we're out of bounds
  1554.             If x < LBound(NewArray, 1) Then Exit Do
  1555.             If x > UBound(NewArray, 1) Then Exit Do
  1556.             If y < LBound(NewArray, 2) Then Exit Do
  1557.             If y > UBound(NewArray, 2) Then Exit Do
  1558.  
  1559.             ' =============================================================================
  1560.             ' BEGIN PRIMARY SEARCH
  1561.             ' =============================================================================
  1562.             ' look along y axis for a blank spot
  1563.             destX = x
  1564.             destY = y + dirY
  1565.             If destX >= LBound(NewArray, 1) Then
  1566.                 If destX <= UBound(NewArray, 1) Then
  1567.                     If destY >= LBound(NewArray, 2) Then
  1568.                         If destY <= UBound(NewArray, 2) Then
  1569.                             If NewArray(destX, destY, 0).c = iEmpty Then
  1570.                                 NewArray(destX, destY, 0).c = FindMe.c
  1571.                                 bResult = TRUE
  1572.                                 Exit Do
  1573.                             End If
  1574.                         End If
  1575.                     End If
  1576.                 End If
  1577.             End If
  1578.  
  1579.             ' look along x axis for a blank spot
  1580.             destX = x + dirX
  1581.             destY = y
  1582.             If destX >= LBound(NewArray, 1) Then
  1583.                 If destX <= UBound(NewArray, 1) Then
  1584.                     If destY >= LBound(NewArray, 2) Then
  1585.                         If destY <= UBound(NewArray, 2) Then
  1586.                             If NewArray(x + dirX, y, 0).c = iEmpty Then
  1587.                                 NewArray(destX, destY, 0).c = FindMe.c
  1588.                                 bResult = TRUE
  1589.                                 Exit Do
  1590.                             End If
  1591.                         End If
  1592.                     End If
  1593.                 End If
  1594.             End If
  1595.  
  1596.             ' look diagonally for a blank spot
  1597.             destX = x + dirX
  1598.             destY = y + dirY
  1599.             If destX >= LBound(NewArray, 1) Then
  1600.                 If destX <= UBound(NewArray, 1) Then
  1601.                     If destY >= LBound(NewArray, 2) Then
  1602.                         If destY <= UBound(NewArray, 2) Then
  1603.                             If NewArray(x + dirX, y + dirY, 0).c = iEmpty Then
  1604.                                 NewArray(destX, destY, 0).c = FindMe.c
  1605.                                 bResult = TRUE
  1606.                                 Exit Do
  1607.                             End If
  1608.                         End If
  1609.                     End If
  1610.                 End If
  1611.             End If
  1612.             ' =============================================================================
  1613.             ' END PRIMARY SEARCH
  1614.             ' =============================================================================
  1615.  
  1616.             ' =============================================================================
  1617.             ' BEGIN SECONDARY SEARCH
  1618.             ' =============================================================================
  1619.             'yoda
  1620.             ' =============================================================================
  1621.             ' END SECONDARY SEARCH
  1622.             ' =============================================================================
  1623.  
  1624.             ' Keep looking
  1625.             x = x + dirX
  1626.             y = y + dirY
  1627.         Loop
  1628.     End If
  1629.  
  1630.     ' Return result
  1631.     FindEmptyShearRotationPoint% = bResult
  1632. End Function ' FindEmptyShearRotationPoint%
  1633.  
  1634. ' /////////////////////////////////////////////////////////////////////////////
  1635.  
  1636. Sub ShearRotateTest1
  1637.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  1638.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  1639.     Dim sMap As String
  1640.     Dim D As Integer
  1641.     Dim in$
  1642.  
  1643.     ' GET A SHAPE TO BE ROTATED
  1644.     Cls
  1645.     Print "3 shear rotation based on code by leopardpm"
  1646.     Print
  1647.  
  1648.     sMap = TestSprite1$
  1649.  
  1650.     ' CONVERT SHAPE TO ARRAY
  1651.     StringToRotationArray RoArray1(), sMap, "."
  1652.     Print "Initial contents of Rotation Array:"
  1653.     Print RotationArrayToStringTest(RoArray1())
  1654.     Print
  1655.  
  1656.     ' ROTATE THE SHAPE
  1657.     Do
  1658.         Print "Type degrees to rotate (0 TO 360) or non-numeric value to quit."
  1659.         Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1660.  
  1661.         Input "Degrees to rotate (q to quit)? "; in$
  1662.         If IsNum%(in$) Then
  1663.             D = Val(in$)
  1664.             If D >= 0 And D <= 360 Then
  1665.                 ShearRotate RoArray1(), RoArray2(), D, Asc(".")
  1666.                 Print
  1667.                 Print "Rotated by " + cstr$(D) + " degrees:"
  1668.                 Print RotationArrayToStringTest(RoArray2())
  1669.                 Print
  1670.             Else
  1671.                 Exit Do
  1672.             End If
  1673.         Else
  1674.             Exit Do
  1675.         End If
  1676.     Loop
  1677. End Sub ' ShearRotateTest1
  1678.  
  1679. ' /////////////////////////////////////////////////////////////////////////////
  1680. ' Now receives parameter sMap
  1681. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  1682.  
  1683. ' e.g. ShearRotateTest2 TestSprite1$
  1684.  
  1685. Sub ShearRotateTest2 (sMap As String)
  1686.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  1687.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  1688.     'Dim sMap As String
  1689.     Dim D As Integer
  1690.     Dim D1 As Integer
  1691.     Dim in$
  1692.     Dim bFinished As Integer
  1693.     Dim iOverwriteCount As Integer
  1694.  
  1695.     ' GET A SHAPE TO BE ROTATED
  1696.     Cls
  1697.     Print "3 shear rotation based on code by leopardpm"
  1698.     'sMap = TestSprite1$
  1699.  
  1700.     ' CONVERT SHAPE TO ARRAY
  1701.     StringToRotationArray RoArray1(), sMap, "."
  1702.  
  1703.     ' GET START ANGLE
  1704.     D = 0
  1705.     Print
  1706.     Print "Rotated by " + cstr$(D) + " degrees:"
  1707.     Print RotationArrayToStringTest(RoArray1())
  1708.     Print
  1709.     Print "Type an angle (-360 to 360) to rotate to, "
  1710.     Print "or blank to increase by 1 degree, or q to quit."
  1711.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1712.     Print "Hold down <ENTER> to rotate continually."
  1713.     Input "Angle (q to quit)? ", in$
  1714.     If Len(in$) > 0 Then
  1715.         If IsNum%(in$) Then
  1716.             D1 = Val(in$)
  1717.         Else
  1718.             D1 = -500
  1719.         End If
  1720.     Else
  1721.         D1 = 1
  1722.     End If
  1723.  
  1724.     ' ROTATE TO EACH ANGLE
  1725.     If D1 >= -360 And D1 <= 360 Then
  1726.         bFinished = FALSE
  1727.         Do
  1728.             ' ROTATE CLOCKWISE
  1729.             For D = D1 To 360
  1730.                 Cls
  1731.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  1732.                 Print
  1733.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  1734.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  1735.  
  1736.                 Print RotationArrayToStringTest(RoArray2())
  1737.                 Print
  1738.  
  1739.                 Print "Type an angle (-360 to 360) to rotate to, "
  1740.                 Print "or blank to increase by 1 degree, or q to quit."
  1741.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1742.                 Print "Hold down <ENTER> to rotate continually."
  1743.                 Input "Angle (q to quit)? ", in$
  1744.                 If Len(in$) > 0 Then
  1745.                     If IsNum%(in$) Then
  1746.                         D = Val(in$)
  1747.                         If D >= 0 And D <= 360 Then
  1748.                             D = D - 1
  1749.                         Else
  1750.                             bFinished = TRUE
  1751.                             Exit For
  1752.                         End If
  1753.                     Else
  1754.                         bFinished = TRUE
  1755.                         Exit For
  1756.                     End If
  1757.                 End If
  1758.             Next D
  1759.             If bFinished = TRUE Then Exit Do
  1760.  
  1761.             ' ROTATE COUNTER-CLOCKWISE
  1762.             For D = 360 To D1 Step -1
  1763.                 Cls
  1764.                 ShearRotate1 RoArray1(), RoArray2(), D, Asc("."), iOverwriteCount
  1765.                 Print
  1766.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  1767.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iOverwriteCount = 0, "", " (" + cstr$(iOverwriteCount) + " points overwritten)") + ":"
  1768.  
  1769.                 Print RotationArrayToStringTest(RoArray2())
  1770.                 Print
  1771.  
  1772.                 Print "Type an angle (0 to 360) to rotate to, "
  1773.                 Print "or blank to increase by 1 degree, or q to quit."
  1774.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1775.                 Print "Hold down <ENTER> to rotate continually."
  1776.                 Input "Angle (q to quit)? ", in$
  1777.                 If Len(in$) > 0 Then
  1778.                     If IsNum%(in$) Then
  1779.                         D = Val(in$)
  1780.                         If D >= 0 And D <= 360 Then
  1781.                             D = D + 1
  1782.                         Else
  1783.                             bFinished = TRUE
  1784.                             Exit For
  1785.                         End If
  1786.                     Else
  1787.                         bFinished = TRUE
  1788.                         Exit For
  1789.                     End If
  1790.                 End If
  1791.             Next D
  1792.             If bFinished = TRUE Then Exit Do
  1793.         Loop
  1794.     End If
  1795. End Sub ' ShearRotateTest2
  1796.  
  1797. ' /////////////////////////////////////////////////////////////////////////////
  1798. ' Tries to correct for missing points.
  1799.  
  1800. ' Receives parameter sMap
  1801. ' which comes from TestSprite1$, TestSprite2$, TestSprite3$, etc.
  1802.  
  1803. ' e.g. ShearRotateTest3 TestSprite1$
  1804.  
  1805. Sub ShearRotateTest3 (sMap As String)
  1806.     Dim RoArray1(-16 To 16, -16 To 16, 127) As RotationType
  1807.     Dim RoArray2(-16 To 16, -16 To 16, 127) As RotationType
  1808.     'Dim sMap As String
  1809.     Dim D As Integer
  1810.     Dim D1 As Integer
  1811.     Dim in$
  1812.     Dim bFinished As Integer
  1813.     Dim iMissing As Integer
  1814.  
  1815.     ' GET A SHAPE TO BE ROTATED
  1816.     Cls
  1817.     Print "3 shear rotation based on code by leopardpm"
  1818.     'sMap = TestSprite1$
  1819.  
  1820.     ' CONVERT SHAPE TO ARRAY
  1821.     StringToRotationArray RoArray1(), sMap, "."
  1822.  
  1823.     ' GET START ANGLE
  1824.     D = 0
  1825.     Print
  1826.     Print "Rotated by " + cstr$(D) + " degrees:"
  1827.     Print RotationArrayToStringTest(RoArray1())
  1828.     Print
  1829.     Print "Type an angle (-360 to 360) to rotate to, "
  1830.     Print "or blank to increase by 1 degree, or q to quit."
  1831.     Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1832.     Print "Hold down <ENTER> to rotate continually."
  1833.     Input "Angle (q to quit)? ", in$
  1834.     If Len(in$) > 0 Then
  1835.         If IsNum%(in$) Then
  1836.             D1 = Val(in$)
  1837.         Else
  1838.             D1 = -500
  1839.         End If
  1840.     Else
  1841.         D1 = 1
  1842.     End If
  1843.  
  1844.     ' ROTATE TO EACH ANGLE
  1845.     If D1 >= -360 And D1 <= 360 Then
  1846.         bFinished = FALSE
  1847.         Do
  1848.             ' ROTATE CLOCKWISE
  1849.             For D = D1 To 360
  1850.                 Cls
  1851.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  1852.                 Print
  1853.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  1854.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  1855.  
  1856.                 Print RotationArrayToStringTest(RoArray2())
  1857.                 Print
  1858.  
  1859.                 Print "Type an angle (-360 to 360) to rotate to, "
  1860.                 Print "or blank to increase by 1 degree, or q to quit."
  1861.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1862.                 Print "Hold down <ENTER> to rotate continually."
  1863.                 Input "Angle (q to quit)? ", in$
  1864.                 If Len(in$) > 0 Then
  1865.                     If IsNum%(in$) Then
  1866.                         D = Val(in$)
  1867.                         If D >= 0 And D <= 360 Then
  1868.                             D = D - 1
  1869.                         Else
  1870.                             bFinished = TRUE
  1871.                             Exit For
  1872.                         End If
  1873.                     Else
  1874.                         bFinished = TRUE
  1875.                         Exit For
  1876.                     End If
  1877.                 End If
  1878.             Next D
  1879.             If bFinished = TRUE Then Exit Do
  1880.  
  1881.             ' ROTATE COUNTER-CLOCKWISE
  1882.             For D = 360 To D1 Step -1
  1883.                 Cls
  1884.                 ShearRotate2 RoArray1(), RoArray2(), D, Asc("."), iMissing
  1885.                 Print
  1886.                 'Print "Rotated by " + cstr$(D) + " degrees:"
  1887.                 Print "Rotated by " + cstr$(D) + " degrees" + IIFSTR$(iMissing = 0, "", " (" + cstr$(iMissing) + " points missing)") + ":"
  1888.  
  1889.                 Print RotationArrayToStringTest(RoArray2())
  1890.                 Print
  1891.  
  1892.                 Print "Type an angle (0 to 360) to rotate to, "
  1893.                 Print "or blank to increase by 1 degree, or q to quit."
  1894.                 Print "Note: Need to fix code for 30,60,120,150,210,240,300,330 degrees (looks bad)."
  1895.                 Print "Hold down <ENTER> to rotate continually."
  1896.                 Input "Angle (q to quit)? ", in$
  1897.                 If Len(in$) > 0 Then
  1898.                     If IsNum%(in$) Then
  1899.                         D = Val(in$)
  1900.                         If D >= 0 And D <= 360 Then
  1901.                             D = D + 1
  1902.                         Else
  1903.                             bFinished = TRUE
  1904.                             Exit For
  1905.                         End If
  1906.                     Else
  1907.                         bFinished = TRUE
  1908.                         Exit For
  1909.                     End If
  1910.                 End If
  1911.             Next D
  1912.             If bFinished = TRUE Then Exit Do
  1913.         Loop
  1914.     End If
  1915. End Sub ' ShearRotateTest3
  1916.  
  1917. ' /////////////////////////////////////////////////////////////////////////////
  1918.  
  1919. Function TestSprite1$
  1920.     Dim m$
  1921.     m$ = ""
  1922.     '                   11111111112222222222333
  1923.     '          12345678901234567890123456789012
  1924.     m$ = m$ + "11111111111111111111111111111111" + Chr$(13) ' 1
  1925.     m$ = m$ + "4..............................2" + Chr$(13) ' 2
  1926.     m$ = m$ + "4....##.....#######.....####...2" + Chr$(13) ' 3
  1927.     m$ = m$ + "4...####....##...###...######..2" + Chr$(13) ' 4
  1928.     m$ = m$ + "4..##..##...##...###..##....##.2" + Chr$(13) ' 5
  1929.     m$ = m$ + "4.##....##..#######...##.......2" + Chr$(13) ' 6
  1930.     m$ = m$ + "4.########..#######...##.......2" + Chr$(13) ' 7
  1931.     m$ = m$ + "4.########..##...###..##....##.2" + Chr$(13) ' 8
  1932.     m$ = m$ + "4.##....##..##...###...######..2" + Chr$(13) ' 9
  1933.     m$ = m$ + "4.##....##..#######.....####...2" + Chr$(13) ' 10
  1934.     m$ = m$ + "4..............................2" + Chr$(13) ' 11
  1935.     m$ = m$ + "4..............................2" + Chr$(13) ' 12
  1936.     m$ = m$ + "4..ABBBBBBBBBBBBBBBBBBBBBBBBC..2" + Chr$(13) ' 13
  1937.     m$ = m$ + "4..A...........EE...........C..2" + Chr$(13) ' 14
  1938.     m$ = m$ + "4..A..........FFFF..........C..2" + Chr$(13) ' 15
  1939.     m$ = m$ + "4..A.........GGGGGG.........C..2" + Chr$(13) ' 16
  1940.     m$ = m$ + "4..A........HHHHHHHH........C..2" + Chr$(13) ' 17
  1941.     m$ = m$ + "4..A.......IIIIIIIIII.......C..2" + Chr$(13) ' 18
  1942.     m$ = m$ + "4..A......JJJJJJJJJJJJ......C..2" + Chr$(13) ' 19
  1943.     m$ = m$ + "4..DDDDDDDDDDDDDDDDDDDDDDDDDC..2" + Chr$(13) ' 20
  1944.     m$ = m$ + "4..............................2" + Chr$(13) ' 21
  1945.     m$ = m$ + "4..............................2" + Chr$(13) ' 22
  1946.     m$ = m$ + "4.######....########..########.2" + Chr$(13) ' 23
  1947.     m$ = m$ + "4.#######...########..########.2" + Chr$(13) ' 24
  1948.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 25
  1949.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 26
  1950.     m$ = m$ + "4.##....##..########..#######..2" + Chr$(13) ' 27
  1951.     m$ = m$ + "4.##...###..##........##.......2" + Chr$(13) ' 28
  1952.     m$ = m$ + "4.#######...##........##.......2" + Chr$(13) ' 29
  1953.     m$ = m$ + "4.######....########..##.......2" + Chr$(13) ' 30
  1954.     m$ = m$ + "4..............................2" + Chr$(13) ' 31
  1955.     m$ = m$ + "33333333333333333333333333333332" + Chr$(13) ' 32
  1956.     TestSprite1$ = m$
  1957. End Function ' TestSprite1$
  1958.  
  1959. ' /////////////////////////////////////////////////////////////////////////////
  1960.  
  1961. Function TestSprite2$
  1962.     Dim m$
  1963.     m$ = ""
  1964.     '                   11111111112222222222333
  1965.     '          12345678901234567890123456789012
  1966.     m$ = m$ + "...............AA..............." + Chr$(13) ' 1
  1967.     m$ = m$ + "..............//BB.............." + Chr$(13) ' 2
  1968.     m$ = m$ + ".............??..CC............." + Chr$(13) ' 3
  1969.     m$ = m$ + "............==....DD............" + Chr$(13) ' 4
  1970.     m$ = m$ + "...........++......EE..........." + Chr$(13) ' 5
  1971.     m$ = m$ + "..........&&........FF.........." + Chr$(13) ' 6
  1972.     m$ = m$ + ".........zz..........GG........." + Chr$(13) ' 7
  1973.     m$ = m$ + "........yy............HH........" + Chr$(13) ' 8
  1974.     m$ = m$ + ".......xx..............II......." + Chr$(13) ' 9
  1975.     m$ = m$ + "......ww................JJ......" + Chr$(13) ' 10
  1976.     m$ = m$ + ".....vv..................KK....." + Chr$(13) ' 11
  1977.     m$ = m$ + "....uu....................LL...." + Chr$(13) ' 12
  1978.     m$ = m$ + "...tt......DDAAAAAAA.......MM..." + Chr$(13) ' 13
  1979.     m$ = m$ + "..ss.......DDAAAAAAA........NN.." + Chr$(13) ' 14
  1980.     m$ = m$ + ".rr........DD.....BB.........OO." + Chr$(13) ' 15
  1981.     m$ = m$ + "qq.........DD.....BB..........PP" + Chr$(13) ' 16
  1982.     m$ = m$ + "pp.........DD.....BB..........QQ" + Chr$(13) ' 17
  1983.     m$ = m$ + ".oo........DD.....BB.........RR." + Chr$(13) ' 18
  1984.     m$ = m$ + "..nn.......CCCCCCCBB........SS.." + Chr$(13) ' 19
  1985.     m$ = m$ + "...mm......CCCCCCCBB.......TT..." + Chr$(13) ' 20
  1986.     m$ = m$ + "....ll....................UU...." + Chr$(13) ' 21
  1987.     m$ = m$ + ".....kk..................VV....." + Chr$(13) ' 22
  1988.     m$ = m$ + "......jj................WW......" + Chr$(13) ' 23
  1989.     m$ = m$ + ".......ii..............XX......." + Chr$(13) ' 24
  1990.     m$ = m$ + "........hh............YY........" + Chr$(13) ' 25
  1991.     m$ = m$ + ".........gg..........ZZ........." + Chr$(13) ' 26
  1992.     m$ = m$ + "..........ff........@@.........." + Chr$(13) ' 27
  1993.     m$ = m$ + "...........ee......##..........." + Chr$(13) ' 28
  1994.     m$ = m$ + "............dd....$$............" + Chr$(13) ' 29
  1995.     m$ = m$ + ".............cc..%%............." + Chr$(13) ' 30
  1996.     m$ = m$ + "..............bb\\.............." + Chr$(13) ' 31
  1997.     m$ = m$ + "...............aa..............." + Chr$(13) ' 32
  1998.     TestSprite2$ = m$
  1999. End Function ' TestSprite2$
  2000.  
  2001. ' /////////////////////////////////////////////////////////////////////////////
  2002.  
  2003. Function PetrText1$
  2004.     Dim m$
  2005.     m$ = ""
  2006.     '                   11111111112222222222333
  2007.     '          12345678901234567890123456789012
  2008.     m$ = m$ + "................................" + Chr$(13) ' 1
  2009.     m$ = m$ + "................................" + Chr$(13) ' 2
  2010.     m$ = m$ + "................................" + Chr$(13) ' 3
  2011.     m$ = m$ + "................................" + Chr$(13) ' 4
  2012.     m$ = m$ + "................................" + Chr$(13) ' 5
  2013.     m$ = m$ + "................................" + Chr$(13) ' 6
  2014.     m$ = m$ + "................................" + Chr$(13) ' 7
  2015.     m$ = m$ + "................................" + Chr$(13) ' 8
  2016.     m$ = m$ + "................................" + Chr$(13) ' 9
  2017.     m$ = m$ + "................................" + Chr$(13) ' 10
  2018.     m$ = m$ + "................................" + Chr$(13) ' 11
  2019.     m$ = m$ + "................................" + Chr$(13) ' 12
  2020.     m$ = m$ + "................................" + Chr$(13) ' 13
  2021.     m$ = m$ + "................................" + Chr$(13) ' 14
  2022.     m$ = m$ + "....It's a SCREEN resolution?..." + Chr$(13) ' 15
  2023.     m$ = m$ + "................................" + Chr$(13) ' 16
  2024.     m$ = m$ + "................................" + Chr$(13) ' 17
  2025.     m$ = m$ + "................................" + Chr$(13) ' 18
  2026.     m$ = m$ + "................................" + Chr$(13) ' 19
  2027.     m$ = m$ + "................................" + Chr$(13) ' 20
  2028.     m$ = m$ + "................................" + Chr$(13) ' 21
  2029.     m$ = m$ + "................................" + Chr$(13) ' 22
  2030.     m$ = m$ + "................................" + Chr$(13) ' 23
  2031.     m$ = m$ + "................................" + Chr$(13) ' 24
  2032.     m$ = m$ + "................................" + Chr$(13) ' 25
  2033.     m$ = m$ + "................................" + Chr$(13) ' 26
  2034.     m$ = m$ + "................................" + Chr$(13) ' 27
  2035.     m$ = m$ + "................................" + Chr$(13) ' 28
  2036.     m$ = m$ + "................................" + Chr$(13) ' 29
  2037.     m$ = m$ + "................................" + Chr$(13) ' 30
  2038.     m$ = m$ + "................................" + Chr$(13) ' 31
  2039.     m$ = m$ + "................................" + Chr$(13) ' 32
  2040.     PetrText1$ = m$
  2041. End Function ' PetrText1$
  2042.  
  2043. ' /////////////////////////////////////////////////////////////////////////////
  2044.  
  2045. Function ArrayToString$ (MyArray( 1 To 32 , 1 To 32) As String)
  2046.     Dim MyString As String
  2047.     Dim iY As Integer
  2048.     Dim iX As Integer
  2049.     Dim sLine As String
  2050.     MyString = ""
  2051.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  2052.         sLine = ""
  2053.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  2054.             sLine = sLine + MyArray(iY, iX)
  2055.         Next iX
  2056.         MyString = MyString + sLine + Chr$(13)
  2057.     Next iY
  2058.     ArrayToString$ = MyString
  2059. End Function ' ArrayToString$
  2060.  
  2061. ' /////////////////////////////////////////////////////////////////////////////
  2062.  
  2063. Function ArrayToStringTest$ (MyArray() As String)
  2064.     Dim MyString As String
  2065.     Dim iY As Integer
  2066.     Dim iX As Integer
  2067.     Dim sLine As String
  2068.     MyString = ""
  2069.  
  2070.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  2071.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  2072.     For iY = LBound(MyArray, 1) To UBound(MyArray, 1)
  2073.         sLine = ""
  2074.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  2075.         For iX = LBound(MyArray, 2) To UBound(MyArray, 2)
  2076.             sLine = sLine + MyArray(iY, iX)
  2077.         Next iX
  2078.         sLine = sLine + Right$("  " + cstr$(iY), 2)
  2079.         MyString = MyString + sLine + Chr$(13)
  2080.     Next iY
  2081.     MyString = MyString + "  12345678901234567890123456789012" + Chr$(13)
  2082.     MyString = MyString + "           11111111112222222222333" + Chr$(13)
  2083.     ArrayToStringTest$ = MyString
  2084. End Function ' ArrayToStringTest$
  2085.  
  2086. ' /////////////////////////////////////////////////////////////////////////////
  2087.  
  2088. Function RotationArrayToStringTest$ (RoArray() As RotationType)
  2089.     Dim MyString As String
  2090.     Dim iY As Integer
  2091.     Dim iX As Integer
  2092.     Dim sLine As String
  2093.     MyString = ""
  2094.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  2095.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  2096.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  2097.     For iY = LBound(RoArray, 1) To UBound(RoArray, 1)
  2098.         sLine = ""
  2099.         sLine = sLine + Right$("    " + cstr$(iY), 3)
  2100.         For iX = LBound(RoArray, 2) To UBound(RoArray, 2)
  2101.             sLine = sLine + Chr$(RoArray(iX, iY, 0).c)
  2102.         Next iX
  2103.         sLine = sLine + Right$("   " + cstr$(iY), 3)
  2104.         MyString = MyString + sLine + Chr$(13)
  2105.     Next iY
  2106.     MyString = MyString + "   654321098765432101234567890123456" + Chr$(13)
  2107.     MyString = MyString + "   1111111                   1111111" + Chr$(13)
  2108.     MyString = MyString + "   ---------------- ++++++++++++++++" + Chr$(13)
  2109.     RotationArrayToStringTest$ = MyString
  2110. End Function ' RotationArrayToStringTest$
  2111.  
  2112. ' /////////////////////////////////////////////////////////////////////////////
  2113. ' 1. split string by line breaks CHR$(13)
  2114. ' 2. split lines up to 1 column per char
  2115. ' 3. count rows, columns
  2116. ' 4. DIM array, making sure array has
  2117. '    a) an _ODD_ number of rows/columns, with a center point
  2118. '    b) index is in cartesian format, where center is (0,0)
  2119. ' 5. populate array with contents of string
  2120.  
  2121. ' dimension #1 = columns
  2122. ' dimension #2 = rows
  2123.  
  2124. Sub StringToRotationArray (RoArray() As RotationType, MyString As String, EmptyChar As String)
  2125.     Dim RoutineName As String: RoutineName = "StringToRotationArray"
  2126.     ReDim arrLines$(0)
  2127.     Dim delim$
  2128.     Dim iRow%
  2129.     Dim iCol%
  2130.     Dim sChar$
  2131.     Dim iColCount As Integer
  2132.     Dim iRowCount As Integer
  2133.     Dim iCount As Integer
  2134.     Dim bAddedRow As Integer: bAddedRow = FALSE
  2135.     Dim bAddedColumn As Integer: bAddedColumn = FALSE
  2136.     Dim iHalf1 As Integer
  2137.     Dim iHalf2 As Integer
  2138.     Dim iFrom1 As Integer
  2139.     Dim iFrom2 As Integer
  2140.     Dim iTo1 As Integer
  2141.     Dim iTo2 As Integer
  2142.     Dim iEmpty As Integer
  2143.     Dim iX As Integer
  2144.     Dim iY As Integer
  2145.  
  2146.     delim$ = Chr$(13)
  2147.     split MyString, delim$, arrLines$()
  2148.  
  2149.     iRowCount = UBound(arrLines$) + 1
  2150.  
  2151.     ' look at all the rows and find the max # of columns used
  2152.     iColCount = 0
  2153.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  2154.  
  2155.         ' count the columns for this row
  2156.         iCount = 0
  2157.         For iCol% = 1 To Len(arrLines$(iRow%))
  2158.             iCount = iCount + 1
  2159.         Next iCol%
  2160.  
  2161.         ' if this row has the most so far, then set that to the max
  2162.         If iCount > iColCount Then
  2163.             iColCount = iCount
  2164.         End If
  2165.     Next iRow%
  2166.  
  2167.     ' adjust columns to be odd
  2168.     If IsEven%(iColCount) Then
  2169.         iColCount = iColCount + 1
  2170.         bAddedColumn = TRUE
  2171.     End If
  2172.  
  2173.     ' calculate array bounds for columns
  2174.     iHalf1 = (iColCount - 1) / 2
  2175.     iFrom1 = 0 - iHalf1
  2176.     iTo1 = iHalf1
  2177.  
  2178.     ' adjust rows to be odd
  2179.     If IsEven%(iRowCount) Then
  2180.         iRowCount = iRowCount + 1
  2181.         bAddedRow = TRUE
  2182.     End If
  2183.  
  2184.     ' calculate array bounds for rows
  2185.     iHalf2 = (iRowCount - 1) / 2
  2186.     iFrom2 = 0 - iHalf2
  2187.     iTo2 = iHalf2
  2188.  
  2189.     ' size array to new bounds
  2190.     ReDim RoArray(iFrom1 To iTo1, iFrom2 To iTo2, 127) As RotationType
  2191.  
  2192.     ' get value for empty
  2193.     If Len(EmptyChar) > 0 Then
  2194.         iEmpty = Asc(EmptyChar)
  2195.     Else
  2196.         iEmpty = 32 ' (use space as default)
  2197.     End If
  2198.  
  2199.     ' clear array
  2200.     For iY = LBound(RoArray, 2) To UBound(RoArray, 2)
  2201.         For iX = LBound(RoArray, 1) To UBound(RoArray, 1)
  2202.             RoArray(iX, iY, 0).c = iEmpty
  2203.             RoArray(iX, iY, 0).origx = iX
  2204.             RoArray(iX, iY, 0).origy = iY
  2205.         Next iX
  2206.     Next iY
  2207.  
  2208.     ' fill array
  2209.     iY = LBound(RoArray, 2) - 1
  2210.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  2211.         iY = iY + 1
  2212.         iX = LBound(RoArray, 1) - 1
  2213.         For iCol% = 1 To Len(arrLines$(iRow%))
  2214.             iX = iX + 1
  2215.             sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  2216.             RoArray(iX, iY, 0).c = Asc(sChar$)
  2217.         Next iCol%
  2218.     Next iRow%
  2219.  
  2220. End Sub ' StringToRotationArray
  2221.  
  2222. ' /////////////////////////////////////////////////////////////////////////////
  2223.  
  2224. Sub StringToArray (MyArray() As String, MyString As String)
  2225.     Dim delim$
  2226.     ReDim arrLines$(0)
  2227.     Dim iRow%
  2228.     Dim iCol%
  2229.     Dim sChar$
  2230.     Dim iDim1 As Integer
  2231.     Dim iDim2 As Integer
  2232.     iDim1 = LBound(MyArray, 1)
  2233.     iDim2 = LBound(MyArray, 2)
  2234.     delim$ = Chr$(13)
  2235.     split MyString, delim$, arrLines$()
  2236.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  2237.         If iRow% <= UBound(MyArray, 2) Then
  2238.             For iCol% = 1 To Len(arrLines$(iRow%))
  2239.                 If iCol% <= UBound(MyArray, 1) Then
  2240.                     sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  2241.  
  2242.                     If Len(sChar$) > 1 Then
  2243.                         sChar$ = Left$(sChar$, 1)
  2244.                     Else
  2245.                         If Len(sChar$) = 0 Then
  2246.                             sChar$ = "."
  2247.                         End If
  2248.                     End If
  2249.                     MyArray(iRow% + iDim1, (iCol% - 1) + iDim2) = sChar$
  2250.                 Else
  2251.                     ' Exit if out of bounds
  2252.                     Exit For
  2253.                 End If
  2254.             Next iCol%
  2255.         Else
  2256.             ' Exit if out of bounds
  2257.             Exit For
  2258.         End If
  2259.     Next iRow%
  2260. End Sub ' StringToArray
  2261.  
  2262. ' /////////////////////////////////////////////////////////////////////////////
  2263.  
  2264. 'SUB ClearArray (MyArray(1 To 32, 1 To 32) AS STRING, MyString As String)
  2265. Sub ClearArray (MyArray() As String, MyString As String)
  2266.     Dim iRow As Integer
  2267.     Dim iCol As Integer
  2268.     Dim sChar$
  2269.     If Len(MyString) = 1 Then
  2270.         sChar$ = MyString
  2271.     Else
  2272.         If Len(MyString) = 0 Then
  2273.             sChar$ = " "
  2274.         Else
  2275.             sChar$ = Left$(MyString, 1)
  2276.         End If
  2277.     End If
  2278.     For iRow = LBound(MyArray, 1) To UBound(MyArray, 1)
  2279.         For iCol = LBound(MyArray, 2) To UBound(MyArray, 2)
  2280.             MyArray(iRow, iCol) = sChar$
  2281.         Next iCol
  2282.     Next iRow
  2283. End Sub ' ClearArray
  2284.  
  2285. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2286. ' BEGIN GENERAL PURPOSE ROUTINES
  2287. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2288.  
  2289. ' /////////////////////////////////////////////////////////////////////////////
  2290.  
  2291. Function cstr$ (myValue)
  2292.     'cstr$ = LTRIM$(RTRIM$(STR$(myValue)))
  2293.     cstr$ = _Trim$(Str$(myValue))
  2294. End Function ' cstr$
  2295.  
  2296. Function cstrl$ (myValue As Long)
  2297.     cstrl$ = _Trim$(Str$(myValue))
  2298. End Function ' cstrl$
  2299.  
  2300. ' /////////////////////////////////////////////////////////////////////////////
  2301.  
  2302. Function IIF (Condition, IfTrue, IfFalse)
  2303.     If Condition Then IIF = IfTrue Else IIF = IfFalse
  2304.  
  2305. ' /////////////////////////////////////////////////////////////////////////////
  2306.  
  2307. Function IIFSTR$ (Condition, IfTrue$, IfFalse$)
  2308.     If Condition Then IIFSTR$ = IfTrue$ Else IIFSTR$ = IfFalse$
  2309.  
  2310. ' /////////////////////////////////////////////////////////////////////////////
  2311. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  2312.  
  2313. Function IsEven% (n)
  2314.     If n Mod 2 = 0 Then
  2315.         IsEven% = TRUE
  2316.     Else
  2317.         IsEven% = FALSE
  2318.     End If
  2319. End Function ' IsEven%
  2320.  
  2321. ' /////////////////////////////////////////////////////////////////////////////
  2322. ' https://slaystudy.com/qbasic-program-to-check-if-number-is-even-or-odd/
  2323.  
  2324. Function IsOdd% (n)
  2325.     If n Mod 2 = 1 Then
  2326.         IsOdd% = TRUE
  2327.     Else
  2328.         IsOdd% = FALSE
  2329.     End If
  2330. End Function ' IsOdd%
  2331.  
  2332. ' /////////////////////////////////////////////////////////////////////////////
  2333. ' By sMcNeill from https://www.qb64.org/forum/index.php?topic=896.0
  2334.  
  2335. Function IsNum% (text$)
  2336.     Dim a$
  2337.     Dim b$
  2338.     a$ = _Trim$(text$)
  2339.     b$ = _Trim$(Str$(Val(text$)))
  2340.     If a$ = b$ Then
  2341.         IsNum% = TRUE
  2342.     Else
  2343.         IsNum% = FALSE
  2344.     End If
  2345. End Function ' IsNum%
  2346.  
  2347. ' /////////////////////////////////////////////////////////////////////////////
  2348. ' Split and join strings
  2349. ' https://www.qb64.org/forum/index.php?topic=1073.0
  2350.  
  2351. 'Combine all elements of in$() into a single string with delimiter$ separating the elements.
  2352.  
  2353. Function join$ (in$(), delimiter$)
  2354.     result$ = in$(LBound(in$))
  2355.     For i = LBound(in$) + 1 To UBound(in$)
  2356.         result$ = result$ + delimiter$ + in$(i)
  2357.     Next i
  2358.     join$ = result$
  2359. End Function ' join$
  2360.  
  2361. ' /////////////////////////////////////////////////////////////////////////////
  2362. ' FROM: String Manipulation
  2363. ' http://www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there]/forum/index_topic_5964-0/
  2364. '
  2365. 'SUMMARY:
  2366. '   Purpose:  A library of custom functions that transform strings.
  2367. '   Author:   Dustinian Camburides (dustinian@gmail.com)
  2368. '   Platform: QB64 (www.[abandoned, outdated and now likely malicious qb64 dot net website - don’t go there])
  2369. '   Revision: 1.6
  2370. '   Updated:  5/28/2012
  2371.  
  2372. 'SUMMARY:
  2373. '[Replace$] replaces all instances of the [Find] sub-string with the [Add] sub-string within the [Text] string.
  2374. 'INPUT:
  2375. 'Text: The input string; the text that's being manipulated.
  2376. 'Find: The specified sub-string; the string sought within the [Text] string.
  2377. 'Add: The sub-string that's being added to the [Text] string.
  2378.  
  2379. Function Replace$ (Text1 As String, Find1 As String, Add1 As String)
  2380.     ' VARIABLES:
  2381.     Dim Text2 As String
  2382.     Dim Find2 As String
  2383.     Dim Add2 As String
  2384.     Dim lngLocation As Long ' The address of the [Find] substring within the [Text] string.
  2385.     Dim strBefore As String ' The characters before the string to be replaced.
  2386.     Dim strAfter As String ' The characters after the string to be replaced.
  2387.  
  2388.     ' INITIALIZE:
  2389.     ' MAKE COPIESSO THE ORIGINAL IS NOT MODIFIED (LIKE ByVal IN VBA)
  2390.     Text2 = Text1
  2391.     Find2 = Find1
  2392.     Add2 = Add1
  2393.  
  2394.     lngLocation = InStr(1, Text2, Find2)
  2395.  
  2396.     ' PROCESSING:
  2397.     ' While [Find2] appears in [Text2]...
  2398.     While lngLocation
  2399.         ' Extract all Text2 before the [Find2] substring:
  2400.         strBefore = Left$(Text2, lngLocation - 1)
  2401.  
  2402.         ' Extract all text after the [Find2] substring:
  2403.         strAfter = Right$(Text2, ((Len(Text2) - (lngLocation + Len(Find2) - 1))))
  2404.  
  2405.         ' Return the substring:
  2406.         Text2 = strBefore + Add2 + strAfter
  2407.  
  2408.         ' Locate the next instance of [Find2]:
  2409.         lngLocation = InStr(1, Text2, Find2)
  2410.  
  2411.         ' Next instance of [Find2]...
  2412.     Wend
  2413.  
  2414.     ' OUTPUT:
  2415.     Replace$ = Text2
  2416. End Function ' Replace$
  2417.  
  2418. ' /////////////////////////////////////////////////////////////////////////////
  2419. ' Split and join strings
  2420. ' https://www.qb64.org/forum/index.php?topic=1073.0
  2421. '
  2422. ' FROM luke, QB64 Developer
  2423. ' Date: February 15, 2019, 04:11:07 AM
  2424. '
  2425. ' Given a string of words separated by spaces (or any other character),
  2426. ' splits it into an array of the words. I've no doubt many people have
  2427. ' written a version of this over the years and no doubt there's a million
  2428. ' ways to do it, but I thought I'd put mine here so we have at least one
  2429. ' version. There's also a join function that does the opposite
  2430. ' array -> single string.
  2431. '
  2432. ' Code is hopefully reasonably self explanatory with comments and a little demo.
  2433. ' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.
  2434.  
  2435. 'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
  2436. 'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
  2437. '
  2438. 'delimiter$ must be one character long.
  2439. 'result$() must have been REDIMmed previously.
  2440.  
  2441. Sub split (in$, delimiter$, result$())
  2442.     ReDim result$(-1)
  2443.     start = 1
  2444.     Do
  2445.         While Mid$(in$, start, 1) = delimiter$
  2446.             start = start + 1
  2447.             If start > Len(in$) Then Exit Sub
  2448.         Wend
  2449.         finish = InStr(start, in$, delimiter$)
  2450.         If finish = 0 Then finish = Len(in$) + 1
  2451.         ReDim _Preserve result$(0 To UBound(result$) + 1)
  2452.         result$(UBound(result$)) = Mid$(in$, start, finish - start)
  2453.         start = finish + 1
  2454.     Loop While start <= Len(in$)
  2455. End Sub ' split
  2456.  
  2457. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2458. ' END GENERAL PURPOSE ROUTINES
  2459. ' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2460.  
  2461. ' #END
  2462. ' ################################################################################################################################################################
  2463.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: SMcNeill on December 23, 2021, 02:33:44 pm
Now, let me start off by apologizing and saying that I haven't actually tried any of the code in this topic at all.  Life has had me busy as heck the last few weeks, and all I've did is skim this topic and view the pretty images.  From what I gather, is this the type of effect which you're trying to generate?

Code: QB64: [Select]
  1. Width 80, 50
  2.  
  3.     Cls
  4.     Print Time$
  5.     DrawText 5, 40, "Second Hand on Clock", (Timer Mod 60) * 6
  6.     _Limit 60
  7.  
  8.  
  9.  
  10. Sub DrawText (x, y, Text$, angle)
  11.     Dim ScreenArray(_Width, _Height) As _Byte
  12.     A = _D2R(angle - 90)
  13.     For i = 1 To Len(Text$)
  14.         t = Asc(Text$, i)
  15.         Do
  16.             xPos = x + Sin(A) * radius: If xPos < 1 Or xPos > _Height Then Exit Do
  17.             yPos = y + Cos(A) * radius: If yPos < 1 Or yPos > _Width Then Exit Do
  18.  
  19.             If ScreenArray(yPos, xPos) = 0 Then ScreenArray(yPos, xPos) = t: Exit Do
  20.             radius = radius + 1
  21.         Loop
  22.     Next
  23.     For x = 1 To _Width
  24.         For y = 1 To _Height
  25.             If ScreenArray(x, y) Then
  26.                 _PrintString (x, y), Chr$(ScreenArray(x, y))
  27.             End If
  28.         Next
  29.     Next

It's a pretty little SCREEN 0 clock hand!  ;D

EDIT: Added some error checking for when the text might try to print off screen for us.
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 28, 2021, 03:46:49 pm
Now, let me start off by apologizing and saying that I haven't actually tried any of the code in this topic at all.  Life has had me busy as heck the last few weeks, and all I've did is skim this topic and view the pretty images.  From what I gather, is this the type of effect which you're trying to generate?

Code: QB64: [Select]
  1. Width 80, 50
  2.  
  3.     Cls
  4.     Print Time$
  5.     DrawText 5, 40, "Second Hand on Clock", (Timer Mod 60) * 6
  6.     _Limit 60
  7.  
  8.  
  9.  
  10. Sub DrawText (x, y, Text$, angle)
  11.     Dim ScreenArray(_Width, _Height) As _Byte
  12.     A = _D2R(angle - 90)
  13.     For i = 1 To Len(Text$)
  14.         t = Asc(Text$, i)
  15.         Do
  16.             xPos = x + Sin(A) * radius: If xPos < 1 Or xPos > _Height Then Exit Do
  17.             yPos = y + Cos(A) * radius: If yPos < 1 Or yPos > _Width Then Exit Do
  18.  
  19.             If ScreenArray(yPos, xPos) = 0 Then ScreenArray(yPos, xPos) = t: Exit Do
  20.             radius = radius + 1
  21.         Loop
  22.     Next
  23.     For x = 1 To _Width
  24.         For y = 1 To _Height
  25.             If ScreenArray(x, y) Then
  26.                 _PrintString (x, y), Chr$(ScreenArray(x, y))
  27.             End If
  28.         Next
  29.     Next

It's a pretty little SCREEN 0 clock hand!  ;D

EDIT: Added some error checking for when the text might try to print off screen for us.

Thanks @SMcNeill  for your reply.
So if I'm understanding the code right, it checks to see if the point we're rotating to is occupied, and if it is, it simply increases the radius by 1 and tries moving the point there?
That's so much easier than what I was trying and discussing with @STxAxTIC.
Very elegant... if I can get it to work!
The problem I'm having is when I try translating it to rotate a 2D array, it just stays stuck at 180 degrees...?
Your code didn't really declare the variables, am I maybe breaking something by declaring something the wrong type?
I'm sure it's due to some dumb error on my part...

Code: QB64: [Select]
  1. ' Uses SMcNeill's solution to rotation plotting 2 points to the same coordinates
  2. ' https://qb64forum.alephc.xyz/index.php?action=post;quote=139325;topic=4502.0
  3.  
  4. Const FALSE = 0
  5. Const TRUE = Not FALSE
  6. Dim Shared m_ProgramPath$: m_ProgramPath$ = Left$(Command$(0), _InStrRev(Command$(0), "\"))
  7. Dim Shared m_ProgramName$: m_ProgramName$ = Mid$(Command$(0), _InStrRev(Command$(0), "\") + 1)
  8. Dim Shared m_bDebug As Integer : m_bDebug = FALSE
  9. Dim Shared m_iMapMinX As Integer: m_iMapMinX = 1
  10. Dim Shared m_iMapMaxX As Integer: m_iMapMaxX = 32
  11. Dim Shared m_iMapMinY As Integer: m_iMapMinY = 1
  12. Dim Shared m_iMapMaxY As Integer: m_iMapMaxY = 32
  13. Dim Shared m_arrText(m_iMapMinX To m_iMapMaxX, m_iMapMinY To m_iMapMaxY) As String
  14. Dim Shared m_arrNew(m_iMapMinX To m_iMapMaxX, m_iMapMinY To m_iMapMaxY) As String
  15.  
  16. ' ACTIVATE DEBUGGING WINDOW
  17. IF m_bDebug = TRUE THEN
  18.         $Console
  19.         _Delay 4
  20.         _Console On
  21.         _Echo "Started " + m_ProgramName$
  22.         _Echo "Debugging on..."
  23.  
  24. Dim in$
  25. main
  26. 'input "PRESS <ENTER> TO EXIT";in$
  27.  
  28. ' DISABLE DEBUGGING
  29. IF m_bDebug = TRUE THEN
  30.         _Console Off
  31.  
  32. ' /////////////////////////////////////////////////////////////////////////////
  33.  
  34. sub main
  35.         dim iAngle as integer
  36.         Width 80, 80
  37.         StringToArray m_arrText(), SteveText1$
  38.         Do
  39.                 for iAngle = 0 to 360
  40.                         DrawText iAngle
  41.                         input "PRESS <ENTER> TO CONTINUE OR q TO QUIT";in$
  42.                         if in$="q" then exit do
  43.                 next iAngle
  44.                 for iAngle = 360 to 0 step -1
  45.                         DrawText iAngle
  46.                         input "PRESS <ENTER> TO CONTINUE OR q TO QUIT";in$
  47.                         if in$="q" then exit do
  48.                 next iAngle
  49.                 _Limit 1
  50.         Loop Until _KeyHit
  51. end sub ' main
  52.  
  53. ' /////////////////////////////////////////////////////////////////////////////
  54.  
  55. Sub DrawText (angle)
  56.         dim x as integer
  57.         dim y as integer
  58.     dim A
  59.         dim i
  60.         dim t as string
  61.         dim xPos
  62.         dim yPos
  63.         dim radius
  64.         dim sLine as string
  65.         dim iBefore as integer
  66.         dim iAfter as integer
  67.         dim iMissing as integer
  68.         dim in$
  69.        
  70.         ' init rotated matrix m_arrNew
  71.         ' and count characters in original matrix m_arrText
  72.         iBefore = 0
  73.         for y = m_iMapMinY to m_iMapMaxY
  74.                 for x = m_iMapMinX to m_iMapMaxX
  75.                         if m_arrText(x, y) <> "." then
  76.                                 iBefore = iBefore + 1
  77.                         end if
  78.                         m_arrNew(x, y) = "."
  79.                 next x
  80.         next y
  81.        
  82.         ' rotate all points in matrix m_arrText
  83.         ' plotting them to m_arrNew
  84.         for y = m_iMapMinY to m_iMapMaxY
  85.                 for x = m_iMapMinX to m_iMapMaxX
  86.                         A = _D2R(angle - 90) ' The _D2R function converts a degree value into a radian value.
  87.                         t = m_arrText(x, y)
  88.                        
  89.                         IF m_bDebug = TRUE THEN
  90.                                 _echo "rotating " + chr$(34) + t + chr$(34) + " from x=" + _Trim$(Str$(x)) + ", " + "y=" + _Trim$(Str$(y))
  91.                         END IF
  92.                        
  93.                         radius = 0
  94.                         Do
  95.                                 xPos = x + Sin(A) * radius
  96.                                 If xPos < m_iMapMinX Or xPos > m_iMapMaxX Then
  97.                                         IF m_bDebug = TRUE THEN
  98.                                                 _echo "    illegal xPos: " + _Trim$(Str$(xPos))
  99.                                         END IF
  100.                                         Exit Do
  101.                                 end if
  102.                                
  103.                                 yPos = y + Cos(A) * radius
  104.                                 If yPos < m_iMapMinY Or yPos > m_iMapMaxY Then
  105.                                         IF m_bDebug = TRUE THEN
  106.                                                 _echo "    illegal yPos: " + _Trim$(Str$(yPos))
  107.                                         END IF
  108.                                         Exit Do
  109.                                 end if
  110.                                
  111.                                 If m_arrNew(xPos, yPos) = "." Then
  112.                                         m_arrNew(xPos, yPos) = t
  113.                                         IF m_bDebug = TRUE THEN
  114.                                                 _echo "    rotated " + chr$(34) + t + chr$(34) + " to x=" + _Trim$(Str$(x)) + ", " + "y=" + _Trim$(Str$(y))
  115.                                         END IF
  116.                                         Exit Do
  117.                                 end if
  118.                                
  119.                                 radius = radius + 1
  120.                                 IF m_bDebug = TRUE THEN
  121.                                         _echo "    increasing radius: " + _Trim$(Str$(radius))
  122.                                 END IF
  123.                         Loop
  124.                 next x
  125.         next y
  126.        
  127.         ' show the rotated matrix
  128.         cls
  129.         print "Angle: " + _Trim$(Str$(angle))
  130.         iAfter = 0
  131.         For y = m_iMapMinY To m_iMapMaxY
  132.                 sLine = ""
  133.                 For x = m_iMapMinX To m_iMapMaxX
  134.                         sLine = sLine + m_arrNew(x,y)
  135.                         ' count the characters in the new rotated matrix
  136.                         if m_arrNew(x, y) <> "." then
  137.                                 iAfter = iAfter + 1
  138.                         end if
  139.                 Next x
  140.                 print sLine
  141.         Next y
  142.        
  143.         ' if any characters are missing, show how many
  144.         iMissing = iBefore - iAfter
  145.         if iMissing > 0 then
  146.                 print "# points missing: " + _Trim$(Str$(iMissing))
  147.         end if
  148.        
  149. End Sub ' DrawText
  150.  
  151. ' /////////////////////////////////////////////////////////////////////////////
  152.  
  153. Function SteveText1$
  154.     Dim m$
  155.     m$ = ""
  156.     '                   11111111112222222222333
  157.     '          12345678901234567890123456789012
  158.     m$ = m$ + "................................" + Chr$(13) ' 1
  159.     m$ = m$ + "................................" + Chr$(13) ' 2
  160.     m$ = m$ + "................................" + Chr$(13) ' 3
  161.     m$ = m$ + "................................" + Chr$(13) ' 4
  162.     m$ = m$ + "................................" + Chr$(13) ' 5
  163.     m$ = m$ + "................................" + Chr$(13) ' 6
  164.     m$ = m$ + "................................" + Chr$(13) ' 7
  165.     m$ = m$ + "................................" + Chr$(13) ' 8
  166.     m$ = m$ + "................................" + Chr$(13) ' 9
  167.     m$ = m$ + "................................" + Chr$(13) ' 10
  168.     m$ = m$ + "................................" + Chr$(13) ' 11
  169.     m$ = m$ + "................................" + Chr$(13) ' 12
  170.     m$ = m$ + "................................" + Chr$(13) ' 13
  171.     m$ = m$ + "................................" + Chr$(13) ' 14
  172.     m$ = m$ + "......Second.Hand.on.Clock......" + Chr$(13) ' 15
  173.     m$ = m$ + "................................" + Chr$(13) ' 16
  174.     m$ = m$ + "................................" + Chr$(13) ' 17
  175.     m$ = m$ + "................................" + Chr$(13) ' 18
  176.     m$ = m$ + "................................" + Chr$(13) ' 19
  177.     m$ = m$ + "................................" + Chr$(13) ' 20
  178.     m$ = m$ + "................................" + Chr$(13) ' 21
  179.     m$ = m$ + "................................" + Chr$(13) ' 22
  180.     m$ = m$ + "................................" + Chr$(13) ' 23
  181.     m$ = m$ + "................................" + Chr$(13) ' 24
  182.     m$ = m$ + "................................" + Chr$(13) ' 25
  183.     m$ = m$ + "................................" + Chr$(13) ' 26
  184.     m$ = m$ + "................................" + Chr$(13) ' 27
  185.     m$ = m$ + "................................" + Chr$(13) ' 28
  186.     m$ = m$ + "................................" + Chr$(13) ' 29
  187.     m$ = m$ + "................................" + Chr$(13) ' 30
  188.     m$ = m$ + "................................" + Chr$(13) ' 31
  189.     m$ = m$ + "................................" + Chr$(13) ' 32
  190.     SteveText1$ = m$
  191. End Function ' SteveText1$
  192.  
  193. ' /////////////////////////////////////////////////////////////////////////////
  194.  
  195. Function PetrText1$
  196.     Dim m$
  197.     m$ = ""
  198.     '                   11111111112222222222333
  199.     '          12345678901234567890123456789012
  200.     m$ = m$ + "................................" + Chr$(13) ' 1
  201.     m$ = m$ + "................................" + Chr$(13) ' 2
  202.     m$ = m$ + "................................" + Chr$(13) ' 3
  203.     m$ = m$ + "................................" + Chr$(13) ' 4
  204.     m$ = m$ + "................................" + Chr$(13) ' 5
  205.     m$ = m$ + "................................" + Chr$(13) ' 6
  206.     m$ = m$ + "................................" + Chr$(13) ' 7
  207.     m$ = m$ + "................................" + Chr$(13) ' 8
  208.     m$ = m$ + "................................" + Chr$(13) ' 9
  209.     m$ = m$ + "................................" + Chr$(13) ' 10
  210.     m$ = m$ + "................................" + Chr$(13) ' 11
  211.     m$ = m$ + "................................" + Chr$(13) ' 12
  212.     m$ = m$ + "................................" + Chr$(13) ' 13
  213.     m$ = m$ + "................................" + Chr$(13) ' 14
  214.     m$ = m$ + "....It's a SCREEN resolution?..." + Chr$(13) ' 15
  215.     m$ = m$ + "................................" + Chr$(13) ' 16
  216.     m$ = m$ + "................................" + Chr$(13) ' 17
  217.     m$ = m$ + "................................" + Chr$(13) ' 18
  218.     m$ = m$ + "................................" + Chr$(13) ' 19
  219.     m$ = m$ + "................................" + Chr$(13) ' 20
  220.     m$ = m$ + "................................" + Chr$(13) ' 21
  221.     m$ = m$ + "................................" + Chr$(13) ' 22
  222.     m$ = m$ + "................................" + Chr$(13) ' 23
  223.     m$ = m$ + "................................" + Chr$(13) ' 24
  224.     m$ = m$ + "................................" + Chr$(13) ' 25
  225.     m$ = m$ + "................................" + Chr$(13) ' 26
  226.     m$ = m$ + "................................" + Chr$(13) ' 27
  227.     m$ = m$ + "................................" + Chr$(13) ' 28
  228.     m$ = m$ + "................................" + Chr$(13) ' 29
  229.     m$ = m$ + "................................" + Chr$(13) ' 30
  230.     m$ = m$ + "................................" + Chr$(13) ' 31
  231.     m$ = m$ + "................................" + Chr$(13) ' 32
  232.     PetrText1$ = m$
  233. End Function ' PetrText1$
  234.  
  235. ' /////////////////////////////////////////////////////////////////////////////
  236.  
  237. Sub StringToArray (MyArray() As String, MyString As String)
  238.     Dim delim$
  239.     ReDim arrLines$(0)
  240.     Dim iRow%
  241.     Dim iCol%
  242.     Dim sChar$
  243.     Dim iDim1 As Integer
  244.     Dim iDim2 As Integer
  245.     iDim1 = LBound(MyArray, 1)
  246.     iDim2 = LBound(MyArray, 2)
  247.     delim$ = Chr$(13)
  248.     split MyString, delim$, arrLines$()
  249.     For iRow% = LBound(arrLines$) To UBound(arrLines$)
  250.         If iRow% <= UBound(MyArray, 2) Then
  251.             For iCol% = 1 To Len(arrLines$(iRow%))
  252.                 If iCol% <= UBound(MyArray, 1) Then
  253.                     sChar$ = Mid$(arrLines$(iRow%), iCol%, 1)
  254.  
  255.                     If Len(sChar$) > 1 Then
  256.                         sChar$ = Left$(sChar$, 1)
  257.                     Else
  258.                         If Len(sChar$) = 0 Then
  259.                             sChar$ = "."
  260.                         End If
  261.                     End If
  262.                     MyArray(iRow% + iDim1, (iCol% - 1) + iDim2) = sChar$
  263.                 Else
  264.                     ' Exit if out of bounds
  265.                     Exit For
  266.                 End If
  267.             Next iCol%
  268.         Else
  269.             ' Exit if out of bounds
  270.             Exit For
  271.         End If
  272.     Next iRow%
  273. End Sub ' StringToArray
  274.  
  275. ' /////////////////////////////////////////////////////////////////////////////
  276.  
  277. 'SUB ClearArray (MyArray(1 To 32, 1 To 32) AS STRING, MyString As String)
  278. Sub ClearArray (MyArray() As String, MyString As String)
  279.     Dim iRow As Integer
  280.     Dim iCol As Integer
  281.     Dim sChar$
  282.     If Len(MyString) = 1 Then
  283.         sChar$ = MyString
  284.     Else
  285.         If Len(MyString) = 0 Then
  286.             sChar$ = " "
  287.         Else
  288.             sChar$ = Left$(MyString, 1)
  289.         End If
  290.     End If
  291.     For iRow = LBound(MyArray, 1) To UBound(MyArray, 1)
  292.         For iCol = LBound(MyArray, 2) To UBound(MyArray, 2)
  293.             MyArray(iRow, iCol) = sChar$
  294.         Next iCol
  295.     Next iRow
  296. End Sub ' ClearArray
  297.  
  298. ' /////////////////////////////////////////////////////////////////////////////
  299. ' Split and join strings
  300. ' https://www.qb64.org/forum/index.php?topic=1073.0
  301. '
  302. ' FROM luke, QB64 Developer
  303. ' Date: February 15, 2019, 04:11:07 AM »
  304. '
  305. ' Given a string of words separated by spaces (or any other character),
  306. ' splits it into an array of the words. I've no doubt many people have
  307. ' written a version of this over the years and no doubt there's a million
  308. ' ways to do it, but I thought I'd put mine here so we have at least one
  309. ' version. There's also a join function that does the opposite
  310. ' array -> single string.
  311. '
  312. ' Code is hopefully reasonably self explanatory with comments and a little demo.
  313. ' Note, this is akin to Python/JavaScript split/join, PHP explode/implode.
  314.  
  315. 'Split in$ into pieces, chopping at every occurrence of delimiter$. Multiple consecutive occurrences
  316. 'of delimiter$ are treated as a single instance. The chopped pieces are stored in result$().
  317. '
  318. 'delimiter$ must be one character long.
  319. 'result$() must have been REDIMmed previously.
  320.  
  321. ' Modified to handle multi-character delimiters
  322.  
  323. Sub split (in$, delimiter$, result$())
  324.     Dim start As Integer
  325.     Dim finish As Integer
  326.     Dim iDelimLen As Integer
  327.     ReDim result$(-1)
  328.  
  329.     iDelimLen = Len(delimiter$)
  330.  
  331.     start = 1
  332.     Do
  333.         'While Mid$(in$, start, 1) = delimiter$
  334.         While Mid$(in$, start, iDelimLen) = delimiter$
  335.             'start = start + 1
  336.             start = start + iDelimLen
  337.             If start > Len(in$) Then
  338.                 Exit Sub
  339.             End If
  340.         Wend
  341.         finish = InStr(start, in$, delimiter$)
  342.         If finish = 0 Then
  343.             finish = Len(in$) + 1
  344.         End If
  345.  
  346.         ReDim _Preserve result$(0 To UBound(result$) + 1)
  347.  
  348.         result$(UBound(result$)) = Mid$(in$, start, finish - start)
  349.         start = finish + 1
  350.     Loop While start <= Len(in$)
  351. End Sub ' split
  352.  

Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 28, 2021, 06:20:10 pm
Now, let me start off by apologizing and saying that I haven't actually tried any of the code in this topic at all.  Life has had me busy as heck the last few weeks, and all I've did is skim this topic and view the pretty images.  From what I gather, is this the type of effect which you're trying to generate?

Code: QB64: [Select]
  1. Width 80, 50
  2.  
  3.     Cls
  4.     Print Time$
  5.     DrawText 5, 40, "Second Hand on Clock", (Timer Mod 60) * 6
  6.     _Limit 60
  7.  
  8.  
  9.  
  10. Sub DrawText (x, y, Text$, angle)
  11.     Dim ScreenArray(_Width, _Height) As _Byte
  12.     A = _D2R(angle - 90)
  13.     For i = 1 To Len(Text$)
  14.         t = Asc(Text$, i)
  15.         Do
  16.             xPos = x + Sin(A) * radius: If xPos < 1 Or xPos > _Height Then Exit Do
  17.             yPos = y + Cos(A) * radius: If yPos < 1 Or yPos > _Width Then Exit Do
  18.  
  19.             If ScreenArray(yPos, xPos) = 0 Then ScreenArray(yPos, xPos) = t: Exit Do
  20.             radius = radius + 1
  21.         Loop
  22.     Next
  23.     For x = 1 To _Width
  24.         For y = 1 To _Height
  25.             If ScreenArray(x, y) Then
  26.                 _PrintString (x, y), Chr$(ScreenArray(x, y))
  27.             End If
  28.         Next
  29.     Next

It's a pretty little SCREEN 0 clock hand!  ;D

EDIT: Added some error checking for when the text might try to print off screen for us.

In fact, I'm having trouble just using the formula to calculate any values at all...
What am I doing wrong?

Code: QB64: [Select]
  1. dim angle as integer
  2. dim A
  3. dim radius
  4. dim xPos
  5. dim yPos
  6. dim in$
  7.  
  8. radius = 0
  9. x = 10
  10. y = 10
  11. For angle = 20 to 40
  12.         A = _D2R(angle - 90) ' The _D2R function converts a degree value into a radian value.
  13.         yPos = y + Cos(A) * radius
  14.         xPos = x + Sin(A) * radius
  15.        
  16.         print _Trim$(Str$(x)) + "," + _Trim$(Str$(y)) + _
  17.                 " rotated to " + _Trim$(Str$(angle)) + " deg = " + _
  18.                 _Trim$(Str$(xPos)) + "," + _Trim$(Str$(yPos))
  19. Next angle
  20.  
  21. input "PRESS <ENTER> TO CONTINUE";in$
  22.  

Update: I tried changing everything to the same data type (tried double and single), but still no change.
This is one of those days where I feel like I can't program my way out of a wet paper bag! :-p

Code: QB64: [Select]
  1. Width 80, 80
  2.  
  3. Dim angle As Double
  4. Dim radius As Double
  5. Dim in$
  6.  
  7. radius = 0
  8. x = 10
  9. y = 10
  10. For angle = 0 To 45
  11.     A = _D2R(angle - 90) ' The _D2R function converts a degree value into a radian value.
  12.     yPos = y + Cos(A) * radius
  13.     xPos = x + Sin(A) * radius
  14.  
  15.     print "" + _
  16.         "A=" + _Trim$(Str$(A)) + _
  17.         "Cos(A) = " + _Trim$(Str$(Cos(A))) + _
  18.         _Trim$(Str$(x)) + "," + _Trim$(Str$(y)) + _
  19.         " rotated to " + _Trim$(Str$(angle)) + " deg = " + _
  20.         _Trim$(Str$(xPos)) + "," + _Trim$(Str$(yPos))
  21. Next angle
  22.  
  23. Input "PRESS <ENTER> TO CONTINUE"; in$
  24.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: SMcNeill on December 28, 2021, 10:35:47 pm
Let me just go through what I've got here, and I'll explain the process for you line by line (more or less).

The whole:

Code: [Select]
Sub DrawText (x, y, Text$, angle)
    Dim ScreenArray(_Width, _Height) As _Byte
    A = _D2R(angle - 90)
    For i = 1 To Len(Text$)
        t = Asc(Text$, i)
        Do
            xPos = x + Sin(A) * radius: If xPos < 1 Or xPos > _Height Then Exit Do
            yPos = y + Cos(A) * radius: If yPos < 1 Or yPos > _Width Then Exit Do

            If ScreenArray(yPos, xPos) = 0 Then ScreenArray(yPos, xPos) = t: Exit Do
            radius = radius + 1
        Loop
    Next
    For x = 1 To _Width
        For y = 1 To _Height
            If ScreenArray(x, y) Then
                _PrintString (x, y), Chr$(ScreenArray(x, y))
            End If
        Next
    Next
End Sub

And now to dissect that whole:

Sub DrawText (x, y, Text$, angle) --- X and Y here represent the center point of where we want to place our text.  TEXT$ is what we want to place onto the screen, and ANGLE is the amount of rotation we want that text to have.

    Dim ScreenArray(_Width, _Height) As _Byte  --- This creates an array for us the same size as our text screen.  All the work I[m doing is going to take place within this array, until I'm actually ready to draw onto the screen itself.

    A = _D2R(angle - 90) --- This is our angle conversion from degrees to radians, with a correction to start in the top center of our circle, just as a clock starts with 12 o'clock as being up at the very top.

    For i = 1 To Len(Text$)  ---   This line runs us a loop from the first letter in our text to the last letter of the text, so we can figure out where to place each character correctly.

        t = Asc(Text$, i) --- Here, I'm just getting the character that I want to work with out of that whole length of text.

        Do --- This starts the internal loop for determining proper positioning

            xPos = x + Sin(A) * radius: If xPos < 1 Or xPos > _Height Then Exit Do  --- A two part line.  The first calculates where to put the text on the screen.  x is our original center.  SIN(A) is the angle we're rotating by.  RADIUS is how far from the center we need to go to place this character.   IF this calculated xPOSition is off the screen -- either by being off the top (less than 1) or off the right (greater than our _HEIGHT of the screen), we can now quit calculating as we can't actually plot this character.  It's off the screen, after all!

            yPos = y + Cos(A) * radius: If yPos < 1 Or yPos > _Width Then Exit Do  --- This is basically the same as the line above, except it calculates our y position.  (Remember, in SCREEN 0 x and y are reversed as they actually represent row and column rather than width and height.)

            If ScreenArray(yPos, xPos) = 0 Then ScreenArray(yPos, xPos) = t: Exit Do  ---  Now, this line basically checks to see if we've plotted to this point already.  Sometimes, as you've noticed yourself, characters might try to overlap.  If this character wants to overlap with a previous one, we simply don't draw it yet and move on with the process to actually calculate where to draw it.

            radius = radius + 1  ---  If we haven't plotted our character yet, then we simply increase the radius by one to move it out another point to recalculate the proper spot.

        Loop  ---  And then we repeat the process until we either find the right spot for this character, or we determine it's going to be off the screen.

    Next  --- If we've gotten to this point, we have now decided either where to place our specific character, or else we've decided that the character in question is going to off the screen.   We can now move on to the next character, until we go through the process for the whole string of text.


    For x = 1 To _Width
        For y = 1 To _Height
            If ScreenArray(x, y) Then
                _PrintString (x, y), Chr$(ScreenArray(x, y))
            End If
        Next
    Next
End Sub


And, I think I can more or less explain this whole batch of code here by simply saying, "This is where we actually check our finished array for our text values, and then simply print them to the corresponding spots on our text screen.



The whole process is actually rather simple, and here's the logic behind it:

Make a blank array the same size as the screen.

Since that array is blank, all the values for it default and start at zero.

Calculate the position for each character we want to plot to the screen.

Check that position vs our array.  If the array is zero (blank) in the spot where we want to put our text, let the array hold the character value that we're going to print.  Otherwise, simply move out another point on the radius and check again, until we find an empty spot in that array to put our text, or determine we've went off-screen.

Once we've did this for all our characters, all we have to do is simply run that array through a loop and LOCATE/PRINT to the screen in the corresponding positions to our array.

It's that simple of a process.

Calculate the position of a character centered at X/Y, with a radius of 0, at the desired angle.
Save that character's position
DO
    Calculate the position of a character centered at X/Y, with a radius of 1, at the desired angle.
    IF that position isn't already written to, save it.  Otherwise, increase the radius by 1 and try again.
LOOP until we're done with all our characters.
Finally plot those saved positions to the screen.
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: SMcNeill on December 28, 2021, 10:54:06 pm
Update: I tried changing everything to the same data type (tried double and single), but still no change.
This is one of those days where I feel like I can't program my way out of a wet paper bag! :-p

Code: QB64: [Select]
  1. Width 80, 80
  2.  
  3. Dim angle As Double
  4. Dim radius As Double
  5. Dim in$
  6.  
  7. radius = 0
  8. x = 10
  9. y = 10
  10. For angle = 0 To 45
  11.     A = _D2R(angle - 90) ' The _D2R function converts a degree value into a radian value.
  12.     yPos = y + Cos(A) * radius
  13.     xPos = x + Sin(A) * radius
  14.  
  15.     print "" + _
  16.         "A=" + _Trim$(Str$(A)) + _
  17.         "Cos(A) = " + _Trim$(Str$(Cos(A))) + _
  18.         _Trim$(Str$(x)) + "," + _Trim$(Str$(y)) + _
  19.         " rotated to " + _Trim$(Str$(angle)) + " deg = " + _
  20.         _Trim$(Str$(xPos)) + "," + _Trim$(Str$(yPos))
  21. Next angle
  22.  
  23. Input "PRESS <ENTER> TO CONTINUE"; in$
  24.  

Itis calculating exactly where you told it to calculate for you:

Centered at X/Y, rotated at ANGLE degrees, with a RADIUS of 0 from that center point.   You're going around in circles at the center point of your circle!!

See how the values change when you increase the radius away from the center:

Code: [Select]
Screen _NewImage(800, 600, 32)

Dim angle As Integer
Dim x As Integer
Dim y As Integer
Dim A
Dim radius
Dim xPos
Dim yPos
Dim in$

For radius = 0 To 10
    Cls
    x = 10
    y = 10
    For angle = 20 To 40
        A = _D2R(angle - 90) ' The _D2R function converts a degree value into a radian value.
        yPos = y + Cos(A) * radius
        xPos = x + Sin(A) * radius
        Print Using "(###/###) rotated to ## degrees with a radius of ## = ###/###"; x, y, angle, radius, xPos, yPos
    Next angle

    Input "PRESS <ENTER> TO CONTINUE"; in$

Next

For a quick illustration of what you're doing, grab a pencil.  Stick it onto the piece of paper with the pencil completely vertical to a single point.  Now, rotate that pencil...   You're turning it, but there's no change in the point where it's located, now is there??

That's why a compass has two points on it -- one with the sharp looking little needle end, and the other with the pencil itself.  The sharp point goes into the center of your circle, you adjust your compass to the desired length (radius), and then rotate from the desired angles to either create your circle, or the arc of a circle. 

Your code is working fine.  Well, it is, as long as you simply want it to rotate that single point which makes the center of a one pixel circle (point) at 10, 10.  ;)
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 28, 2021, 11:13:31 pm
Itis calculating exactly where you told it to calculate for you:

Centered at X/Y, rotated at ANGLE degrees, with a RADIUS of 0 from that center point.   You're going around in circles at the center point of your circle!!

See how the values change when you increase the radius away from the center:

...

For a quick illustration of what you're doing, grab a pencil.  Stick it onto the piece of paper with the pencil completely vertical to a single point.  Now, rotate that pencil...   You're turning it, but there's no change in the point where it's located, now is there??

That's why a compass has two points on it -- one with the sharp looking little needle end, and the other with the pencil itself.  The sharp point goes into the center of your circle, you adjust your compass to the desired length (radius), and then rotate from the desired angles to either create your circle, or the arc of a circle. 

Your code is working fine.  Well, it is, as long as you simply want it to rotate that single point which makes the center of a one pixel circle (point) at 10, 10.  ;)

OK that makes sense... Silly me!
Thanks for explaining.
I still need to figure out how to translate this to work for a 64x64 (or whatever size) grid, but at least I'm not going around in circles (pun intended).
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 29, 2021, 09:17:04 am
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:

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.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: STxAxTIC on December 29, 2021, 10:24:13 am
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.

  [ This attachment cannot be displayed inline in 'Print Page' view ]  



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].
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 29, 2021, 11:33:34 am
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:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Here is 31 degrees:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

And here is what we get when we try merging:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

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:
^^ 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.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 29, 2021, 12:06:08 pm
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.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 29, 2021, 04:54:01 pm
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.  
Title: Re: 3-shear rotation issue rotating to 30, 60, 120, 150, 210, 240, 300, 330 degrees
Post by: madscijr on December 29, 2021, 05:01:41 pm
SheerRotate4 vs SheerRotate6:

29 degrees (same for all versions):
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

30 degrees with SheerRotate4:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

30 degrees with SheerRotate6:
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

31 degrees (same for all versions):
  [ This attachment cannot be displayed inline in 'Print Page' view ]