Vector Graphics with LowResCoder – Lesson 3

Lesson 3: Different shapes

In this lesson we will change our code to show different shapes.

Changing the initialization

Our first problem is that different shapes will probably have different numbers of points and edges and we need be able to store the different objects in our arrays POINTS and EDGES.

So we setup two new constants for the maximum number of points and edges the different objects are allowed to have and create the arrays accordingly:


REM OBJECTS CAN HAVE NO MORE THAN 30 POINTS
MAXNUMBEROFPOINTS = 30
NUMBEROFDIMENSIONS = 2
DIM POINTS(MAXNUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)
IDXX = 0
IDXY = 1

REM OBJECTS CAN HAVE NO MORE THAN 30 EDGES
MAXNUMBEROFEDGES = 30
NUMBEROFPOINTSOFANEDGE = 2
DIM EDGES(MAXNUMBEROFEDGES - 1, NUMBEROFPOINTSOFANEDGE - 1)
IDXSTARTPOINT = 0
IDXENDPOINT = 1

(We will keep using the old variables NUMBEROFPOINTS and NUMBEROFEDGES later on as you’ll see.)

Then we change the data list for points and edges so that the first value holds the count of points or edges:

Additionally we change the label to the data of the rectangle a bit also:

DATAOFRECTANGLE:
REM 4 POINTS FOLLOW
DATA 4
DATA -20, -10
DATA  20, -10
DATA  20,  10
DATA -20,  10

REM 4 EDGES FOLLOW
DATA 4
DATA 0, 1
DATA 1, 2
DATA 2, 3
DATA 3, 0

And now we change the reading of the points and edges so that it reads also the numbers of the points and the edges.

We put that into a subroutine called INITPOINTSANDEDGES:

INITPOINTSANDEDGES:
  RESTORE DATAOFRECTANGLE 

  REM READ THE NUMBER OF POINTS FIRST
  READ NUMBEROFPOINTS

  REM THEN READ THE COORDINATES OF THE POINTS
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
    READ POINTS(POINTNO, IDXX)
    READ POINTS(POINTNO, IDXY)
  NEXT POINTNO
  
  REM READ NOW READ THE NUMBER OF EDGES
  READ NUMBEROFEDGES

  REM THEN READ THE START AND END POINT OF THE EDGES
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
    READ EDGES(EDGENO, IDXSTARTPOINT)
    READ EDGES(EDGENO, IDXENDPOINT)
  NEXT EDGENO
  
RETURN

More shapes

So now we will add some more data lines for other shapes.
Let’s think of a simple triangle:

           P0
         /   \
       /       \
     E2    C    E0
    /             \
  /                 \
P2---------E1--------P1

The data is as follows:

DATAOFTRIANGLE:
REM 3 POINTS FOLLOW
DATA 3
DATA   0, -10
DATA   10, 10
DATA  -10, 10

REM 3 EDGES FOLLOW
DATA 3
DATA 0, 1
DATA 1, 2
DATA 2, 0

Now let’s think of a more complex figure, a jet.
That’s the data of our jet:

DATAOFJET:
REM 15 POINTS FOLLOW
DATA 15
DATA  0, -8
DATA  1, -5
DATA  1, -2
DATA  6,  3
DATA  1,  3
DATA  1,  6
DATA  3,  8
DATA  0,  8
DATA  0,  5
DATA -3,  8
DATA -1,  6
DATA -1,  3
DATA -6,  3
DATA -1, -2
DATA -1, -5
REM 18 EDGES FOLLOW
DATA 18
DATA 0,1
DATA 1,2
DATA 2,3
DATA 3,4
DATA 4,5
DATA 5,6
DATA 6,7
DATA 7,8
DATA 7,9
DATA 9,10
DATA 10,11
DATA 11,12
DATA 12,13
DATA 13,14
DATA 14,0
DATA 1,4
DATA 11,13
DATA 2,4

For our three different object types we create three constants:

REM CONSTANTS FOR THE OBJECT TYPES
OBJTYPERECTANGLE = 0
OBJTYPETRIANGLE = 1
OBJTYPEJET = 2

Reading the shapes

We will now change our subroutine INITPOINTSANDEDGES a bit so that it reads the correct data for the chosen obj type OBJTYPE:

REM INIT POINTS AND EDGES
REM IN:
REM   OBJTYPE: THE OBJECT TYPE TO BE READ
REM
INITPOINTSANDEDGES:
  REM RESTORE TO THE RIGHT LABEL DEPENDING ON THE OBJECT TYPE
  IF OBJTYPE = OBJTYPERECTANGLE THEN
    RESTORE DATAOFRECTANGLE 
  ELSE IF OBJTYPE = OBJTYPETRIANGLE THEN
    RESTORE DATAOFTRIANGLE
  ELSE IF OBJTYPE = OBJTYPEJET THEN
    RESTORE DATAOFJET
  ELSE 
    PRINT "UNKNOWN OBJTYPE " + OBJTYPE
    END
  END IF

  REM READ THE NUMBER OF POINTS FIRST
  READ NUMBEROFPOINTS

  REM THEN READ THE COORDINATES OF THE POINTS
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
    READ POINTS(POINTNO, IDXX)
    READ POINTS(POINTNO, IDXY)
  NEXT POINTNO
  
  REM NOW READ THE NUMBER OF EDGES
  READ NUMBEROFEDGES

  REM THEN READ THE START AND END POINT OF THE EDGES
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
    READ EDGES(EDGENO, IDXSTARTPOINT)
    READ EDGES(EDGENO, IDXENDPOINT)
  NEXT EDGENO
  
RETURN

Switching between the shapes

Before we start the main loop we will initialize our object as a rectangle. In the main loop we want to toggle through the object types with “B”:

REM INIT THE OBJECT THE FIRST TIME
OBJTYPE = OBJTYPERECTANGLE
GOSUB INITPOINTSANDEDGES


REM MAIN LOOP
DO 
  REM CLEAR SCREEN AND DRAW THE RECTANGLE
  CLS
  GOSUB CALCSCREENPOINTS
  GOSUB DRAWEDGES
  WAIT 0.04
  
  REM WITHOUT ANY BUTTON PRESS WE MOVE THE RECTANGLE
  IF UP(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX + 1
  
  REM PRESSING BUTTON A AND UP OR DOWN CHANGES THE SCALE
  IF DOWN(0) AND BUTTON(0) AND OBJSCALE > 0.1 THEN OBJSCALE = OBJSCALE - 0.1
  IF UP(0) AND BUTTON(0) THEN OBJSCALE = OBJSCALE + 0.1
  
  REM PRESSING BUTTON A AND LEFT OR RIGHT ROTATES THE OBJECT
  IF LEFT(0) AND BUTTON(0, 1) THEN 
    REM TURN LEFT BY REDUCING OBJROTATION (AND THUS ROTATE COUNTERCLOCKWISE)
    OBJROTATION = OBJROTATION - 0.1
    REM IF WE PASS NORTH FROM THE RIGHT TO THE LEFT THEN WE NEED TO ADD 2 * PI
    IF OBJROTATION < 0 THEN
      OBJROTATION = OBJROTATION + 2 * PI
    END IF
  END IF
  IF RIGHT(0) AND BUTTON(0, 1) THEN 
    REM TURN RIGHT BY INCREASING OBJROTATION (AND THUS ROTATE CLOCKWISE)
    OBJROTATION = OBJROTATION + 0.1
    REM IF WE PASS NORTH FROM THE LEFT TO THE RIGHT THEN WE NEED TO SUBSTRACT 2 * PI
    IF OBJROTATION >= 2 * PI THEN
      OBJROTATION = OBJROTATION - 2 * PI
    END IF
  END IF

  REM IF BUTTON B IS PRESSED CHANGE OBJECT TO NEXT OBJECT TYPE
  IF BUTTON(0, 2) THEN
    OBJTYPE = OBJTYPE + 1
    REM IF WE'RE OUT OF OBJECT TYPES RESTART AT THE RECTANGLE
    IF OBJTYPE > OBJTYPEJET THEN
      OBJTYPE = OBJTYPERECTANGLE
    END IF
    GOSUB INITPOINTSANDEDGES
  END IF
  
LOOP

Ok, now let’s glue it all together and try it:
Open source code in LowResCoder app

REM VECTOR GRAPHICS - LESSON 3 - DIFFERENT SHAPES
REM BY TODDL



REM OBJECTS CAN HAVE NO MORE THAN 30 POINTS
MAXNUMBEROFPOINTS = 30
NUMBEROFDIMENSIONS = 2
DIM POINTS(MAXNUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)
IDXX = 0
IDXY = 1

REM OBJECTS CAN HAVE NO MORE THAN 30 EDGES
MAXNUMBEROFEDGES = 30
NUMBEROFPOINTSOFANEDGE = 2
DIM EDGES(MAXNUMBEROFEDGES - 1, NUMBEROFPOINTSOFANEDGE - 1)
IDXSTARTPOINT = 0
IDXENDPOINT = 1

REM ARRAY FOR SCREEN POINTS
DIM SCREENPOINTS(MAXNUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)

REM CONSTANTS FOR THE OBJECT TYPES
OBJTYPERECTANGLE = 0
OBJTYPETRIANGLE = 1
OBJTYPEJET = 2


SCREENCENTREX = 32
SCREENCENTREY = 32



REM THE POSITION OF OUR RECTANGLE
OBJPOSX = 0
OBJPOSY = 0

REM SCALE FACTOR FOR OUR RECTANGLE
OBJSCALE = 1.0

REM THE ROTATION ANGLE
OBJROTATION = 0.0



REM ENABLE GAMEPAD
GAMEPAD 1

REM INIT THE OBJECT THE FIRST TIME
OBJTYPE = OBJTYPERECTANGLE
GOSUB INITPOINTSANDEDGES

REM MAIN LOOP
DO 
  REM CLEAR SCREEN AND DRAW THE RECTANGLE
  CLS
  GOSUB CALCSCREENPOINTS
  GOSUB DRAWEDGES
  WAIT 0.04
  
  REM WITHOUT ANY BUTTON PRESS WE MOVE THE RECTANGLE
  IF UP(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX + 1
  
  REM PRESSING BUTTON A AND UP OR DOWN CHANGES THE SCALE
  IF DOWN(0) AND BUTTON(0) AND OBJSCALE > 0.1 THEN OBJSCALE = OBJSCALE - 0.1
  IF UP(0) AND BUTTON(0) THEN OBJSCALE = OBJSCALE + 0.1
  
  REM PRESSING BUTTON A AND LEFT OR RIGHT ROTATES THE OBJECT
  IF LEFT(0) AND BUTTON(0, 1) THEN 
    REM TURN LEFT BY REDUCING OBJROTATION (AND THUS ROTATE COUNTERCLOCKWISE)
    OBJROTATION = OBJROTATION - 0.1
    REM IF WE PASS NORTH FROM THE RIGHT TO THE LEFT THEN WE NEED TO ADD 2 * PI
    IF OBJROTATION < 0 THEN
      OBJROTATION = OBJROTATION + 2 * PI
    END IF
  END IF
  IF RIGHT(0) AND BUTTON(0, 1) THEN 
    REM TURN RIGHT BY INCREASING OBJROTATION (AND THUS ROTATE CLOCKWISE)
    OBJROTATION = OBJROTATION + 0.1
    REM IF WE PASS NORTH FROM THE LEFT TO THE RIGHT THEN WE NEED TO SUBSTRACT 2 * PI
    IF OBJROTATION >= 2 * PI THEN
      OBJROTATION = OBJROTATION - 2 * PI
    END IF
  END IF
  
  REM IF BUTTON B IS PRESSED CHANGE OBJECT TO NEXT OBJECT TYPE
  IF BUTTON(0, 2) THEN
    OBJTYPE = OBJTYPE + 1
    REM IF WE'RE OUT OF OBJECT TYPES RESTART AT THE RECTANGLE
    IF OBJTYPE > OBJTYPEJET THEN
      OBJTYPE = OBJTYPERECTANGLE
    END IF
    GOSUB INITPOINTSANDEDGES
  END IF
  
LOOP




REM INIT POINTS AND EDGES
REM IN:
REM   OBJTYPE: THE OBJECT TYPE TO BE READ
REM
INITPOINTSANDEDGES:
  REM RESTORE TO THE RIGHT LABEL DEPENDING ON THE OBJECT TYPE
  IF OBJTYPE = OBJTYPERECTANGLE THEN
    RESTORE DATAOFRECTANGLE 
  ELSE IF OBJTYPE = OBJTYPETRIANGLE THEN
    RESTORE DATAOFTRIANGLE
  ELSE IF OBJTYPE = OBJTYPEJET THEN
    RESTORE DATAOFJET
  ELSE 
    PRINT "UNKNOWN OBJTYPE " + OBJTYPE
    END
  END IF

  REM READ THE NUMBER OF POINTS FIRST
  READ NUMBEROFPOINTS

  REM THEN READ THE COORDINATES OF THE POINTS
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
    READ POINTS(POINTNO, IDXX)
    READ POINTS(POINTNO, IDXY)
  NEXT POINTNO
  
  REM NOW READ THE NUMBER OF EDGES
  READ NUMBEROFEDGES

  REM THEN READ THE START AND END POINT OF THE EDGES
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
    READ EDGES(EDGENO, IDXSTARTPOINT)
    READ EDGES(EDGENO, IDXENDPOINT)
  NEXT EDGENO
  
RETURN



CALCSCREENPOINTS:
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
    SCREENPOINTS(POINTNO, IDXX) = COS(OBJROTATION) * POINTS(POINTNO, IDXX) - SIN(OBJROTATION) * POINTS(POINTNO, IDXY)
    SCREENPOINTS(POINTNO, IDXY) = SIN(OBJROTATION) * POINTS(POINTNO, IDXX) + COS(OBJROTATION) * POINTS(POINTNO, IDXY)
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) * OBJSCALE
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) * OBJSCALE
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + OBJPOSX
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + OBJPOSY
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + SCREENCENTREX 
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + SCREENCENTREY 
    SCREENPOINTS(POINTNO, IDXX) = INT(SCREENPOINTS(POINTNO, IDXX) + 0.5)
    SCREENPOINTS(POINTNO, IDXY) = INT(SCREENPOINTS(POINTNO, IDXY) + 0.5)
  NEXT POINTNO
RETURN



DRAWEDGES:
  REM ITERATE OVER ALL EDGES
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
    STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
    ENDPOINT = EDGES(EDGENO, IDXENDPOINT)

    REM DRAW FROM STARTPOINT TO ENDPOINT 
    LINE SCREENPOINTS(STARTPOINT, IDXX), SCREENPOINTS(STARTPOINT, IDXY) TO SCREENPOINTS(ENDPOINT, IDXX), SCREENPOINTS(ENDPOINT, IDXY)
    
  NEXT EDGENO
RETURN




DATAOFRECTANGLE:
REM 4 POINTS FOLLOW
DATA 4
DATA -20, -10
DATA  20, -10
DATA  20,  10
DATA -20,  10

