Skip to content

Instantly share code, notes, and snippets.

@FoamyGuy
Created August 7, 2021 17:26
Show Gist options
  • Save FoamyGuy/8fe27cdec0dc0febad754c186090a5da to your computer and use it in GitHub Desktop.
Save FoamyGuy/8fe27cdec0dc0febad754c186090a5da to your computer and use it in GitHub Desktop.
"""
Gauge
Turning the arc function into a guage that starts at angle 315 degrees
and sweeps 270 degrees
"""
import math
import displayio
class Gauge(displayio.TileGrid):
def __init__(self, xcenter, ycenter, radius, width, progress, lineColor, progressColor, backgroundColor):
self.xcenter = xcenter
self.ycenter = ycenter
self.radius = radius
self.width = width
self._progress = progress
tileGridWidth = 2 * self.radius + 1
tileGridHeight = math.ceil(0.71 * self.radius) + self.radius + 1
self._bitmap = displayio.Bitmap(tileGridWidth, tileGridHeight, 3)
self._palette = displayio.Palette(3)
self._palette[0] = backgroundColor
self._palette[1] = lineColor
self._palette[2] = progressColor
x_offset = self.xcenter - self.radius + 1
y_offset = self.ycenter - self.radius + 1
super().__init__(
self._bitmap, pixel_shader=self._palette, x=x_offset, y=y_offset
)
self._draw_progress()
def _boundaryFill4(self, px, py, fc,
bc): # px & py = x, y coord to start fill, fc = fill color, bc = background color
fillArea = [[px, py]]
while len(fillArea) > 0:
x, y = fillArea.pop()
if self._bitmap[x, y] != bc:
continue
self._bitmap[x, y] = fc
fillArea.append((x + 1, y))
fillArea.append((x - 1, y))
fillArea.append((x, y + 1))
fillArea.append((x, y - 1))
def _bLine(self, x0, y0, x1, y1, color): # function to draw a line
if x0 == x1:
if y0 > y1:
y0, y1 = y1, y0
for h in range(y0, y1 + 1):
self._bitmap[x0, h] = color
elif y0 == y1:
if x0 > x1:
x0, x1 = x1, x0
for w in range(x0, x1 + 1):
self._bitmap[w, y0] = color
else:
steep = abs(y1 - y0) > abs(x1 - x0)
if steep:
x0, y0 = y0, x0
x1, y1 = y1, x1
if x0 > x1:
x0, x1 = x1, x0
y0, y1 = y1, y0
dx = x1 - x0
dy = abs(y1 - y0)
err = dx / 2
if y0 < y1:
ystep = 1
else:
ystep = -1
for x in range(x0, x1 + 1):
if steep:
self._bitmap[y0, x] = color
else:
self._bitmap[x, y0] = color
err -= dy
if err < 0:
y0 += ystep
err += dx
def _draw_progress(self):
# empty the bitmap
self._bitmap.fill(0)
x = 0
y = self.radius
d = 3 - 2 * self.radius
# Bresenham's circle algorithm
# Outer arc
while x <= y:
self._bitmap[-x + self.radius, -y + self.radius] = 1
self._bitmap[x + self.radius, -y + self.radius] = 1
self._bitmap[y + self.radius, x + self.radius] = 1
self._bitmap[-y + self.radius, x + self.radius] = 1
self._bitmap[-y + self.radius, -x + self.radius] = 1
self._bitmap[y + self.radius, -x + self.radius] = 1
if d <= 0:
d = d + (4 * x) + 6
else:
d = d + 4 * (x - y) + 10
y = y - 1
x = x + 1
self.yend = self.xend = x - 1
# Inner Arc
x = 0
y = self.radius - self.width + 1
d = 3 - 2 * (y)
while x <= y:
self._bitmap[-x + self.radius, -y + self.radius] = 1
self._bitmap[x + self.radius, -y + self.radius] = 1
self._bitmap[y + self.radius, x + self.radius] = 1
self._bitmap[-y + self.radius, x + self.radius] = 1
self._bitmap[-y + self.radius, -x + self.radius] = 1
self._bitmap[y + self.radius, -x + self.radius] = 1
if d <= 0:
d = d + (4 * x) + 6
else:
d = d + 4 * (x - y) + 10
y = y - 1
x = x + 1
self.yend2 = self.xend2 = x - 1
# Connect inner and outer arc at endpoints
x = self.xend
for y in range(self.yend, self.yend2 - 1, -1):
self._bitmap[self.radius - x, self.radius + y] = 1
self._bitmap[self.radius + x, self.radius + y] = 1
x -= 1
# Color in progress
print("drawing progress: {}".format(self.progress))
# Find progress point
prog = 315 - (self.progress * 270 / 100) # what percent of gauge in degrees to fill in
xs = self.radius + int(round(math.sin(math.radians(prog)) * (self.radius - 1), 0))
ys = self.radius + int(round(math.cos(math.radians(prog)) * (self.radius - 1), 0))
xe = self.radius + int(round(math.sin(math.radians(prog)) * (self.radius - self.width + 2), 0))
ye = self.radius + int(round(math.cos(math.radians(prog)) * (self.radius - self.width + 2), 0))
print("{}, {}, {}, {}".format(xs, ys, xe, ye))
if self.progress == 0: # Just draw the gauge
return
# Draw end line for progress value
if self.progress != 100: # @ 100%, no need to draw end line
self._bLine(xs, ys, xe, ye, 2)
# Find a point just above the 0% progress line as a start point for the boundary fill
x = self.radius - ((int((self.xend - self.xend2) / 2) + 1) + self.xend2)
y = self.radius + ((int((self.yend - self.yend2) / 2) - 1) + self.yend2)
print("{}, {}".format(x, y))
self._boundaryFill4(x, y, 2, 0)
@property
def progress(self):
return self._progress
@progress.setter
def progress(self, new_progress):
print("updating progress")
self._progress = new_progress
self._draw_progress()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment