CAD.bas - A Fundamental CAD Program Written In MMBasic

CAD.bas

CAD.bas is a Computer Aided Drafting (CAD) app written in PicoMite MMBasic Ver 6.00.03 for the ClockWork PicoCalc with the RP2040 board. Although it has only six tools, 2D drawings such as 3 view drawings can be made with it. Because of the minimum number of tools, the learning curve is easy and short. Because of the small but high resolution PicoCalc screen, the drawings are very sharp and detailed.

It took Jim Williams, the author, about two months to complete this project. It would have taken much longer if Jim’s co-author had not been available. The co-author’s name is ChatGPT. Because MMBasic has so many, many versions, and because PicoMite MMBasic Ver 6.00.03 User’s Manual doesn’t have all of the graphic commands, syntax, etc., ChatGPT was instrumental in producing CAD.bas. With it, I learned a lot about programing and picked up some very valuable tricks along the way. Thank you ChatGPT!

CAD.bas User’s Manual:

PicoCalc Screen:

The Screen is only 3.8” X 3.8” but the resolution is 320 X 320 Pixels. CAD.bas renumbers the pixels so that the user draws in the first quadrant of the Cartesian Coordinate System. That is, the lower left hand pixel is (0,0) and the upper right hand pixel is (319, 319). So, each row has 320 pixels. However each column has only 304 pixels to draw on because the bottom 15 rows are used to write a Status Bar (or Command Line).

Status Bar:

The Status Bar at the bottom of the screen keeps the user informed as to what is going on at the present time. At the left end of the status Bar are the coordinates of the cursor (X,Y). This is always shown. Which tool is currently being used (Cursor, Line, or Circle) is shown next. Other data, just as Radius is shown next. and finally, the Line Type is shown. (The text changes color to indicate current line type.)

Cursor:

The program starts with an empty screen except for the cursor which shows up at the middle of the screen and the Status Bar shows (160,152). The PicoCalc’s arrow keys are used to move the cursor.

Line:

To draw a line, press the β€œL” key once. (Really, lower case β€œl”) Move the cursor to the pixel where the line is to start. (Look at coordinates in Status Bar) When cursor is at the correct position, press the Space Bar once. This will anchor the start end of the line. Now, draw the line by moving the cursor with the arrow keys. The display will show the line being drawn as the cursor is being moved. Notice that not only vertical and horizontal lines can be drawn, but also diagonal lines by using all four directional arrow keys. When the cursor gets to the place where the line is to end, press the space bar again. This will anchor the end of the line and the line will be committed to the drawing. A tap or two of the arrow keys will show the cursor moving away from this line and ready to start another line. At this stage, the program will stay in the Line (β€œL Mode”). That is, the β€œL” key does not have to be pressed to draw another line. Just move cursor to the next line starting point and press the space bar to start the next line. Note: If the second line starts at the end of the first line, just tap the space bar twice at the end of the first line and start dragging the second line.

Circle:

Drawing a circle is very similar to drawing a line. Begin by pressing the β€œC” key once. (Really, lower case β€œc”) Move the cursor to the pixel where the center of the circle will be. (Look at coordinates in Status Bar) When cursor is at the correct position, press the Space Bar once. This will anchor the circle’s center point. Now use either the Up or Right arrow keys to draw the circle. Notice that the Up and Right arrow keys increase the radius and the Down and Left arrow keys decrease the radius. The radius size (in pixels) is shown in the Status Bar. When the circle reaches the correct size, press the space bar again. This will anchor the circle and the circle will be committed to the drawing. Note: Move the cursor away from the circle’s center. This will leave the least gap in the circle. Move the cursor away from the center if you want to draw outside of the circle. Move the cursor in towards the center if you want to draw inside of the circle.

Line Type:

Dash hidden lines do not show up well on the PicoCalc. For this reason, I have used colored lines to distinguish line types. On this app, the normal solid line is green. By tapping β€œt”, (for Type) the user can toggle between green and blue. This can be done pretty much anywhere in the app. I get by on just these two colors. Green for solid lines and blue for both hidden lines and center lines. If other users need more line types, more colors can be easily added to the code – after all, it is just a Basic program.

Escape:

If you mess up while drawing a line or circle, tap Esc (Escape). This will take you back to the beginning of the routine where you need to press the space bar to anchor the first point. Tapping Esc two times will take you back to the cursor mode. Note: Changing from line mode to circle mode or vice versa, you do not have to go back to cursor mode. Just tapping β€œc” or β€œl” while in one mode will get you into the other mode.

Save / Open:

Tap β€œs” to save a drawing to the B: drive, the SD card. Tap β€œo” to open a drawing from the B: drive. The Status bar will ask for the File Name. NOTE: For both Save and Open, type in just the file name. The program will add the β€œB:” and the extension β€œ.txt” The drawing’s geometry is saved in a β€œtext” file which can be viewed on any computer that has anything like β€œNotepad”. This β€œtext” file can be edited to remove unwanted lines and circles.

NOTE: This is the first release of CAD.bas. Please contact Jim Williams (UtahPilot) if you find any bugs in the program and I will try to fix the problem. Thank you. - Jim

CLS
Clear
'----------------------------
’ Constants
'----------------------------
Const KEY_UP = 128
Const KEY_DOWN = 129
Const KEY_LEFT = 130
Const KEY_RIGHT = 131
Const KEY_L = 108
Const KEY_T = 116
Const KEY_C = 99
Const KEY_SP = 32
Const KEY_ESC = 27
Const KEY_S = 115
Const KEY_O = 111
Const TOOL_CURSOR = 0
Const TOOL_LINE = 1
Const TOOL_CIRCLE = 2
Const TYPE_SOLID = 0
Const TYPE_ALT = 1

'----------------------------
’ Declarations Globals
'----------------------------
Dim Integer X, Y, K
Dim String KS$
Dim Integer Tool
Dim Integer HiddenMode
’ Line tool globals
Dim Integer LineStage
Dim Integer StartX, StartY
Dim Integer PrevX, PrevY
Dim Integer PreviewDrawn
’ Circle tool globals
Dim Integer CircleStage
Dim Integer CX, CY, R
Dim Integer CirclePreviewDrawn
Dim Integer PrevR
’ Geometry Storage
Const MAX_LINES = 200
Const MAX_CIRCLES = 100
Const MAX_OBJECTS = MAX_LINES + MAX_CIRCLES
Dim Integer LineCount
Dim Integer LineX1(MAX_LINES), LineY1(MAX_LINES)
Dim Integer LineX2(MAX_LINES), LineY2(MAX_LINES)
Dim Integer LineType(MAX_LINES)
Dim Integer CircleCount
Dim Integer CircleX(MAX_CIRCLES), CircleY(MAX_CIRCLES)
Dim Integer CircleR(MAX_CIRCLES)
Dim Integer CircleType(MAX_CIRCLES)
Dim Integer ObjectCount
Dim Integer ObjectType(MAX_OBJECTS)

'----------------------------
’ Initialize
'----------------------------
CLS
Colour RGB(Green), RGB(Black)
Line 0,304,319,304,RGB(Blue) ’ baseline
X = 160
Y = 151
Tool = TOOL_CURSOR
LineCount = 0
CircleCount = 0

'----------------------------
’ Cursor/Eraser routines
'----------------------------
Sub DrawCursor
Colour RGB(Yellow)
Pixel X, Y
End Sub

Sub MoveCursor(K)
Colour RGB(Black)
Pixel X, Y
Select Case K
Case KEY_LEFT : X = X - 1
Case KEY_RIGHT : X = X + 1
Case KEY_UP : Y = Y - 1
Case KEY_DOWN : Y = Y + 1
End Select
If X < 0 Then X = 0
If X > 319 Then X = 319
If Y < 0 Then Y = 0
If Y > 302 Then Y = 302
DrawCursor
End Sub

'----------------------------
’ Color routine
'----------------------------
Sub SetDrawColor
If HiddenMode = 0 Then
Colour RGB(Green)
Else
Colour RGB(Blue)
End If
End Sub

'----------------------------
’ Line tool routines
'----------------------------
Sub DrawPreview
SetDrawColor
Line StartX, StartY, X, Y
PrevX = X
PrevY = Y
PreviewDrawn = 1
End Sub

Sub ErasePreview
If PreviewDrawn = 1 Then
Colour RGB(Black)
Line StartX, StartY, PrevX, PrevY
PreviewDrawn = 0
End If
End Sub

Sub CommitLine
ErasePreview
If LineCount < MAX_LINES Then
LineX1(LineCount) = StartX
LineY1(LineCount) = StartY
LineX2(LineCount) = X
LineY2(LineCount) = Y
LineType(LineCount) = HiddenMode
ObjectType(ObjectCount) = TOOL_LINE
LineCount = LineCount + 1
ObjectCount = ObjectCount + 1
End If
LineStage = 0
RedrawAll
DrawCursor
End Sub

Sub LineToolAction
If LineStage = 0 Then
StartX = X
StartY = Y
PrevX = X
PrevY = Y
LineStage = 1
PreviewDrawn = 0
Else
CommitLine
End If
End Sub

Sub LineToolMove
If LineStage = 1 Then
ErasePreview
DrawPreview
End If
End Sub

Sub LineToolCancel
If LineStage = 1 Then
ErasePreview
LineStage = 0
PreviewDrawn = 0
End If
End Sub