REM 4 EDGES FOLLOW
DATA 4
DATA 0, 1
DATA 1, 2
DATA 2, 3
DATA 3, 0

DATAOFTRIANGLE:
REM 3 POINTS FOLLOW
DATA 3
DATA   0, -10
DATA   10, 10
DATA  -10, 10
REM 3 EDGES FOLLOW
DATA 3
DATA 0, 1
DATA 1, 2
DATA 2, 0

DATAOFJET:
REM 15 POINTS FOLLOW
DATA 15
DATA  0, -8
DATA  1, -5
DATA  1, -2
DATA  6,  3
DATA  1,  3
DATA  1,  6
DATA  3,  8
DATA  0,  8
DATA  0,  5
DATA -3,  8
DATA -1,  6
DATA -1,  3
DATA -6,  3
DATA -1, -2
DATA -1, -5
REM 18 EDGES FOLLOW
DATA 18
DATA 0,1
DATA 1,2
DATA 2,3
DATA 3,4
DATA 4,5
DATA 5,6
DATA 6,7
DATA 7,8
DATA 7,9
DATA 9,10
DATA 10,11
DATA 11,12
DATA 12,13
DATA 13,14
DATA 14,0
DATA 1,4
DATA 11,13
DATA 2,4

To be continued if I have time again and get some feedback 🙂

Advertisement
Privacy Settings
Vector Graphics with LowResCoder – Lesson 3

Vector Graphics with LowResCoder – Lesson 2

Lesson 2: Let’s move, scale and rotate the rectangle

In this lesson we will move the rectangle, scale and rotate it.

Moving the rectangle

Moving of our rectangle is quite easy. We will have two variables for the position of our rectangle in our 2D coordinates system:

REM THE POSITION OF OUR OBJECT, THE RECTANGLE
OBJPOSX = 0
OBJPOSY = 0

We’ll change our drawing code to a subroutine by adding a RETURN statement at the end and we’ll add our rectangle position coordinates to each of the point coordinates:

DRAWEDGES:
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
    STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
    ENDPOINT = EDGES(EDGENO, IDXENDPOINT)
 
    REM MADE THE CODE A BIT MORE COMPACT HERE...
    STARTPOINTX = POINTS(STARTPOINT, IDXX) + SCREENCENTREX + OBJPOSX
    STARTPOINTY = POINTS(STARTPOINT, IDXY) + SCREENCENTREY + OBJPOSY
    ENDPOINTX = POINTS(ENDPOINT, IDXX) + SCREENCENTREX + OBJPOSX
    ENDPOINTY = POINTS(ENDPOINT, IDXY) + SCREENCENTREY + OBJPOSY
    
    LINE STARTPOINTX, STARTPOINTY TO ENDPOINTX, ENDPOINTY
    
  NEXT EDGENO
RETURN

And then we add some code to draw the rectangle continously while checking for the user to move it with the cursor pad.

REM ENABLE GAMEPAD
GAMEPAD 1

REM MAIN LOOP
DO 
  REM CLEAR SCREEN AND DRAW THE RECTANGLE
  CLS
  GOSUB DRAWEDGES
  WAIT 0.04
  
  REM HANDLE CURSOR PAD INPUT TO CHANGE 
  REM THE POSITION OF OUR RECTANGLE
  IF UP(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) THEN OBJPOSX = OBJPOSX + 1
LOOP

So let’s glue it all together and try it.

You should be able to move the rectangle with the game pad.

Open source code in LowResCoder app

REM VECTOR GRAPHICS - LESSON 2 A - MOVING
REM BY TODDL



REM SET UP POINTS OF THE RECTANGLE

NUMBEROFPOINTS = 4
NUMBEROFDIMENSIONS = 2
DIM POINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)
IDXX = 0
IDXY = 1

INITPOINTS:

RESTORE POINTSDATA
FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
  READ POINTS(POINTNO, IDXX)
  READ POINTS(POINTNO, IDXY)
NEXT POINTNO



REM SET UP EDGES OF THE RECTANGLE

NUMBEROFEDGES = 4
NUMBEROFPOINTSOFANEDGE = 2
DIM EDGES(NUMBEROFEDGES - 1, NUMBEROFPOINTSOFANEDGE - 1)
IDXSTARTPOINT = 0
IDXENDPOINT = 1

INITEDGES:

RESTORE EDGESDATA
FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  READ EDGES(EDGENO, IDXSTARTPOINT)
  READ EDGES(EDGENO, IDXENDPOINT)
NEXT EDGENO



SCREENCENTREX = 32
SCREENCENTREY = 32

REM THE POSITION OF OUR RECTANGLE
OBJPOSX = 0
OBJPOSY = 0



REM ENABLE GAMEPAD
GAMEPAD 1

REM MAIN LOOP
DO 
  REM CLEAR SCREEN AND DRAW THE RECTANGLE
  CLS
  GOSUB DRAWEDGES
  WAIT 0.04
  
  REM HANDLE CURSOR PAD INPUT TO CHANGE 
  REM THE POSITION OF OUR RECTANGLE
  IF UP(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) THEN OBJPOSX = OBJPOSX + 1
LOOP


DRAWEDGES:
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
    STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
    ENDPOINT = EDGES(EDGENO, IDXENDPOINT)
 
    REM MADE THE CODE A BIT MORE COMPACT HERE...
    STARTPOINTX = POINTS(STARTPOINT, IDXX) + SCREENCENTREX + OBJPOSX
    STARTPOINTY = POINTS(STARTPOINT, IDXY) + SCREENCENTREY + OBJPOSY
    ENDPOINTX = POINTS(ENDPOINT, IDXX) + SCREENCENTREX + OBJPOSX
    ENDPOINTY = POINTS(ENDPOINT, IDXY) + SCREENCENTREY + OBJPOSY
    
    LINE STARTPOINTX, STARTPOINTY TO ENDPOINTX, ENDPOINTY
    
  NEXT EDGENO
RETURN



POINTSDATA:
DATA -20, -10
DATA  20, -10
DATA  20,  10
DATA -20,  10

EDGESDATA:
DATA 0, 1
DATA 1, 2
DATA 2, 3
DATA 3, 0

Improving our code

Before we continue we refactor our drawing code a bit to make things more transparent, faster and more elegant.

We split up our DRAWEDGES subroutine into two subroutines called CALCSCREENPOINTS and DRAWEDGES.

First CALCSCREENPOINT will calculate the screen points from the 2D world points. CALCSCREENPOINT will do the following steps:

  1. Copy all object points from array POINTS to array SCREENPOINTS
    (We will never change the original POINTS array. We always work on a copy called SCREENPOINTS.)

  2. Add the object position OBJPOSX, OBJPOSY to all SCREENPOINTS
  3. Take into account that 2D world origin 0, 0 is at screen position SCREENCENTREX, SCREENCENTREY
  4. Round the screenpoints to the nearest integer

After that DRAWEDGES will then only draw the edges between the screen points.

So we define an array for screen points called SCREENPOINTS and iterate over all world points and calculate their corresponding screen points:

REM ARRAY FOR SCREEN POINTS
DIM SCREENPOINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)

CALCSCREENPOINTS:
  REM ITERATE OVER ALL POINTS OF THE RECTANGLE
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1

    REM 1. COPY ALL POINTS TO THE SCREENPOINTS ARRAY
    SCREENPOINTS(POINTNO, IDXX) = POINTS(POINTNO, IDXX)
    SCREENPOINTS(POINTNO, IDXY) = POINTS(POINTNO, IDXY)

    REM 2. ADD OBJECT POSITION OBJPOSX, OBJPOSY TO ALL SCREENPOINTS
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + OBJPOSX
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + OBJPOSY
    
    REM 3. ADD SCREENCENTREX, SCREENCENTRE Y TO ALL SCREENPOINTS
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + SCREENCENTREX 
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + SCREENCENTREY 
    
    REM 4. ROUND THE SCREENPOINTS TO THE NEAREST INTEGER
    SCREENPOINTS(POINTNO, IDXX) = INT(SCREENPOINTS(POINTNO, IDXX) + 0.5)
    SCREENPOINTS(POINTNO, IDXY) = INT(SCREENPOINTS(POINTNO, IDXY) + 0.5)
    
  NEXT POINTNO
RETURN


DRAWEDGES:
  REM ITERATE OVER ALL EDGES
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
    STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
    ENDPOINT = EDGES(EDGENO, IDXENDPOINT)

    REM DRAW FROM STARTPOINT TO ENDPOINT 
    LINE SCREENPOINTS(STARTPOINT, IDXX), SCREENPOINTS(STARTPOINT, IDXY) TO SCREENPOINTS(ENDPOINT, IDXX), SCREENPOINTS(ENDPOINT, IDXY)
    
  NEXT EDGENO
RETURN

So now we have to change our main loop accordingly to call both subroutines:

REM ENABLE GAMEPAD
GAMEPAD 1

REM MAIN LOOP
DO 
  CLS
  GOSUB CALCSCREENPOINTS
  GOSUB DRAWEDGES
  WAIT 0.04
  
  REM HANDLE CURSOR PAD INPUT TO CHANGE 
  REM THE POSITION OF OUR RECTANGLE
  IF UP(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) THEN OBJPOSX = OBJPOSX + 1
LOOP

Scaling the rectangle

Now we will add code to scale the rectangle.

For this we introduce a scale factor for our rectangle:

REM SCALE FACTOR FOR OUR RECTANGLE
OBJSCALE = 1.0

The initial scale factor of the rectangle will be 1, that means it will be 40 pixels wide and 20 pixels high.
With a scale factor of 0.5, it will only be half the size, thus 20 pixels wide and 10 pixels high.

We need to take the scale factor into account when calculating the screen coordinates from the 2D world coordinates.

So we change our CALCSCREENPOINTS subroutine a bit and multiply our world coordinates with the scale factor before we do the other calculations:

  1. Copy all object points from array POINTS to array SCREENPOINTS
  2. Multiply all point positions with the scale factor OBJSCALE
  3. Add the object position OBJPOSX, OBJPOSY to all SCREENPOINTS
  4. Take into account that 2D world origin 0, 0 is at screen position SCREENCENTREX, SCREENCENTREY
  5. Round the screenpoints to the nearest integer
CALCSCREENPOINTS:
  REM ITERATE OVER ALL POINTS OF THE RECTANGLE
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
  
    REM 1. COPY ALL POINTS TO THE SCREENPOINTS ARRAY
    SCREENPOINTS(POINTNO, IDXX) = POINTS(POINTNO, IDXX)
    SCREENPOINTS(POINTNO, IDXY) = POINTS(POINTNO, IDXY)

    REM 2. SCALE ALL SCREENPOINTS 
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) * OBJSCALE
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) * OBJSCALE

    REM 3. ADD OBJECT POSITION OBJPOSX, OBJPOSY TO ALL SCREENPOINTS
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + OBJPOSX
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + OBJPOSY
    
    REM 4. ADD SCREENCENTREX, SCREENCENTRE Y TO ALL SCREENPOINTS
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + SCREENCENTREX 
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + SCREENCENTREY 
    
    REM 5. ROUND THE SCREENPOINTS TO THE NEAREST INTEGER
    SCREENPOINTS(POINTNO, IDXX) = INT(SCREENPOINTS(POINTNO, IDXX) + 0.5)
    SCREENPOINTS(POINTNO, IDXY) = INT(SCREENPOINTS(POINTNO, IDXY) + 0.5)

  NEXT POINTNO
RETURN

We want to be able the scale with button A and UP or DOWN, so we change the input handling in the main loop:

REM ENABLE GAMEPAD
GAMEPAD 1

REM MAIN LOOP
DO 
  CLS
  GOSUB CALCSCREENPOINTS
  GOSUB DRAWEDGES
  WAIT 0.04

  REM WITHOUT ANY BUTTON PRESS WE MOVE THE RECTANGLE
  IF UP(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX + 1
  
  REM PRESSING BUTTON A AND UP OR DOWN CHANGES THE SCALE
  IF DOWN(0) AND BUTTON(0, 1) AND OBJSCALE > 0.1 THEN OBJSCALE = OBJSCALE - 0.1
  IF UP(0) AND BUTTON(0, 1) THEN OBJSCALE = OBJSCALE + 0.1
LOOP

Again, let’s glue it all together and try it:

Open source code in LowResCoder app

REM VECTOR GRAPHICS - LESSON 2 B - SCALING
REM BY TODDL



REM SET UP POINTS OF THE RECTANGLE

NUMBEROFPOINTS = 4
NUMBEROFDIMENSIONS = 2
DIM POINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)
IDXX = 0
IDXY = 1

INITPOINTS:

RESTORE POINTSDATA
FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
  READ POINTS(POINTNO, IDXX)
  READ POINTS(POINTNO, IDXY)
NEXT POINTNO



REM SET UP EDGES OF THE RECTANGLE

NUMBEROFEDGES = 4
NUMBEROFPOINTSOFANEDGE = 2
DIM EDGES(NUMBEROFEDGES - 1, NUMBEROFPOINTSOFANEDGE - 1)
IDXSTARTPOINT = 0
IDXENDPOINT = 1

INITEDGES:

RESTORE EDGESDATA
FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  READ EDGES(EDGENO, IDXSTARTPOINT)
  READ EDGES(EDGENO, IDXENDPOINT)
NEXT EDGENO




REM ARRAY FOR SCREEN POINTS
DIM SCREENPOINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)




SCREENCENTREX = 32
SCREENCENTREY = 32



REM THE POSITION OF OUR RECTANGLE
OBJPOSX = 0
OBJPOSY = 0

REM SCALE FACTOR FOR OUR RECTANGLE
OBJSCALE = 1.0







REM ENABLE GAMEPAD
GAMEPAD 1

REM MAIN LOOP
DO 
  REM CLEAR SCREEN AND DRAW THE RECTANGLE
  CLS
  GOSUB CALCSCREENPOINTS
  GOSUB DRAWEDGES
  WAIT 0.04
  
  REM WITHOUT ANY BUTTON PRESS WE MOVE THE RECTANGLE
  IF UP(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX + 1
  
  REM PRESSING BUTTON A AND UP OR DOWN CHANGES THE SCALE
  IF DOWN(0) AND BUTTON(0, 1) AND OBJSCALE > 0.1 THEN OBJSCALE = OBJSCALE - 0.1
  IF UP(0) AND BUTTON(0, 1) THEN OBJSCALE = OBJSCALE + 0.1
LOOP



CALCSCREENPOINTS:
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
    SCREENPOINTS(POINTNO, IDXX) = POINTS(POINTNO, IDXX)
    SCREENPOINTS(POINTNO, IDXY) = POINTS(POINTNO, IDXY)
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) * OBJSCALE
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) * OBJSCALE
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + OBJPOSX
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + OBJPOSY
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + SCREENCENTREX 
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + SCREENCENTREY 
    SCREENPOINTS(POINTNO, IDXX) = INT(SCREENPOINTS(POINTNO, IDXX) + 0.5)
    SCREENPOINTS(POINTNO, IDXY) = INT(SCREENPOINTS(POINTNO, IDXY) + 0.5)
  NEXT POINTNO
RETURN

DRAWEDGES:
  REM ITERATE OVER ALL EDGES
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
    STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
    ENDPOINT = EDGES(EDGENO, IDXENDPOINT)

    REM DRAW FROM STARTPOINT TO ENDPOINT 
    LINE SCREENPOINTS(STARTPOINT, IDXX), SCREENPOINTS(STARTPOINT, IDXY) TO SCREENPOINTS(ENDPOINT, IDXX), SCREENPOINTS(ENDPOINT, IDXY)
    
  NEXT EDGENO
RETURN




POINTSDATA:
DATA -20, -10
DATA  20, -10
DATA  20,  10
DATA -20,  10

EDGESDATA:
DATA 0, 1
DATA 1, 2
DATA 2, 3
DATA 3, 0

Rotating the rectangle

To rotate our rectangle around its centre we need some trigonometrical “magic”.

The general formula for rotating a point (x, y) around the centre (0, 0) with a rotation angle a is:

rotated x = cos(a) * x – sin(a) * y

rotated y = sin(a) * x + cos(a) * y

Excursion: Degrees, radians, circles and directions

Note that the trigonometric functions in LowResCoder – as in most programming languages – define angles in radians and not in degrees.

A circle is 360 degrees. 360 degrees is equal to 2 * Π radians. (Π = PI which is roughly 3.1415)

The general conversion formula to convert from degrees to radians obviously is:

radians = degreens / 180 * Π

To convert from radians to degrees the formula then is:

degrees = radians / Π * 180

Here’s a small table to help you to convert from degrees to radians:

Direction Degrees Radians
North 0 0
Northeast 45 1/4 * Π
East 90 1/2 * Π
Southeast 135 3/4 * Π
South 180 Π
Southwest 225 5/4 * Π
West 270 3/2 * Π
Northwest 315 7/4 * Π

Let’s put the rotation into BASIC code

First we need a variable that holds the rotation angle a in radians.

REM THE ROTATION ANGLE
OBJROTATION = 0.0

Now we need to change our CALCSCREENPOINTS subroutine to take the rotation into account.
We do this by changing our copying step from array POINTS to array SCREENPOINTS so that it not only copies the points but also rotates them while copying.

CALCSCREENPOINTS will do now the following steps:

  1. Rotate object points from array POINTS with rotation angle OBJROTATION and store the result in array SCREENPOINTS

    Do this by applying our trignometrical formula:

    rotated x = cos(a) * x – sin(a) * y

    rotated y = sin(a) * x + cos(a) * y

  2. Multiply all point positions with the scale factor OBJSCALE
  3. Add the object position OBJPOSX, OBJPOSY to all SCREENPOINTS
  4. Take into account that 2D world origin 0, 0 is at screen position SCREENCENTREX, SCREENCENTREY
  5. Round the screenpoints to the nearest integer

Those are our changes:

CALCSCREENPOINTS:
  REM ITERATE OVER ALL POINTS OF THE RECTANGLE
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1

    REM 1. ROTATE ALL POINTS AND STORE THEM IN SCREENPOINTS
    SCREENPOINTS(POINTNO, IDXX) = COS(OBJROTATION) * POINTS(POINTNO, IDXX) - SIN(OBJROTATION) * POINTS(POINTNO, IDXY)
    SCREENPOINTS(POINTNO, IDXY) = SIN(OBJROTATION) * POINTS(POINTNO, IDXX) + COS(OBJROTATION) * POINTS(POINTNO, IDXY)

    REM 2. SCALE ALL SCREENPOINTS 
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) * OBJSCALE
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) * OBJSCALE

    REM 3. ADD OBJECT POSITION OBJPOSX, OBJPOSY TO ALL SCREENPOINTS
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + OBJPOSX
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + OBJPOSY
    
    REM 4. ADD SCREENCENTREX, SCREENCENTRE Y TO ALL SCREENPOINTS
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + SCREENCENTREX 
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + SCREENCENTREY 

    REM 5. ROUND THE SCREENPOINTS TO THE NEAREST INTEGER
    SCREENPOINTS(POINTNO, IDXX) = INT(SCREENPOINTS(POINTNO, IDXX) + 0.5)
    SCREENPOINTS(POINTNO, IDXY) = INT(SCREENPOINTS(POINTNO, IDXY) + 0.5)

  NEXT POINTNO
RETURN

Now we change our main loop again so that we are able to change the rotation by pressing button A and left or right.

REM MAIN LOOP
DO 
  REM CLEAR SCREEN AND DRAW THE RECTANGLE
  CLS
  GOSUB CALCSCREENPOINTS
  GOSUB DRAWEDGES
  WAIT 0.04
  
  REM WITHOUT ANY BUTTON PRESS WE MOVE THE RECTANGLE
  IF UP(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX + 1
  
  REM PRESSING BUTTON A AND UP OR DOWN CHANGES THE SCALE
  IF DOWN(0) AND BUTTON(0, 1) AND OBJSCALE > 0.1 THEN OBJSCALE = OBJSCALE - 0.1
  IF UP(0) AND BUTTON(0, 1) THEN OBJSCALE = OBJSCALE + 0.1

  REM PRESSING BUTTON A AND LEFT OR RIGHT ROTATES THE OBJECT
  IF LEFT(0) AND BUTTON(0, 1) THEN 
    REM TURN LEFT BY REDUCING OBJROTATION (AND THUS ROTATE COUNTERCLOCKWISE)
    OBJROTATION = OBJROTATION - 0.1
    REM IF WE PASS NORTH FROM THE RIGHT TO THE LEFT THEN WE NEED TO ADD 2 * PI
    IF OBJROTATION < 0 THEN
      OBJROTATION = OBJROTATION + 2 * PI
    END IF
  END IF
  IF RIGHT(0) AND BUTTON(0, 1) THEN 
    REM TURN RIGHT BY INCREASING OBJROTATION (AND THUS ROTATE CLOCKWISE)
    OBJROTATION = OBJROTATION + 0.1
    REM IF WE PASS NORTH FROM THE LEFT TO THE RIGHT THEN WE NEED TO SUBSTRACT 2 * PI
    IF OBJROTATION >= 2 * PI THEN
      OBJROTATION = OBJROTATION - 2 * PI
    END IF
  END IF

LOOP

Let’s glue all together and try it:

Open source code in LowResCoder app

REM VECTOR GRAPHICS - LESSON 2 C - ROTATING
REM BY TODDL



REM SET UP POINTS OF THE RECTANGLE

NUMBEROFPOINTS = 4
NUMBEROFDIMENSIONS = 2
DIM POINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)
IDXX = 0
IDXY = 1

INITPOINTS:

RESTORE POINTSDATA
FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
  READ POINTS(POINTNO, IDXX)
  READ POINTS(POINTNO, IDXY)
NEXT POINTNO



REM SET UP EDGES OF THE RECTANGLE

NUMBEROFEDGES = 4
NUMBEROFPOINTSOFANEDGE = 2
DIM EDGES(NUMBEROFEDGES - 1, NUMBEROFPOINTSOFANEDGE - 1)
IDXSTARTPOINT = 0
IDXENDPOINT = 1

INITEDGES:

RESTORE EDGESDATA
FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  READ EDGES(EDGENO, IDXSTARTPOINT)
  READ EDGES(EDGENO, IDXENDPOINT)
NEXT EDGENO




REM ARRAY FOR SCREEN POINTS
DIM SCREENPOINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)




SCREENCENTREX = 32
SCREENCENTREY = 32



REM THE POSITION OF OUR RECTANGLE
OBJPOSX = 0
OBJPOSY = 0

REM SCALE FACTOR FOR OUR RECTANGLE
OBJSCALE = 1.0

REM THE ROTATION ANGLE
OBJROTATION = 0.0



REM ENABLE GAMEPAD
GAMEPAD 1

REM MAIN LOOP
DO 
  REM CLEAR SCREEN AND DRAW THE RECTANGLE
  CLS
  GOSUB CALCSCREENPOINTS
  GOSUB DRAWEDGES
  WAIT 0.04
  
  REM WITHOUT ANY BUTTON PRESS WE MOVE THE RECTANGLE
  IF UP(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY - 1
  IF DOWN(0) AND NOT BUTTON(0) THEN OBJPOSY = OBJPOSY + 1
  IF LEFT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX - 1
  IF RIGHT(0) AND NOT BUTTON(0) THEN OBJPOSX = OBJPOSX + 1
  
  REM PRESSING BUTTON A AND UP OR DOWN CHANGES THE SCALE
  IF DOWN(0) AND BUTTON(0) AND OBJSCALE > 0.1 THEN OBJSCALE = OBJSCALE - 0.1
  IF UP(0) AND BUTTON(0) THEN OBJSCALE = OBJSCALE + 0.1
  
  REM PRESSING BUTTON A AND LEFT OR RIGHT ROTATES THE OBJECT
  IF LEFT(0) AND BUTTON(0, 1) THEN 
    REM TURN LEFT BY REDUCING OBJROTATION (AND THUS ROTATE COUNTERCLOCKWISE)
    OBJROTATION = OBJROTATION - 0.1
    REM IF WE PASS NORTH FROM THE RIGHT TO THE LEFT THEN WE NEED TO ADD 2 * PI
    IF OBJROTATION < 0 THEN
      OBJROTATION = OBJROTATION + 2 * PI
    END IF
  END IF
  IF RIGHT(0) AND BUTTON(0, 1) THEN 
    REM TURN RIGHT BY INCREASING OBJROTATION (AND THUS ROTATE CLOCKWISE)
    OBJROTATION = OBJROTATION + 0.1
    REM IF WE PASS NORTH FROM THE LEFT TO THE RIGHT THEN WE NEED TO SUBSTRACT 2 * PI
    IF OBJROTATION >= 2 * PI THEN
      OBJROTATION = OBJROTATION - 2 * PI
    END IF
  END IF
  
LOOP



CALCSCREENPOINTS:
  FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
    SCREENPOINTS(POINTNO, IDXX) = COS(OBJROTATION) * POINTS(POINTNO, IDXX) - SIN(OBJROTATION) * POINTS(POINTNO, IDXY)
    SCREENPOINTS(POINTNO, IDXY) = SIN(OBJROTATION) * POINTS(POINTNO, IDXX) + COS(OBJROTATION) * POINTS(POINTNO, IDXY)
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) * OBJSCALE
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) * OBJSCALE
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + OBJPOSX
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + OBJPOSY
    SCREENPOINTS(POINTNO, IDXX) = SCREENPOINTS(POINTNO, IDXX) + SCREENCENTREX 
    SCREENPOINTS(POINTNO, IDXY) = SCREENPOINTS(POINTNO, IDXY) + SCREENCENTREY 
    SCREENPOINTS(POINTNO, IDXX) = INT(SCREENPOINTS(POINTNO, IDXX) + 0.5)
    SCREENPOINTS(POINTNO, IDXY) = INT(SCREENPOINTS(POINTNO, IDXY) + 0.5)
  NEXT POINTNO
RETURN

DRAWEDGES:
  REM ITERATE OVER ALL EDGES
  FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
    STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
    ENDPOINT = EDGES(EDGENO, IDXENDPOINT)

    REM DRAW FROM STARTPOINT TO ENDPOINT 
    LINE SCREENPOINTS(STARTPOINT, IDXX), SCREENPOINTS(STARTPOINT, IDXY) TO SCREENPOINTS(ENDPOINT, IDXX), SCREENPOINTS(ENDPOINT, IDXY)
    
  NEXT EDGENO
RETURN




POINTSDATA:
DATA -20, -10
DATA  20, -10
DATA  20,  10
DATA -20,  10

EDGESDATA:
DATA 0, 1
DATA 1, 2
DATA 2, 3
DATA 3, 0

Continued in lesson 3

Vector Graphics with LowResCoder – Lesson 2

Vector Graphics with LowResCoder – Lesson 1

Vector Graphics with LowResCoder

In this tutorial I’ll show how to do vector graphics with LowResCoder.

Have fun!

Lesson 1: Let’s draw one rectangle

In the first lesson we start by drawing one rectangle.

What’s a rectangle?

A rectangle consists of four points which are connected by four edges.

Storing the points information

See this picture of our rectangle which has 4 points: P0, P1, P2 and P3.

 P0-------------------------------------P1 
 |                                       |
 |                                       |
 |                                       | 
 |                                       |
 |                                       |
 |                                       | 
 |                                       |
 |                                       | 
 |                                       | 
 |                                       |
 |                                       |
 P3-------------------------------------P2 

Let’s put this rectangle into a 2D coordinate system which where the origin of the coordinate system is identical to the centre of the rectanglee – we call this point C where x = 0 and y = 0.

 ----------------- x axis --------------->
                   
-20  -15  -10  -5    0    5   10   15   20 
 |    |    |    |    |    |    |    |    | 
 
 P0-------------------------------------P1 - -20   |
 |                                       |         |
 |                                       |         |
 |                                       | - -10   |
 |                                       |         |
 |                                       |         |
 |                   C                   | -  0  y axis
 |                                       |         |
 |                                       |         |
 |                                       | -  10   |
 |                                       |         |
 |                                       |         |
 P3-------------------------------------P2 -  20   v

So our points have the following coordinates:

POINTS TABLE:

POINT   X,  Y
P0    -20, -10
P1     20, -10
P2     20,  10
P3    -20,  10

We instantly see that we could put the above table into an array where every row holds a point and the two columns hold the X and the Y value.

We’ll call this array POINTS. The table is obviously 4 rows x 2 columns, so needed POINTS array holding this table looks like this:

The array will look like this:

Array POINTS column 0 column 1
row 0 X position of point 0 Y position of point 0
row 1 X position of point 1 Y position of point 1
row 2 X position of point 2 Y position of point 2
row 3 X position of point 3 Y position of point 3

To make this a bit more convenient we setup two constants which holds the number of rows and number of columns:

REM HOW MANY POINTS DO WE HAVE - THAT'S THE NUMBER OF ROWS
NUMBEROFPOINTS = 4

REM OUR WORLD IS A 2D COORDINATE SYSTEM (X AND Y) - THAT'S THE NUMBER OF COLUMNS
NUMBEROFDIMENSIONS = 2

Now we need to create our array POINTS. An array of course is created with the DIM command.

Remember that the first argument passed to the DIM command notes the highest row number, not the number of rows! Remember also that the numbering of our rows starts with zero. So if we have 4 rows, the rows have the number 0, 1, 2 and 3 and thus the highest row number is 3.

The same applies for the columns. We have 2 columns (for X and Y), so the numbers of the columns are 0 and 1 and thus the highest rownumber is 1.

That’s why we write:

DIM POINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)

Let’s define some constants to access the different columns more easily:

REM THE X POSITION IS STORED IN COLUMN 0
IDXX = 0

REM THE Y POSITION IS STORED IN COLUMN 1
IDXY = 1

Now we can store our table in this array:

INITPOINTS:

REM SET THE X AND Y VALUE FOR POINT P0
POINTS(0, IDXX) = -20
POINTS(0, IDXY) = -10

REM SET THE X AND Y VALUE FOR POINT P1
POINTS(1, IDXX) = 20
POINTS(1, IDXY) = -10

REM SET THE X AND Y VALUE FOR POINT P2
POINTS(2, IDXX) = 20
POINTS(2, IDXY) = 10

REM SET THE X AND Y VALUE FOR POINT P3
POINTS(3, IDXX) = -20
POINTS(3, IDXY) = 10

Once we put everything together the code for initialzing our points table looks like this:

REM SET UP THE POINTS ARRAY

REM HOW MANY POINTS DO WE HAVE - THAT'S THE NUMBER OF ROWS
NUMBEROFPOINTS = 4

REM OUR WORLD IS A 2D COORDINATE SYSTEM (X AND Y) - THAT'S THE NUMBER OF COLUMNS
NUMBEROFDIMENSIONS = 2

DIM POINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)

REM THE X POSITION IS STORED IN COLUMN 0
IDXX = 0

REM THE Y POSITION IS STORED IN COLUMN 1
IDXY = 1

INITPOINTS:

REM SET THE X AND Y VALUE FOR POINT P0
POINTS(0, IDXX) = -20
POINTS(0, IDXY) = -10

REM SET THE X AND Y VALUE FOR POINT P1
POINTS(1, IDXX) = 20
POINTS(1, IDXY) = -10

REM SET THE X AND Y VALUE FOR POINT P2
POINTS(2, IDXX) = 20
POINTS(2, IDXY) = 10

REM SET THE X AND Y VALUE FOR POINT P3
POINTS(3, IDXX) = -20
POINTS(3, IDXY) = 10

Storing the edges information

Since we now have defined the four points of the rectangle, let’s concentrate on the edges:

The four points are connected by four edges we name E0, E1, E2 and E3:

 P0------------------E0-----------------P1 
 |                                       |
 |                                       |
 |                                       | 
 |                                       |
 |                                       |
 E3                                      E1
 |                                       |
 |                                       | 
 |                                       | 
 |                                       |
 |                                       |
 P3------------------E2-----------------P2 

We can set up a table which shows which edge connects which two points:

EDGES TABLE:

EDGE   START POINT, END POINT
E0              P0,        P1
E1              P1,        P2
E2              P2,        P3
E3              P3,        P0

We can put this into an array called EDGES where every row hold an edge and the first column holds the start point and the second column holds the end point:

REM SET UP THE EDGES ARRAY

REM HOW MANY EDGES DO WE HAVE?
NUMBEROFEDGES = 4

REM AN EDGE HAS TWO POINTS
NUMBEROFPOINTSOFANEDGE = 2

REM LET'S CREATE THE EDGES ARRAY
DIM EDGES(NUMBEROFEDGES - 1, NUMBEROFPOINTSOFANEDGE - 1)

REM INDEX OF THE COLUMN THAT HOLDS THE START POINT OF THE EDGE
IDXSTARTPOINT = 0

REM INDEX OF THE COLUMN THAT HOLDS THE END POINT OF THE EDGE
IDXENDPOINT = 1



INITEDGES:

REM THE START POINT OF EDGE 0 IS 0
EDGES(0, IDXSTARTPOINT) = 0
REM THE END POINT OF EDGE 0 IS 1
EDGES(0, IDXENDPOINT) = 1

REM THE START POINT OF EDGE 1 IS 1
EDGES(1, IDXSTARTPOINT) = 1
REM THE END POINT OF EDGE 1 IS 2
EDGES(1, IDXENDPOINT) = 2

REM THE START POINT OF EDGE 2 IS 2
EDGES(2, IDXSTARTPOINT) = 2
REM THE END POINT OF EDGE 2 IS 3
EDGES(2, IDXENDPOINT) = 3

REM THE START POINT OF EDGE 3 IS 3
EDGES(3, IDXSTARTPOINT) = 3
REM THE END POINT OF EDGE 3 IS 0
EDGES(3, IDXENDPOINT) = 0

By now we have stored all needed information about our rectangle in the arrays POINTS and EDGES.

So let’s draw the rectangle.

We will do this by drawing one edge after the other. To do this, we need to know where the centre C of our 2D world is in pixel coordinates.

Since LowResCoder has a screen width and height of 64 pixels, we define that the origin of our 2D world coordinate system is the centre of the screen, so the screen coordinates of the centre are X = 32, Y = 32.

Let’s store this in two constants:

REM CONSTANTS FOR THE CENTRE OF OUR WORLD IN SCREEN COORDINATES
SCREENCENTREX = 32
SCREENCENTREY = 32

We can easily calculate screen coordinates from our 2D world coordinates:

SCREENX = OURX + SCREENCENTREX
SCREENY = OURY + SCREENCENTREY

Example:

This means that we would plot point P0 which has the coordinates (4, -2) at screen position (36, 30).

Now let’s really draw the rectangle by drawing one edge after the other

REM DRAW ALL EDGES
DRAWEDGES:

REM TO DO THIS: ITERATE OVER ALL EDGES
FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
  REM FETCH START POINT AND END POINT FOR CURRENT EDGE
  STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
  ENDPOINT = EDGES(EDGENO, IDXENDPOINT)
  
  REM FETCH WORLD X POSITION OF START POINT
  STARTPOINTX = POINTS(STARTPOINT, IDXX)
  REM AND CONVERT IT TO SCREEN COORDINATES
  STARTPOINTX = STARTPOINTX + SCREENCENTREX
  
  REM DO THE SAME FOR Y POSITION OF START POINT
  STARTPOINTY = POINTS(STARTPOINT, IDXY)
  STARTPOINTY = STARTPOINTY + SCREENCENTREY
  
  REM AND DO THE SAME FOR X AND Y OF END POINT
  ENDPOINTX = POINTS(ENDPOINT, IDXX)
  ENDPOINTX = ENDPOINTX + SCREENCENTREX
  ENDPOINTY = POINTS(ENDPOINT, IDXY)
  ENDPOINTY = ENDPOINTY + SCREENCENTREY
  
  REM NOW THAT WE HAVE THE SCREEN X AND Y COORDINATES OF 
  REM THE START AND END POINT WE CAN DRAW THE LINE
  LINE STARTPOINTX, STARTPOINTY TO ENDPOINTX, ENDPOINTY
  
NEXT EDGENO

Let’s glue it all together and try it:

Open source code in LowResCoder app

REM VECTOR GRAPHICS - LESSON 1 A - A START
REM BY TODDL



REM SET UP THE POINTS ARRAY

REM HOW MANY POINTS DO WE HAVE - THAT'S THE NUMBER OF ROWS
NUMBEROFPOINTS = 4

REM OUR WORLD IS A 2D COORDINATE SYSTEM (X AND Y) - THAT'S THE NUMBER OF COLUMNS
NUMBEROFDIMENSIONS = 2

REM LET'S CREATE THE POINTS ARRAY
DIM POINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)

REM INDEX OF THE COLUMN THAT HOLDS THE X COORDINATE OF A POINT
IDXX = 0

REM INDEX OF THE COLUMN THAT HOLDS THE Y COORDINATE OF A POINT
IDXY = 1



INITPOINTS: 

REM SET THE X AND Y VALUE FOR POINT P0
POINTS(0, IDXX) = -20
POINTS(0, IDXY) = -10

REM SET THE X AND Y VALUE FOR POINT P1
POINTS(1, IDXX) = 20
POINTS(1, IDXY) = -10

REM SET THE X AND Y VALUE FOR POINT P2
POINTS(2, IDXX) = 20
POINTS(2, IDXY) = 10

