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

0 Members and 1 Guest are viewing this topic.

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
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.  
« Last Edit: December 20, 2021, 09:29:59 pm by madscijr »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
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.  

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
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.
« Last Edit: December 21, 2021, 04:32:11 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
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.  

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
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!

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
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:
  [ You are not allowed to view this attachment ]  

New logic (ShearRotateTest3) has a lot less lost points:
  [ You are not allowed to view this attachment ]  


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

Old logic (ShearRotateTest2) has lost points:
  [ You are not allowed to view this attachment ]  

New logic (ShearRotateTest3) has no lost points:
  [ You are not allowed to view this attachment ]  


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.  
« Last Edit: December 21, 2021, 02:41:39 pm by madscijr »

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
    • View Profile
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.

« Last Edit: December 23, 2021, 12:14:08 pm by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
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!

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
@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

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.  

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
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.
« Last Edit: December 23, 2021, 03:14:46 pm by SMcNeill »
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
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.  

« Last Edit: December 28, 2021, 03:52:58 pm by madscijr »

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
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.  
« Last Edit: December 28, 2021, 10:11:12 pm by madscijr »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
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.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
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.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline madscijr

  • Seasoned Forum Regular
  • Posts: 295
    • View Profile
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).