Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add various functions to convert polar geometry to cartesian geometry #17

Merged
merged 4 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Beautiful Micropython Graphics

<img src="./pico-tempe-shapes.png" width="480" alt="A Raspberry Pi Pico with a variety of shapes drawn on a screen" /> <img src=".//docs/source/user_guide/shapes.png" width="160" alt="A variety of shapes drawn in an image" />

<img src="./pico-tempe-polar.png" width="480" alt="A Raspberry Pi Pico with a variety of polar plots on the screen" /> <img src=".//docs/source/user_guide/polar.png" width="160" alt="A variety of polar plots drawn in an image" />

Tempe is a pure-Micropython graphics system designed to be make using the
full capabilities of display devices more accessible, particularly on
memory-constrained microcontrollers. The aim is to allow data scientists,
Expand Down
Binary file added docs/source/user_guide/polar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 7 additions & 10 deletions examples/lines_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,13 @@
# draw some polylines
polylines = WidePolyLines(
RowGeometry([
(
array('h', [
10 + 30 * i, 125,
10 + 30 * i, 225,
15 + 30 * i, 225,
25 + 30 * i, 165,
10 + 30 * i, 125,
]),
i+1,
)
array('h', [
10 + 30 * i, 125,
10 + 30 * i, 225,
15 + 30 * i, 225,
25 + 30 * i, 165,
10 + 30 * i, 125,
] + [i+1])
for i in range(10)
]),
Interpolated(viridis, 10),
Expand Down
189 changes: 189 additions & 0 deletions examples/polar_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
import asyncio
from array import array
import framebuf
import random
import math

from tempe.colors import grey_e, grey_3
from tempe.colormaps.viridis import viridis
from tempe.data_view import Repeat, Range, Interpolated
from tempe.geometry import ColumnGeometry, Extend, RowGeometry
from tempe.polar_geometry import polar_rects, polar_point_arrays, polar_points, polar_r_lines
from tempe.surface import Surface
from tempe.shapes import Rectangles, Polygons, Circles, Lines
from tempe.markers import Markers
from tempe.display import FileDisplay

random.seed(0)

surface = Surface()

# a buffer one quarter the size of the screen
working_buffer = array('H', bytearray(2*320*61))

# fill the background with white pixels
background = Rectangles([(0, 0, 320, 240)], [0xffff])
surface.add_shape('BACKGROUND', background)


# draw a coxcomb plot
circle_grid = Circles(
ColumnGeometry([
Repeat(64),
Repeat(64),
Range(10, 70, 10),
]),
Repeat(grey_e),
fill=False,
clip=(0, 0, 320, 240),
)
surface.add_shape('UNDERLAY', circle_grid)
ray_grid = Lines(
polar_r_lines(64, 64, ColumnGeometry([
Repeat(0),
Range(0, 360, 60),
Repeat(60),
])),
Repeat(grey_e),
clip=(0, 0, 320, 240),
)
surface.add_shape('UNDERLAY', ray_grid)
coxcomb = Polygons(
polar_rects(64, 64, ColumnGeometry([
Repeat(0),
Range(0, 360, 60),
[30, 15, 45, 5, 45, 60],
Repeat(60)
])),
Interpolated(viridis, 6),
clip=(0, 0, 320, 240),
)
surface.add_shape('DRAWING', coxcomb)

# draw a radar plot
circle_grid = Circles(
ColumnGeometry([
Repeat(196),
Repeat(64),
Range(10, 70, 10),
]),
Repeat(grey_e),
fill=False,
clip=(0, 0, 320, 240),
)
surface.add_shape('UNDERLAY', circle_grid)
ray_grid = Lines(
polar_r_lines(196, 64, ColumnGeometry([
Repeat(0),
Range(0, 360, 60),
Repeat(60),
])),
Repeat(grey_e),
clip=(0, 0, 320, 240),
)
surface.add_shape('UNDERLAY', ray_grid)
radar = Polygons(
polar_point_arrays(196, 64,
RowGeometry.from_lists([
[30, 0, 15, 60, 45, 120, 5, 180, 45, 240, 60, 300],
[12, 0, 18, 60, 43, 120, 35, 180, 25, 240, 20, 300],
]),
),
Interpolated(viridis, 6),
fill=False,
clip=(0, 0, 320, 240),
)
surface.add_shape('DRAWING', radar)
markers = Markers(
Extend([
polar_points(196, 64,
ColumnGeometry([
[30, 15, 45, 5, 45, 60],
Range(0, 360, 60),
]),
),
ColumnGeometry([Repeat(24)]),
]),
Repeat(grey_3),
[f" {x}" for x in [6, 3, 9, 1, 9, 12]],
clip=(0, 0, 320, 240),
)
surface.add_shape('OVERLAY', markers)

circle_bar = Polygons(
polar_rects(128, 240-64, ColumnGeometry([
Range(24, 60, 12),
Repeat(-90),
Repeat(8),
[240, 320, 100],
]), decimation=6),
Interpolated(viridis, 3),
clip=(0, 0, 320, 240),
)
surface.add_shape('DRAWING', circle_bar)
circle_bar_ends = Circles(
Extend([
polar_points(128, 240-64, ColumnGeometry([
Range(28, 60, 12),
[240-90, 320-90, 100-90],
])),
ColumnGeometry([Repeat(4)]),
]),
Interpolated(viridis, 3),
fill=True,
clip=(0, 0, 320, 240),
)
surface.add_shape('DRAWING', circle_bar_ends)

values = [6, 3, 9, 1, 9, 12]
cumsum = [sum(values[:i]) for i in range(len(values) + 1)]
angles = [int(values * 360 / cumsum[-1]) for values in cumsum]
deltas = [angles[i+1] - angles[i] for i in range(len(values))]

donut = Polygons(
polar_rects(256, 240-64, ColumnGeometry([
Repeat(30),
angles[:-1],
Repeat(24),
deltas,
]), decimation=10),
Interpolated(viridis, 6),
fill=True,
clip=(0, 0, 320, 240),
)
surface.add_shape('DRAWING', donut)


def main(surface, working_buffer):

async def init_display():
from devices.st7789 import ST7789
from machine import Pin, SPI

spi = SPI(0, baudrate=62_500_000, phase=1, polarity=1, sck=Pin(18, Pin.OUT), mosi=Pin(19, Pin.OUT), miso=Pin(16, Pin.OUT))
backlight = Pin(20, Pin.OUT)
display = ST7789(spi, cs_pin=Pin(17, Pin.OUT, value=1), dc_pin=Pin(16, Pin.OUT))
backlight(1)
await display.init()
return display

# set up the display object
display = asyncio.run(init_display())

# refresh the display
display.clear()
surface.refresh(display, working_buffer)

if __name__ == '__main__':

# if we have an actual screen, use it
main(surface, working_buffer)

elif __name__ != '__test__':

# set up the display object
display = FileDisplay('polar.rgb565', (320, 240))
# refresh the display
with display:
display.clear()
surface.refresh(display, working_buffer)
Binary file added pico-tempe-polar.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
34 changes: 30 additions & 4 deletions src/tempe/geometry.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from .data_view import DataView

from array import array
from math import pi, sin, cos

from .data_view import DataView

POINT = "point"
CIRCLE = "circle"
Expand Down Expand Up @@ -43,7 +45,11 @@ def __iter__(self):
yield array("h", coords)

def __len__(self):
return max(len(coord) for coord in self.geometry)
lengths = [len(coord) for coord in self.geometry if len(coord) is not None]
if lengths:
return max(lengths)
else:
return None


class StripGeometry(Geometry):
Expand All @@ -65,9 +71,29 @@ def __iter__(self):
start = 0
buf = array("h", bytearray(2 * size))
for i in range(len(self)):
start += self.step * self.n_coords
buf[:] = self.geometry[start : start + size]
start += self.step * self.n_coords
yield buf

def __len__(self):
return ((len(self.geometry) // self.n_coords) - self.n_vertices) // self.step + 1


class Extend(Geometry):

def __iter__(self):
for coords in zip(*self.geometry):
buf = array('h', bytearray(2*sum(len(coord) for coord in coords)))
i = 0
for coord in coords:
buf[i:i + len(coord)] = coord
i += len(coord)
yield buf

def __len__(self):
return ((len(self.geometry) // self.n_coords) - self.n_vertices) // self.step
lengths = [len(coord) for coord in self.geometry if len(coord) is not None]
if lengths:
return max(lengths)
else:
return None

6 changes: 4 additions & 2 deletions src/tempe/lines.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ class WidePolyLines(ColoredGeometry):
def draw(self, buffer, x=0, y=0):
vertices = array('h', bytearray(16))
for geometry, color in self:
lines, w = geometry
w = geometry[-1]
lines = geometry[:-1]
for i in range(0, len(lines) - 2, 2):
x0 = lines[i]
y0 = lines[i+1]
Expand All @@ -84,7 +85,8 @@ def _bounds(self):
max_y = -0x7fff
min_y = 0x7fff
for geometry in self.geometry:
lines, w = geometry
w = geometry[-1]
lines = geometry[:-1]
for i in range(0, len(lines), 2):
max_x = max(max_x, lines[i] + w)
min_x = min(min_x, lines[i] - w)
Expand Down
1 change: 1 addition & 0 deletions src/tempe/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
["tempe/geometry.py", "github:unital/tempe/src/tempe/geometry.py"],
["tempe/lines.py", "github:unital/tempe/src/tempe/lines.py"],
["tempe/markers.py", "github:unital/tempe/src/tempe/markers.py"],
["tempe/polar.py", "github:unital/tempe/src/tempe/polar.py"],
["tempe/raster.py", "github:unital/tempe/src/tempe/raster.py"],
["tempe/shapes.py", "github:unital/tempe/src/tempe/shapes.py"],
["tempe/surface.py", "github:unital/tempe/src/tempe/surface.py"],
Expand Down
Loading