'----------------------------
’ Circle tool routines
'----------------------------
Sub DrawCirclePreview
If R < 0 Then R = 0
SetDrawColor
Circle CX, CY, R
PrevR = R
CirclePreviewDrawn = 1
End Sub

Sub EraseCirclePreview
If CirclePreviewDrawn = 1 Then
Colour RGB(Black)
Circle CX, CY, PrevR
CirclePreviewDrawn = 0
End If
End Sub

Sub CommitCircle
EraseCirclePreview
If CircleCount < MAX_CIRCLES Then
CircleX(CircleCount) = CX
CircleY(CircleCount) = CY
CircleR(CircleCount) = R
CircleType(CircleCount) = HiddenMode
ObjectType(ObjectCount) = TOOL_CIRCLE
CircleCount = CircleCount + 1
ObjectCount = ObjectCount + 1
End If
CircleStage = 0
RedrawAll
DrawCursor
End Sub

Sub CircleToolAction
If CircleStage = 0 Then
CX = X
CY = Y
R = 0
PrevR = 0
CirclePreviewDrawn = 0
CircleStage = 1
Else
CommitCircle
End If
End Sub

Sub CircleToolMove
If CircleStage = 1 Then
EraseCirclePreview
R = Int(Sqr((X - CX)^2 + (Y - CY)^2))
DrawCirclePreview
End If
End Sub

Sub CircleToolCancel
If CircleStage = 1 Then
EraseCirclePreview
CircleStage = 0
R = 0
CirclePreviewDrawn = 0
End If
End Sub

'----------------------------
’ Tool dispatcher
'----------------------------
Sub ToolMove
Select Case Tool
Case TOOL_LINE : LineToolMove
Case TOOL_CIRCLE : CircleToolMove
End Select
End Sub

Sub ToolAction
Select Case Tool
Case TOOL_LINE : LineToolAction
Case TOOL_CIRCLE : CircleToolAction
End Select
End Sub

Sub ToolCancel
Select Case Tool
Case TOOL_LINE : LineToolCancel
Case TOOL_CIRCLE : CircleToolCancel
End Select
End Sub

'----------------------------
’ Redraw all geometry
'----------------------------
Sub RedrawAll
CLS
’ Reset preview flags (safety)
PreviewDrawn = 0
CirclePreviewDrawn = 0
’ Baseline
Line 0,304,319,304,RGB(Blue)
’ Draw all lines
For I = 0 To LineCount - 1
If LineType(I) = 0 Then
Colour RGB(Green)
Else
Colour RGB(Blue)
End If
Line LineX1(I), LineY1(I), LineX2(I), LineY2(I)
Next I
’ Draw all circles
For I = 0 To CircleCount - 1
If CircleType(I) = 0 Then
Colour RGB(Green)
Else
Colour RGB(Blue)
End If
Circle CircleX(I), CircleY(I), CircleR(I)
Next I
End Sub

