Skip to content

Instantly share code, notes, and snippets.

@danj2k
Last active July 6, 2024 14:10
Show Gist options
  • Save danj2k/374776c005929d4b0de9108f89db6b5f to your computer and use it in GitHub Desktop.
Save danj2k/374776c005929d4b0de9108f89db6b5f to your computer and use it in GitHub Desktop.
BBC BASIC program to draw a map of Great Britain
REM Requires GXR (or BBC Master) for flood fill
ON ERROR VDU23,1,1,0;0;0;0;:END
MODE 1
REM Swap yellow for green
VDU19,2,2,0,0,0
REM Define dither patterns
VDU23,12,1,0,0,1,1,0,0,1
VDU23,13,2,0,0,2,2,0,0,2
VDU23,14,1,2,2,1,1,2,2,1
REM Country outlines
GCOL 0,3
FOR P% = 1 TO 5
F% = 1
READ X%, Y%
REPEAT
IF F% = 1 THEN MOVE (X%*4)+230, (Y%*8)+100 ELSE DRAW (X%*4)+230, (Y%*8)+100
IF F% = 1 THEN F% = 0
READ X%, Y%
UNTIL X% < 0
NEXT P%
REM Flood fill
FOR C% = 1 TO 3
READ P%
FOR Q% = 1 TO P%
READ X%, Y%
IF Q% = 1 THEN A% = X%: B% = Y%
GCOL 16*C%,0
PLOT &85,(X%*4)+230, (Y%*8)+100
NEXT Q%
REM Labels
A% = (A%*4)+230: B% = (B%*8)+100
IF C% = 1 THEN B% = 96: A% = A% - 112: L$ = "England"
IF C% = 2 THEN B% = 984: A% = A% - 128: L$ = "Scotland"
IF C% = 3 THEN A% = A% - 304: B% = B% + 16: L$ = "Wales"
VDU 5
MOVE A%, B%
GCOL 0,3
PRINT L$;
VDU 4
NEXT C%
REM Turn cursor off
VDU23,1,0;0;0;0;
REPEAT UNTIL FALSE
REM Data for England
DATA 125, 55, 127, 54, 129, 54, 131, 53, 132, 51, 134, 51, 136, 50, 138, 50, 136, 49, 136, 47, 142, 44, 136, 44, 134, 45, 132, 45, 134, 45, 138, 43
DATA 140, 43, 144, 41, 146, 37, 144, 37, 140, 35, 142, 36, 144, 36, 142, 36, 144, 36, 146, 35, 148, 35, 150, 36, 154, 36, 156, 37, 158, 36, 164, 36
DATA 166, 35, 168, 35, 170, 34, 171, 32, 171, 30, 169, 26, 167, 26, 165, 25, 163, 25, 164, 23, 162, 23, 160, 22, 158, 22, 157, 20, 159, 21, 161, 21
DATA 159, 21, 155, 19, 153, 19, 155, 19, 157, 18, 167, 18, 167, 16, 163, 14, 161, 14, 157, 12, 153, 12, 151, 11, 147, 11, 145, 10, 143, 10, 141, 11
DATA 131, 11, 129, 10, 119, 10, 117, 11, 115, 10, 107, 10, 103, 8, 99, 8, 97, 9, 97, 7, 93, 9, 91, 9, 89, 10, 87, 10, 85, 9, 77, 9
DATA 76, 7, 76, 5, 74, 5, 72, 4, 70, 4, 68, 5, 66, 5, 64, 6, 62, 5, 60, 6, 58, 6, 56, 5, 52, 5, 50, 4, 48, 4, 46, 3
DATA 45, 1, 43, 1, 42, 3, 38, 3, 36, 2, 34, 2, 35, 4, 41, 4, 43, 5, 45, 5, 46, 7, 48, 7, 50, 8, 52, 8, 56, 10, 57, 12
DATA 59, 13, 63, 13, 63, 15, 65, 15, 67, 16, 77, 16, 79, 15, 83, 15, 87, 17, 84, 17, 86, 18, 88, 18, 90, 19, 92, 19, 92, 21, 93, 23
DATA 89, 23, 87, 24, 85, 24, 84, 26, 86, 27, 87, 29, 83, 29, 87, 31, 85, 31, 86, 33, 84, 34, 88, 36, 90, 36, 92, 35, 90, 36, 89, 38
DATA 87, 38, 83, 40, 82, 42, 84, 41, 86, 41, 85, 43, 86, 45, 86, 47, 90, 49, 82, 49, 81, 51, 77, 53, 77, 55, 79, 56, 80, 58, 82, 59
DATA 86, 59, 90, 61, 92, 61, 100, 65, 102, 65, 100, 66, 101, 68, 103, 68, 105, 69, 111, 66, 112, 64, 112, 62, 114, 61, 116, 57, 120, 55, 124, 55
DATA 125, 55, -1, -1
DATA 117, 10, 121, 10, 120, 8, 116, 8, 114, 9, 112, 9, 114, 9, 116, 10, 117, 10, -1, -1
REM Data for Scotland
DATA 45, 85, 49, 85, 47, 85, 46, 87, 48, 87, 50, 86, 48, 87, 46, 87, 48, 88, 50, 88, 44, 88, 43, 90, 45, 91, 47, 90, 49, 90, 47, 90
DATA 45, 91, 47, 92, 45, 92, 45, 94, 47, 94, 49, 95, 51, 94, 55, 94, 51, 96, 53, 96, 53, 98, 59, 98, 57, 98, 55, 99, 57, 100, 57, 102
DATA 59, 103, 61, 102, 63, 102, 62, 100, 66, 102, 68, 101, 66, 101, 70, 101, 72, 102, 84, 102, 86, 103, 88, 103, 88, 101, 87, 99, 85, 99, 81, 97
DATA 79, 97, 75, 95, 73, 95, 73, 93, 71, 93, 69, 94, 71, 93, 77, 93, 75, 93, 73, 92, 71, 92, 69, 91, 67, 91, 73, 91, 71, 91, 70, 89
DATA 68, 89, 70, 89, 72, 90, 76, 90, 78, 91, 80, 91, 82, 92, 84, 92, 86, 91, 106, 91, 108, 90, 108, 88, 106, 88, 104, 87, 101, 81, 99, 81
DATA 97, 80, 96, 78, 94, 78, 92, 77, 88, 77, 86, 76, 84, 76, 88, 76, 90, 77, 92, 77, 91, 75, 95, 75, 93, 74, 89, 74, 87, 73, 85, 73
DATA 83, 72, 77, 72, 83, 72, 85, 71, 89, 71, 91, 72, 95, 72, 97, 71, 101, 71, 103, 70, 103, 68, 101, 68, 99, 67, 101, 66, 91, 61, 89, 61
DATA 85, 59, 79, 59, 77, 58, 73, 58, 71, 57, 69, 57, 67, 58, 65, 58, 64, 56, 62, 56, 58, 58, 54, 58, 55, 56, 51, 58, 51, 60, 53, 60
DATA 54, 62, 56, 62, 57, 64, 61, 66, 57, 68, 57, 70, 59, 71, 61, 71, 59, 72, 57, 72, 58, 74, 60, 74, 58, 74, 56, 70, 54, 70, 53, 72
DATA 51, 71, 49, 71, 50, 73, 52, 73, 56, 75, 54, 75, 48, 72, 48, 70, 50, 70, 48, 69, 47, 67, 45, 66, 46, 64, 42, 64, 42, 66, 43, 68
DATA 47, 70, 45, 69, 44, 71, 46, 71, 44, 71, 46, 72, 44, 72, 46, 73, 46, 75, 48, 75, 46, 75, 50, 77, 54, 77, 50, 77, 48, 78, 52, 78
DATA 50, 78, 51, 80, 55, 80, 53, 80, 54, 82, 52, 82, 54, 82, 46, 78, 42, 78, 40, 79, 42, 80, 46, 80, 36, 80, 38, 81, 42, 81, 44, 82
DATA 42, 82, 43, 84, 45, 84, 45, 85, -1, -1
REM Data for Wales
DATA 81, 41, 83, 40, 85, 40, 89, 38, 89, 36, 91, 36, 87, 36, 85, 35, 86, 33, 85, 31, 87, 31, 85, 30, 83, 30, 85, 29, 87, 29, 86, 27
DATA 84, 27, 84, 25, 86, 24, 88, 24, 90, 23, 92, 23, 92, 21, 91, 19, 85, 19, 83, 18, 81, 18, 79, 17, 77, 18, 75, 18, 71, 20, 65, 20
DATA 63, 19, 63, 21, 61, 21, 59, 22, 55, 22, 51, 20, 49, 20, 51, 21, 49, 22, 45, 22, 47, 22, 46, 24, 44, 23, 48, 25, 52, 25, 54, 26
DATA 56, 26, 58, 27, 62, 27, 64, 28, 66, 28, 67, 30, 67, 34, 65, 35, 61, 35, 59, 34, 55, 34, 59, 36, 61, 36, 69, 40, 79, 40, 81, 41
DATA 81, 41, -1, -1
DATA 62, 42, 66, 40, 68, 40, 64, 38, 62, 38, 60, 39, 58, 39, 59, 41, 61, 41, 62, 42, -1, -1
REM Flood fill points for England
DATA 2
DATA 115, 33
DATA 117, 9
REM Flood fill points for Scotland
DATA 1
DATA 70, 79
REM Flood fill points for Wales
DATA 2
DATA 76, 28
DATA 63, 40
# Python program to generate the data for the BBC Micro map drawing
import fiona
import math
import os
from rdp import rdp
from polylabel import polylabel
geo_data = []
# Download the Boundary-Line™ GeoPackage from Ordnance Survey at https://osdatahub.os.uk/downloads/open/BoundaryLine
with fiona.open('bdline_gb.gpkg', layer='country_region') as layer:
minx, miny, maxx, maxy = layer.bounds
width = maxx - minx
height = maxy - miny
aspect = width/height
xscale = 320 * aspect
sorted_layer = sorted(layer, key=lambda x: x.properties['Hectares'], reverse=True) # reverse sort by land area
total_pcount = 0
for feature in sorted_layer[:3]: # biggest 3 areas will be the 3 countries of Great Britain
scaled_coords = []
for polygon in feature.geometry['coordinates']:
ring = polygon[0] # first ring is exterior ring
polygon_coords = []
oldx = -999
oldy = -999
first = True
for c in ring:
x, y = c
scaled_x = int(math.ceil((x - minx)*xscale/(maxx - minx)))
scaled_y = int(math.ceil((y - miny)*128/(maxy - miny)))
if first:
first_x = scaled_x
first_y = scaled_y
first = False
if abs(oldx-scaled_x)>1 or abs(oldy-scaled_y)>1:
polygon_coords.append([scaled_x, scaled_y])
oldx = scaled_x
oldy = scaled_y
polygon_coords = rdp(polygon_coords)
if len(polygon_coords) > 1:
scaled_coords.extend(polygon_coords)
scaled_coords.append([first_x,first_y])
scaled_coords.append([-1,-1])
total_pcount = total_pcount + 1
geo_data.append({ "name": feature.properties['Name'], "coordinates": scaled_coords })
minx = 999
miny = 999
maxx = -999
maxy = -999
fill_block = ""
for g in geo_data:
line = "REM Data for " + g['name']
print(line)
scaled_coords = g['coordinates']
line = "DATA "
thislinecount = 0
for c in scaled_coords:
x, y = c
if x == -1 or y == -1:
thislinecount = 15
if thislinecount < 15:
line = line + str(x) + ", " + str(y) + ", "
thislinecount = thislinecount + 1
else:
line = line + str(x) + ", " + str(y)
thislinecount = 0
print(line)
line = "DATA "
if x > maxx:
maxx = x
if y > maxy:
maxy = y
if x < minx and x > -1:
minx = x
if y < miny and y > -1:
miny = y
if thislinecount > 0:
print(line)
line = "REM Flood fill points for " + g['name']
fill_block = fill_block + line + os.linesep
polygon_coords = []
pcount = 0
fill_line = ""
first = True
for c in scaled_coords:
x, y = c
if x == -1 or y == -1:
fill_point = polylabel([polygon_coords])
fill_x, fill_y = fill_point
if not first:
fill_line = fill_line + os.linesep
else:
first = False
fill_line = fill_line + "DATA " + str(math.ceil(fill_x)) + ", " + str(math.ceil(fill_y))
polygon_coords = []
pcount = pcount + 1
else:
polygon_coords.append([x, y])
line = "DATA " + str(pcount) + os.linesep
fill_block = fill_block + line + fill_line + os.linesep
print(fill_block)
print("Number of polygons: " + str(total_pcount))
print("Bounds: " + str(minx) + ", " + str(miny) + " - " + str(maxx) + ", " + str(maxy))
# Python program to draw a map of Great Britain
import fiona
import math
import os
from rdp import rdp
from polylabel import polylabel
from graphics import * # graphics.py
geo_data = []
# Download the Boundary-Line™ GeoPackage from Ordnance Survey at https://osdatahub.os.uk/downloads/open/BoundaryLine
with fiona.open('bdline_gb.gpkg', layer='country_region') as layer:
minx, miny, maxx, maxy = layer.bounds
width = maxx - minx
height = maxy - miny
aspect = width/height
xscale = 320 * aspect
sorted_layer = sorted(layer, key=lambda x: x.properties['Hectares'], reverse=True) # reverse sort by land area
total_pcount = 0
for feature in sorted_layer[:3]: # biggest 3 areas will be the 3 countries of Great Britain
scaled_coords = []
for polygon in feature.geometry['coordinates']:
ring = polygon[0] # first ring is exterior ring
polygon_coords = []
oldx = -999
oldy = -999
first = True
for c in ring:
x, y = c
scaled_x = int(math.ceil((x - minx)*xscale/(maxx - minx)))
scaled_y = int(math.ceil((y - miny)*128/(maxy - miny)))
if first:
first_x = scaled_x
first_y = scaled_y
first = False
if abs(oldx-scaled_x)>1 or abs(oldy-scaled_y)>1:
polygon_coords.append([scaled_x, scaled_y])
oldx = scaled_x
oldy = scaled_y
polygon_coords = rdp(polygon_coords)
if len(polygon_coords) > 1:
scaled_coords.extend(polygon_coords)
scaled_coords.append([first_x,first_y])
scaled_coords.append([-1,-1])
total_pcount = total_pcount + 1
geo_data.append({ "name": feature.properties['Name'], "coordinates": scaled_coords })
win = GraphWin(title = "Map of Great Britain", width = 640, height = 512)
win.setCoords(0,0,639,511)
win.setBackground("black")
country_colours = ["red", "green", "yellow"]
for g in geo_data:
scaled_coords = g['coordinates']
polygon_coords = []
polygon_points = []
this_colour = country_colours.pop(0)
first = True
for c in scaled_coords:
x, y = c
if x == -1 or y == -1:
aPolygon = Polygon(polygon_points)
aPolygon.setFill(this_colour)
aPolygon.setOutline("white")
aPolygon.setWidth(3)
aPolygon.draw(win)
if first:
label_coords = polylabel([polygon_coords])
label_x, label_y = label_coords
if g['name'] == "England":
label_y = 48
if g['name'] == "Scotland":
label_y = 492
if g['name'] == "Wales":
label_x = label_x - 114
label_point = Point(label_x, label_y)
label = Text(label_point, g['name'])
label.setFace("courier")
label.setStyle("bold")
label.setSize(18)
label.setTextColor("white")
label.draw(win)
first = False
polygon_coords = []
polygon_points = []
else:
polygon_points.append(Point((x*2)+115,(y*4)+50))
polygon_coords.append([(x*2)+115,(y*4)+50])
clickPoint = win.getMouse()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment