-
Notifications
You must be signed in to change notification settings - Fork 499
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
PicoVector. #783
PicoVector. #783
Conversation
5249a0e
to
ddc3e41
Compare
Some rather rough and ready code to render a radial 6-channel spectrometer graph. import time
import math
from pimoroni_i2c import PimoroniI2C
from breakout_as7262 import BreakoutAS7262
from picographics import PicoGraphics, DISPLAY_PICO_W_EXPLORER, PEN_RGB332
from picovector import PicoVector, Polygon, RegularPolygon, ANTIALIAS_NONE, ANTIALIAS_X4, ANTIALIAS_X16
PINS_BREAKOUT_GARDEN = {"sda": 4, "scl": 5}
PINS_PICO_EXPLORER = {"sda": 20, "scl": 21}
i2c = PimoroniI2C(**PINS_PICO_EXPLORER)
as7262 = BreakoutAS7262(i2c)
dev_type = as7262.device_type()
hw_version = as7262.hardware_version()
fw_version = as7262.firmware_version()
as7262.set_gain(BreakoutAS7262.X16)
as7262.set_measurement_mode(BreakoutAS7262.CONT_ROYGBR)
as7262.set_illumination_current(BreakoutAS7262.MA12)
as7262.set_indicator_current(BreakoutAS7262.MA4)
as7262.set_leds(True, True)
print("Device: ", dev_type, "HW: ", hw_version, sep="", end=", ")
print("FW: ", fw_version[0], ".", fw_version[1], ".", fw_version[2])
display = PicoGraphics(DISPLAY_PICO_W_EXPLORER, pen_type=PEN_RGB332)
display.set_backlight(0.8)
vector = PicoVector(display)
vector.set_antialiasing(ANTIALIAS_X4)
result = vector.set_font("/AdvRe.af", 30)
WIDTH, HEIGHT = display.get_bounds()
RADIUS = 90
SPIN_DEGREES = 0
angle = 0
RED = display.create_pen(255, 0, 0)
ORANGE = display.create_pen(255, 128, 0)
YELLOW = display.create_pen(255, 255, 0)
GREEN = display.create_pen(0, 255, 0)
BLUE = display.create_pen(0, 0, 255)
VIOLET = display.create_pen(255, 0, 255)
BLACK = display.create_pen(0, 0, 0)
GREY = display.create_pen(128, 128, 128)
WHITE = display.create_pen(255, 255, 255)
cols = [RED, ORANGE, YELLOW, GREEN, BLUE, VIOLET]
def regular_polygon(o_x, o_y, radius, rotation):
sides = 6
angle = math.radians(360 / sides)
rotation = math.radians(rotation)
points = []
for side in range(sides):
current_angle = side * angle + rotation
x = math.cos(current_angle) * radius[side]
y = math.sin(current_angle) * radius[side]
points.append((int(x) + o_x, int(y) + o_y))
return Polygon(*points)
labels = [
"R",
"O",
"Y",
"G",
"B",
"V"
]
angle = 0
while True:
display.set_pen(BLACK)
display.clear()
reading = list(as7262.read())
print("R:", reading[0], end=" ")
print("O:", reading[1], end=" ")
print("Y:", reading[2], end=" ")
print("G:", reading[3], end=" ")
print("B:", reading[4], end=" ")
print("V:", reading[5])
for i in range(6):
reading[i] = int(reading[i] / 3.0)
reading[i] = min(reading[i], RADIUS)
poly = regular_polygon(int(WIDTH / 2), int(HEIGHT / 2), reading, 0)
lines = RegularPolygon(int(WIDTH / 2), int(HEIGHT / 2), 6, RADIUS)
label_points = RegularPolygon(int(WIDTH / 2), int(HEIGHT / 2), 6, RADIUS * 0.7)
vector.rotate(poly, angle, int(WIDTH / 2), int(HEIGHT / 2))
vector.rotate(lines, angle, int(WIDTH / 2), int(HEIGHT / 2))
vector.rotate(label_points, angle - (360 / 12), int(WIDTH / 2), int(HEIGHT / 2))
display.set_pen(GREY)
for point in lines:
x, y = point
display.line(int(WIDTH / 2), int(HEIGHT / 2), int(x), int(y))
points = list(poly)
a = points[-1]
c = (int(WIDTH / 2), int(HEIGHT / 2))
for i in range(6):
display.set_pen(cols[i])
b = points[i]
vector.draw(Polygon(a, b, c))
a = b
i = 0
for p in label_points:
l = labels[i]
x, y = p
display.set_pen(cols[i])
vector.text(l, int(x) - 5, int(y) - 20)
i += 1
display.set_pen(WHITE)
vector.text("Spectrograph", 5, -5)
angle += SPIN_DEGREES
display.update() |
9f911d1
to
b969631
Compare
And a clock example, because it was inevitable - import time
import math
import random
from picographics import PicoGraphics, DISPLAY_PICO_W_EXPLORER, PEN_RGB332
from picovector import PicoVector, Polygon, RegularPolygon, Rectangle, ANTIALIAS_NONE, ANTIALIAS_X4, ANTIALIAS_X16
display = PicoGraphics(DISPLAY_PICO_W_EXPLORER, pen_type=PEN_RGB332)
display.set_backlight(0.8)
vector = PicoVector(display)
vector.set_antialiasing(ANTIALIAS_X4)
RED = display.create_pen(255, 0, 0)
ORANGE = display.create_pen(255, 128, 0)
YELLOW = display.create_pen(255, 255, 0)
GREEN = display.create_pen(0, 255, 0)
BLUE = display.create_pen(0, 0, 255)
VIOLET = display.create_pen(255, 0, 255)
BLACK = display.create_pen(0, 0, 0)
GREY = display.create_pen(128, 128, 128)
WHITE = display.create_pen(255, 255, 255)
result = vector.set_font("/AdvRe.af", 30)
WIDTH, HEIGHT = display.get_bounds()
def random_polygon(length, x, y, w, h):
for i in range(length):
yield random.randint(x, x + w), random.randint(y, y + h)
hub = RegularPolygon(int(WIDTH / 2), int(HEIGHT / 2), 36, 5)
hub2 = RegularPolygon(int(WIDTH / 2), int(HEIGHT / 2), 36, 10)
#p = RegularPolygon(0, 0, 6, 100)
a = 0
print(time.localtime())
while True:
year, month, day, hour, minute, second, _, _ = time.localtime()
#p = Polygon(*random_polygon(10, 0, 0, WIDTH, HEIGHT))
display.set_pen(BLACK)
display.clear()
display.set_pen(GREY)
tick_mark = Rectangle(int(WIDTH / 2) - 1, 0, 2, 10)
for _ in range(12):
vector.rotate(tick_mark, 360 / 12.0, int(WIDTH / 2), int(HEIGHT / 2))
vector.draw(tick_mark)
angle_second = second * 6
second_hand = Rectangle(-1, -100, 2, 100)
vector.rotate(second_hand, angle_second, 0, 0)
vector.translate(second_hand, int(WIDTH / 2), int(HEIGHT / 2))
angle_minute = minute * 6
angle_minute += second / 10.0
minute_hand = Rectangle(-2, -60, 4, 60)
vector.rotate(minute_hand, angle_minute, 0, 0)
vector.translate(minute_hand, int(WIDTH / 2), int(HEIGHT / 2))
angle_hour = (hour % 12) * 30
angle_hour += minute / 2
hour_hand = Rectangle(-3, -30, 6, 30)
vector.rotate(hour_hand, angle_hour, 0, 0)
vector.translate(hour_hand, int(WIDTH / 2), int(HEIGHT / 2))
display.set_pen(WHITE)
vector.draw(second_hand, minute_hand, hour_hand)
display.set_pen(BLACK)
vector.draw(hub2)
display.set_pen(WHITE)
vector.draw(hub)
display.update()
time.sleep(1.0 / 30)
a += 1 |
Rotated text test for benchmarking: import time
import math
import random
import machine
from picographics import PicoGraphics, DISPLAY_PICO_W_EXPLORER, PEN_RGB332
from picovector import PicoVector, Polygon, RegularPolygon, Rectangle, ANTIALIAS_NONE, ANTIALIAS_X4, ANTIALIAS_X16
machine.freq(250_000_000)
display = PicoGraphics(DISPLAY_PICO_W_EXPLORER, pen_type=PEN_RGB332)
display.set_backlight(0.8)
vector = PicoVector(display)
vector.set_antialiasing(ANTIALIAS_NONE)
RED = display.create_pen(255, 0, 0)
ORANGE = display.create_pen(255, 128, 0)
YELLOW = display.create_pen(255, 255, 0)
GREEN = display.create_pen(0, 255, 0)
BLUE = display.create_pen(0, 0, 255)
VIOLET = display.create_pen(255, 0, 255)
BLACK = display.create_pen(0, 0, 0)
GREY = display.create_pen(128, 128, 128)
WHITE = display.create_pen(255, 255, 255)
result = vector.set_font("/Jokerman-Regular.af", 30)
WIDTH, HEIGHT = display.get_bounds()
X = int(WIDTH / 2)
Y = int(HEIGHT / 2)
a = 0
frames = 0
t_count = 0
t_total = 0
while True:
tstart = time.ticks_ms()
display.set_pen(BLACK)
display.clear()
for x in range(8):
c = 31 + (x * 32)
display.set_pen(display.create_pen(255-c, 0, c))
vector.text("Hello World\nHello World", X, Y, angle=x * 45 + a)
display.update()
a += 1
tfinish = time.ticks_ms()
total = tfinish - tstart
t_total += total
t_count += 1
if t_count == 60:
per_frame_avg = t_total / t_count
print(f"60 frames in {t_total}ms, avg {per_frame_avg:.02f}ms per frame, {1000/per_frame_avg:.02f} FPS")
t_count = 0
t_total = 0
# pause for a moment (important or the USB serial device will fail)
# try to pace at 60fps or 30fps
if total > 1000 / 30:
time.sleep(0.0001)
elif total > 1000 / 60:
t = 1000 / 30 - total
time.sleep(t / 1000)
else:
t = 1000 / 60 - total
time.sleep(t / 1000) |
Example to bake the points for two concentric circles and then animate it as if it were a radial loading graph by selecting groups of four points to display. Resolutions over 45 points will give a slightly smoother circle, but the RGB332 colourspace runs out of distinct colours to represent the segments: import time
import math
import random
from picographics import PicoGraphics, DISPLAY_PICO_W_EXPLORER, PEN_RGB332
from picovector import PicoVector, Polygon, RegularPolygon, Rectangle, ANTIALIAS_NONE, ANTIALIAS_X4, ANTIALIAS_X16
display = PicoGraphics(DISPLAY_PICO_W_EXPLORER, pen_type=PEN_RGB332)
display.set_backlight(0.5)
vector = PicoVector(display)
vector.set_antialiasing(ANTIALIAS_X4)
BLACK = display.create_pen(0, 0, 0)
WHITE = display.create_pen(255, 255, 255)
WIDTH, HEIGHT = display.get_bounds()
def bake_radial_graph(ox, oy, radius, thickness, resolution=45):
outer_points = []
inner_points = []
angle_per_point = math.radians(360.0 / resolution)
outer = radius
inner = radius - thickness
for x in range(resolution):
a = angle_per_point * x
s = math.cos(a)
c = math.sin(a)
in_x = int(c * inner) + ox
out_x = int(c * outer) + ox
in_y = int(s * inner) + oy
out_y = int(s * outer) + oy
outer_points.append((out_x, out_y))
inner_points.insert(0, (in_x, in_y))
return outer_points, inner_points
a = 2
d = 1
outer_points, inner_points = bake_radial_graph(int(WIDTH / 2), int(HEIGHT / 2), 120, 20)
num_points = len(outer_points)
angle = 0
while True:
display.set_pen(BLACK)
display.clear()
display.set_pen(WHITE)
inner_start = inner_points[0]
outer_start = outer_points[-1]
for hue in range(1, a):
points = [inner_start, inner_points[hue], outer_points[-(hue + 1)], outer_start]
inner_start = inner_points[hue]
outer_start = outer_points[-(hue + 1)]
display.set_pen(display.create_pen_hsv(hue / num_points, 1.0, 1.0))
p = Polygon(*points)
vector.rotate(p, angle, int(WIDTH / 2), int(HEIGHT / 2))
vector.draw(p)
display.update()
a += d
if a >= num_points:
d = -1
if a <= 2:
d = 1
angle += 8 |
I'm grappling with a very strange bug relating to rotating polygons immediately after drawing some unrelated polygons. This seems to be fixed by either using the spread operator to unpack a tuple of polygons to draw, or by inserting a small (1ms) delay before rotation. It feels like something is clobbering the matrix transform for rotation but it's being stubborn to pin down- import gc
import time
from picographics import PicoGraphics, DISPLAY_PICO_W_EXPLORER, PEN_RGB332
from picovector import PicoVector, Polygon, Rectangle, ANTIALIAS_NONE
display = PicoGraphics(DISPLAY_PICO_W_EXPLORER, pen_type=PEN_RGB332)
display.set_backlight(0.5)
vector = PicoVector(display)
vector.set_antialiasing(ANTIALIAS_NONE)
BLACK = display.create_pen(0, 0, 0)
WHITE = display.create_pen(255, 255, 255)
WIDTH, HEIGHT = display.get_bounds()
poly_list = [Rectangle(10, 85, 60, 60), Rectangle(250, 85, 60, 60)]
while True:
display.set_pen(BLACK)
vector.draw(Rectangle(0, 0, 320, 240), Rectangle(60, 60, 200, 120)) # Breaks
#vector.draw(*(Rectangle(0, 0, 320, 240), Rectangle(60, 60, 200, 120))) # Works
#time.sleep_ms(1) # Works if I add a 1ms sleep here
for p in poly_list:
vector.rotate(p, 8, int(WIDTH / 2), int(HEIGHT / 2))
display.set_pen(WHITE)
vector.draw(*poly_list)
display.update() |
6d56e37
to
c443f8d
Compare
d9522c5
to
231ceb7
Compare
PicoVector, based upon Pretty Poly, lays the groundwork for Alright Fonts, a vector-based font library that will eventually replace our Hershey font implementation. More details here: https://github.com/lowfatcode/alright-fonts
It also gives us a nice(er) polygon renderer, which couldn't hurt.
The aim here is to make PicoVector a library - like PNG or JPEG - which takes a PicoGraphics instance and offers some additional functionality. In the case of PicoVector that will be a set of vector primitives, helpers and so forth.
todo
gc.collect()
appears to stop this. Need to figure out exactly where some memory is allocated, in-use, but not reachable when GC walks the pointers.