by einander
PB 3.93
Draws lines and polygons using a string of commands, coordinates and angles, based on HPGL plotter and LOGO turtle graphics.
Angles are entered betweeen 0 And 3600. The following commands are available:
FD n Moves the drawing pencil n pixels Forward
BK n Moves the drawing pencil n pixels Backwards
LT a Turns the drawing pencil Left a/10 degrees
RT a Turns the drawing pencil Right a/10 degrees
MA a Turns the drawing pencil to Absolute Angle a/10 degrees, pointing as follows:
a= 0 Or 3600 Right
a= 900 Down
a= 1800 Left
a= 2700 Up
PU Lifts the pen Up; move without drawing
PD Lowers the pen Down to draw (Default)
AT X Y Sets pencil position At Absolute coordinates X Y without drawing - Ignores Pen Down
To X Y Draws line from actual pen position To Absolute coordinates X Y - Ignores Pen Up
CO c Sets drawing colour To c
PW w Sets pen Width To w
If command succeeds, it returns the address where last used values are stored, as 5 Longs
These values are:
Addr : X position
Addr+4 : Y position
Addr+8 : Pen Width
Addr+12 : Pen Color
Addr+16 : Absolute Angle*10
If Command fails, it returns 0
The parameters for individual commands must be specified using strings - See example.
Syntax: Turtle(DC, Command$)
DC = Device Context handle , as returned by StartDrawing()
Command$= string with commands to move pen, case insensitive, using commas or spaces as separators.
Beware of missing inner separators!
Code: Select all
    #Deg2rad=3.14159265 / 1800
    Structure Dat
        X.l
        Y.l
        Wid.l
        RGB.l
        Angle.l
    EndStructure
    
Procedure Turtle(DC,C$)
    Static X,Y,Ang.f,Angle.l,Wid,RGB,PenUp
    P.Dat
    If Wid=0:Wid=1:EndIf                   ; default pen width
    C$=UCase(C$)
    ReplaceString(C$,","," ",2)         ; comma to  SPC
    C$=ReplaceString(C$,"  "," ")    ; double SPC to single SPC
    Repeat                                           ; HEX to DEC
        INS= FindString(C$,"$",1)
        If INS=0 :Break 
        Else
            a$=StringField(Mid(C$,INS,Len(C$)),1," ")
            LE=Len(a$)
            For i=2 To LE
                Dec<<4 : D$=Mid(a$,i,1)
                a=PeekB(@D$)
                If a>60 : Dec+a-55
                Else : Dec+a-48
                EndIf
            Next
            C$= ReplaceString(C$,a$,Str(Dec))
        EndIf
    ForEver
    C$=Trim(C$)
 
    Repeat              ; parser
        Po+1 : a$=StringField(C$,Po," ") ; command
        If a$="":Break:EndIf
        Select a$      
            Case "FD"
                Po+1:Val=Val(StringField(C$,Po," ")) 
                X+Val*Cos(Ang)  :  Y+Val*Sin(Ang) 
                If PenUp=0  ; if Penup =1 , keep position without drawing
                    pen=CreatePen_(#PS_SOLID,Wid,RGB)  
                    SelectObject_(DC,pen) 
                    LineTo_(DC,X,Y) 
                    DeleteObject_(pen) 
                EndIf
            Case "BK" 
                Po+1:Val=Val(StringField(C$,Po," ")) 
                X-Val*Cos(-Ang)  :  Y-Val*Sin(-Ang) 
                If PenUp=0 
                    pen=CreatePen_(#PS_SOLID,Wid,RGB)  
                    SelectObject_(DC,pen) 
                    LineTo_(DC,X,Y) 
                    DeleteObject_(pen) 
                EndIf
            Case "PD" : PenUp=0
            Case "PU" : PenUp= 1
            Case "RT" 
                Po+1:Angle=Val(StringField(C$,Po," ")) 
                Ang+Angle*#Deg2rad
            Case"LT" 
                Po+1:Angle=Val(StringField(C$,Po," ")) 
                Ang-Angle*#Deg2rad
            Case "MA"
                Po+1:Angle=Val(StringField(C$,Po," ")) 
                Ang= Angle*#Deg2rad
            Case"CO" 
                Po+1:RGB=Val(StringField(C$,Po," ")) 
            Case "PW"
                Po+1:Wid=Val(StringField(C$,Po," ")) 
            Case "AT"
                Po+1:X=Val(StringField(C$,Po," "))
                Po+1:Y=Val(StringField(C$,Po," "))
                MoveToEx_(DC,X,Y,0)
            Case "TO"
                Po+1:X=Val(StringField(C$,Po," ")) 
                Po+1:Y=Val(StringField(C$,Po," ")) 
                pen=CreatePen_(#PS_SOLID,Wid,RGB)  
                SelectObject_(DC,pen) 
                LineTo_(DC,X,Y) 
                DeleteObject_(pen) 
            Default
 ;               MessageRequester("Error !","Unknown command "+Chr(13)+a$,0)
                ProcedureReturn 0  ; if unknown command
        EndSelect
    ForEver
    P\X=X
    P\Y=Y
    P\Wid=Wid
    P\RGB=RGB
    P\Angle=Angle
    ProcedureReturn @P
EndProcedure 
        ;______________________________________________________________________-
; TEST
OpenWindow(0,0,0,0,0,#WS_OVERLAPPEDWINDOW | #WS_MAXIMIZE,"PBTurtle - LogoParser")
XX=WindowWidth()/2 : YY=WindowHeight()/2
_D=StartDrawing(WindowOutput())  
Turtle(_D," PW 3 co "+Str(Random($FFFFFF)))   ; case insensitive, pen width=3, random color
Turtle(_D,"at 100 100 to 100 200 to 200 200 to 200 100 to 100 100") ; draw box from coordinates
Turtle(_D,"co 255 at "+Str(WindowWidth()-100)+ " 100 pd rt 900 fd 100 rt 900 fd 100 rt 900 fd 100 rt 900 fd 100" ) ; box from angles and sides
Turtle(_D,"at "+Str(XX)+" "+Str(YY))
;Octagon And cubes *********************************
For i=1 To 8
    For j=1 To 8
        Addr=Turtle(_D,"FD "+Str(50)+" RT 450")   ; replace 50 by any value or numeric variable 
        X=PeekL(Addr)
        Y=PeekL(Addr+4)
;        Wid=PeekL(Addr+8)
        Color=PeekL(Addr+12)
 ;       Angle=PeekL(Addr+16)
        Circle(X,Y,5,Color)
    Next
    Turtle(_D,"co "+Str(Random($FFFFFF))+" rT 450")  
Next
Turtle(_D,"at 150 150 pw 1 co $aaaaaa")   ; move to 150 150 without drawing , color gray
; ;rotanting Pentagons  *****************************************
For i=1 To 16
    For j=1 To 4 
        Turtle(_D,"FD 100 RT 900 ")
    Next
    Turtle(_D," RT 300")
Next
Turtle(_D,"PW 2 co 255 to "+Str(XX)+" "+Str(YY))   ; move to xx yy drawing red ; Don't forget inner separators!
Turtle (_D,"to "+Str(WindowWidth()-150)+" "+Str(150))
Circle(PeekL(Addr),PeekL(Addr+4),10,#Yellow)
Repeat
Until WaitWindowEvent()= #PB_Event_CloseWindow 
End 