'----------------------------
’ Status bar
'----------------------------
Sub DrawStatusBar
Colour RGB(Cyan)
Text 0,308," "
Text 80,308," "
Text 160,308,β€œCount:”+Str$(ObjectCount)
Text 0,308,Right$(" β€œ+Str$(X),3)+”,β€œ+Right$(” β€œ+Str$(302-Y),3)
If HiddenMode = 0 Then
Colour RGB(Green)
Else
Colour RGB(Blue)
End If
If Tool = TOOL_CURSOR Then
Text 80,308,β€œCursor”
ElseIf Tool = TOOL_LINE Then
Text 80,308,β€œLine”
ElseIf Tool = TOOL_CIRCLE Then
Text 80,308,β€œRadius:”+Str$(R)+” Circle"
End If
Colour RGB(Cyan)
End Sub

'----------------------------
’ Undo
'----------------------------
Sub UndoLast
If ObjectCount = 0 Then Exit Sub

Select Case ObjectType(ObjectCount-1)
Case TOOL_LINE
If LineCount > 0 Then LineCount = LineCount - 1
Case TOOL_CIRCLE
If CircleCount > 0 Then CircleCount = CircleCount - 1
End Select
ObjectCount = ObjectCount - 1
RedrawAll
DrawCursor
End Sub

'----------------------------
’ Save / Open Drawing
'----------------------------
Sub SaveDrawing
Local filename$, i, itemNum
Local saveY1, saveY2, saveCY
Print
Input β€œSave Filename: β€œ, filename$
If filename$ = β€œβ€ Then Print β€œSave cancelled.”: Exit Sub
filename$ = β€œB:” + filename$ + β€œ.txt”
Open filename$ For Output As #1
Print #1, β€œCASCADE_CAD_V2”
’ ---- LINES ----
Print #1, β€œLINES,”; LineCount
itemNum = 1
For i = 0 To LineCount - 1
saveY1 = 302 - LineY1(i)
saveY2 = 302 - LineY2(i)
Print #1,itemNum;”,”;LineType(i);β€œ,”;LineX1(i);β€œ,”;saveY1;β€œ,”;LineX2(i);β€œ,”;LineX2(i);β€œ,”;saveY2
itemNum = itemNum + 1
Next i
’ ---- CIRCLES ----
Print #1, β€œCIRCLES,”; CircleCount
For i = 0 To CircleCount - 1
saveCY = 302 - CircleY(i)
Print #1,itemNum;β€œ,”;CircleType(i);β€œ,”;CircleX(i);β€œ,”;saveCY;β€œ,”;CircleR(i)
itemNum = itemNum + 1
Next i
Close #1
Print "Saved to "; filename$
RedrawAll
DrawCursor
DrawStatusBar
End Sub

Sub OpenDrawing
Local filename$, i, header$
Local lineCountFile, circleCountFile
Local itemNum, lType
Local temp$
Local loadY1, loadY2, loadCY
Print
Input "Open Filename: ", filename$
If filename$ = β€œβ€ Then Print β€œOpen cancelled.”: Exit Sub
filename$ = β€œB:” + filename$ + β€œ.txt”
Open filename$ For Input As #1
’ ---- Reset Everything ----
LineCount = 0
CircleCount = 0
ObjectCount = 0
LineStage = 0
CircleStage = 0
Line Input #1, header$
If header$ <> β€œCASCADE_CAD_V2” Then
Print β€œFile format error”
Close #1
Exit Sub
End If
’ ---- LINES ----
Input #1, temp$, lineCountFile
If lineCountFile > MAX_LINES Then lineCountFile = MAX_LINES
For i = 0 To lineCountFile - 1
Input #1,itemNum,lType,LineX1(i),loadY1,LineX2(i),loadY2
LineY1(i) = 302 - loadY1
LineY2(i) = 302 - loadY2
LineType(i) = lType
If ObjectCount < MAX_OBJECTS Then
ObjectType(ObjectCount) = TOOL_LINE
ObjectCount = ObjectCount + 1
End If
Next i
LineCount = lineCountFile
’ ---- CIRCLES ----
Input #1, temp$, circleCountFile
If circleCountFile > MAX_CIRCLES Then circleCountFile = MAX_CIRCLES
For i = 0 To circleCountFile - 1
Input #1, itemNum, lType,CircleX(i), loadCY, CircleR(i)
CircleY(i) = 302 - loadCY
CircleType(i) = lType
If ObjectCount < MAX_OBJECTS Then
ObjectType(ObjectCount) = TOOL_CIRCLE
ObjectCount = ObjectCount + 1
End If
Next i
CircleCount = circleCountFile
Close #1
RedrawAll
DrawCursor
DrawStatusBar
End Sub

'----------------------------
’ Main Loop
'----------------------------
DrawCursor
DrawStatusBar

Do
KS$ = Inkey$
If KS$ = β€œβ€ Then Continue Do

’ Handle special keys (arrows)
If Asc(KS$) = 0 Then
KS$ = Inkey$
End If
K = Asc(KS$)

’ ESC cancels current tool
If K = KEY_ESC Then
Select Case Tool
Case TOOL_LINE
If LineStage = 1 Then LineToolCancel Else Tool = TOOL_CURSOR
Case TOOL_CIRCLE
If CircleStage = 1 Then CircleToolCancel Else Tool = TOOL_CURSOR
End Select
DrawCursor
DrawStatusBar
Continue Do
End If

’ Cursor movement
If K = KEY_UP Or K = KEY_DOWN Or K = KEY_LEFT Or K = KEY_RIGHT Then
MoveCursor K
ToolMove
DrawStatusBar
Continue Do
End If

’ Toggle hidden/blue mode
If K = KEY_T Then HiddenMode = 1 - HiddenMode

’ Select tool
If K = Asc(β€œl”) Then Tool = TOOL_LINE
If K = KEY_C Or K = Asc(β€œc”) Then
Tool = TOOL_CIRCLE
CircleStage = 0
R = 0
End If

’ Activate tool (space bar)
If K = KEY_SP Then ToolAction

’ Undo
If K = Asc(β€œu”) Then UndoLast

’ Save / Open
If K = Asc(β€œs”) Then SaveDrawing
If K = Asc(β€œo”) Then OpenDrawing

’ Always refresh status bar
DrawStatusBar
Loop

7 Likes

This is really cool! When I swap back to my RP2040 I’ll be sure to try this out, should be easier with the mmbasic vscode plugin posted here: VSCode extension for MMBasic - #15 by DNSGeek

1 Like

Please note: This Line in Sub SaveDrawing should be:

Print #1,itemNum;”,”;LineType(i);β€œ,”;LineX1(i);β€œ,”;saveY1;β€œ,”;LineX2(i);β€œ,”;saveY2