REM SET THE X AND Y VALUE FOR POINT P3
POINTS(3, IDXX) = -20
POINTS(3, IDXY) = 10



REM SET UP THE EDGES ARRAY

REM HOW MANY EDGES DO WE HAVE?
NUMBEROFEDGES = 4

REM AN EDGE HAS TWO POINTS
NUMBEROFPOINTSOFANEDGE = 2

REM LET'S CREATE THE EDGES ARRAY
DIM EDGES(NUMBEROFEDGES - 1, NUMBEROFPOINTSOFANEDGE - 1)

REM INDEX OF THE COLUMN THAT HOLDS THE START POINT OF THE EDGE
IDXSTARTPOINT = 0

REM INDEX OF THE COLUMN THAT HOLDS THE END POINT OF THE EDGE
IDXENDPOINT = 1



INITEDGES:

REM THE START POINT OF EDGE 0 IS 0
EDGES(0, IDXSTARTPOINT) = 0
REM THE END POINT OF EDGE 0 IS 1
EDGES(0, IDXENDPOINT) = 1

REM THE START POINT OF EDGE 1 IS 1
EDGES(1, IDXSTARTPOINT) = 1
REM THE END POINT OF EDGE 1 IS 2
EDGES(1, IDXENDPOINT) = 2

REM THE START POINT OF EDGE 2 IS 2
EDGES(2, IDXSTARTPOINT) = 2
REM THE END POINT OF EDGE 2 IS 3
EDGES(2, IDXENDPOINT) = 3

REM THE START POINT OF EDGE 3 IS 3
EDGES(3, IDXSTARTPOINT) = 3
REM THE END POINT OF EDGE 3 IS 0
EDGES(3, IDXENDPOINT) = 0



REM CONSTANTS FOR THE SCREENCENTRE OF OUR WORLD IN SCREEN COORDINATES
SCREENCENTREX = 32
SCREENCENTREY = 32



REM DRAW ALL EDGES

REM TO DO THIS: ITERATE OVER ALL EDGES
FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
  REM FETCH START POINT AND END POINT FOR CURRENT EDGE
  STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
  ENDPOINT = EDGES(EDGENO, IDXENDPOINT)
  
  REM FETCH WORLD X POSITION OF START POINT
  STARTPOINTX = POINTS(STARTPOINT, IDXX)
  REM AND CONVERT IT TO SCREEN COORDINATES
  STARTPOINTX = STARTPOINTX + SCREENCENTREX
  
  REM DO THE SAME FOR Y POSITION OF START POINT
  STARTPOINTY = POINTS(STARTPOINT, IDXY)
  STARTPOINTY = STARTPOINTY + SCREENCENTREY
  
  REM AND DO THE SAME FOR X AND Y OF END POINT
  ENDPOINTX = POINTS(ENDPOINT, IDXX)
  ENDPOINTX = ENDPOINTX + SCREENCENTREX
  ENDPOINTY = POINTS(ENDPOINT, IDXY)
  ENDPOINTY = ENDPOINTY + SCREENCENTREY
  
  REM NOW THAT WE HAVE THE SCREEN X AND Y COORDINATES OF 
  REM THE START AND END POINT WE CAN DRAW THE LINE
  LINE STARTPOINTX, STARTPOINTY TO ENDPOINTX, ENDPOINTY
  
NEXT EDGENO

Now let’s refactor the code a bit so that the initialization of the points and edges array is a bit more elegant.

We’ll do this by storing the inital data for points and edges in DATA lines and refactor our initialization code.

Let’s remember our points table:

POINTS TABLE:

POINT   X,  Y
P0    -20, -10
P1     20, -10
P2     20,  10
P3    -20,  10

We can write this information down in four DATA lines:

REM THE COORDINATES OF OUR POINTS
POINTSDATA:
DATA -20, -10
DATA  20, -10
DATA  20,  10
DATA -20,  10

And read this data via the READ command.

INITPOINTS:

REM SET THE READ POINTER TO THE DATA FOR THE POINTS
RESTORE POINTSDATA

REM NOW READ THE COORDINATES FOR OUR 4 POINTS
FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
  READ POINTS(POINTNO, IDXX)
  READ POINTS(POINTNO, IDXY)
NEXT POINTNO

We’ll do exactly the same for our edges.

The edges table looked like this:

EDGES TABLE:

EDGE   START POINT, END POINT
E0              P0,        P1
E1              P1,        P2
E2              P2,        P3
E3              P3,        P0

We can write this information down in four DATA lines:

REM THE START AND END POINTS OF OUR EDGES
EDGESDATA:
DATA 0, 1
DATA 1, 2
DATA 2, 3
DATA 3, 0

Reading the edges is quite similar to reading the points:

INITEDGES:

REM SET THE READ POINTER TO THE DATA FOR THE EDGES
RESTORE EDGESDATA

REM NOW READ THE START AND END POINT OF OUR 4 EDGES
FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  READ EDGES(EDGENO, IDXSTARTPOINT)
  READ EDGES(EDGENO, IDXENDPOINT)
NEXT EDGENO

Let’s glue it all together again and try the improved version out – it should still show a rectangle:

Note: I leave out most of the comments now.

Open source code in LowResCoder app

REM VECTOR GRAPHICS - LESSON 1 B - REFACTORED CODE
REM BY TODDL



REM SET UP POINTS ARRAY OF THE RECTANGLE

NUMBEROFPOINTS = 4
NUMBEROFDIMENSIONS = 2
DIM POINTS(NUMBEROFPOINTS - 1, NUMBEROFDIMENSIONS - 1)
IDXX = 0
IDXY = 1

INITPOINTS:

RESTORE POINTSDATA
FOR POINTNO = 0 TO NUMBEROFPOINTS - 1
  READ POINTS(POINTNO, IDXX)
  READ POINTS(POINTNO, IDXY)
NEXT POINTNO



REM SET UP EDGES ARRAY OF THE RECTANGLE

NUMBEROFEDGES = 4
NUMBEROFPOINTSOFANEDGE = 2
DIM EDGES(NUMBEROFEDGES - 1, NUMBEROFPOINTSOFANEDGE - 1)
IDXSTARTPOINT = 0
IDXENDPOINT = 1

INITEDGES:

RESTORE EDGESDATA
FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  READ EDGES(EDGENO, IDXSTARTPOINT)
  READ EDGES(EDGENO, IDXENDPOINT)
NEXT EDGENO



SCREENCENTREX = 32
SCREENCENTREY = 32



DRAWEDGES:
FOR EDGENO = 0 TO NUMBEROFEDGES - 1
  
  STARTPOINT = EDGES(EDGENO, IDXSTARTPOINT)
  ENDPOINT = EDGES(EDGENO, IDXENDPOINT)

  REM MADE THE CODE A BIT MORE COMPACT HERE...
  STARTPOINTX = POINTS(STARTPOINT, IDXX) + SCREENCENTREX
  STARTPOINTY = POINTS(STARTPOINT, IDXY) + SCREENCENTREY
  ENDPOINTX = POINTS(ENDPOINT, IDXX) + SCREENCENTREX
  ENDPOINTY = POINTS(ENDPOINT, IDXY) + SCREENCENTREY
  
  LINE STARTPOINTX, STARTPOINTY TO ENDPOINTX, ENDPOINTY
  
NEXT EDGENO



POINTSDATA:
DATA -20, -10
DATA  20, -10
DATA  20,  10
DATA -20,  10

EDGESDATA:
DATA 0, 1
DATA 1, 2
DATA 2, 3
DATA 3, 0

Continued in lesson 2…

Vector Graphics with LowResCoder – Lesson 1