Skip to content

Commit e8e67c0

Browse files
committed
# TODO Make axes, separate from data [X]
# TODO Replace with drawline/vectorio [ ] # TODO Make a rectangle function [ ] # TODO Include functions to equal space ticks [ ] # TODO Make labels and text [ ] # TODO Make Styles applicable [ ] # TODO Animate when overflow [ ]
1 parent 45bd920 commit e8e67c0

File tree

2 files changed

+52
-259
lines changed

2 files changed

+52
-259
lines changed
Lines changed: 0 additions & 208 deletions
Original file line numberDiff line numberDiff line change
@@ -1,208 +0,0 @@
1-
# SPDX-FileCopyrightText: Kevin Matocha
2-
#
3-
# SPDX-License-Identifier: MIT
4-
5-
"""
6-
`adafruit_displayio_layout.widgets`
7-
=======================
8-
"""
9-
10-
import math
11-
12-
# * Copyright (c) 2017 Werner Stoop <wstoop@gmail.com>
13-
# *
14-
# * Permission is hereby granted, free of charge, to any person obtaining a copy
15-
# * of this software and associated documentation files (the "Software"), to deal
16-
# * in the Software without restriction, including without limitation the rights
17-
# * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
18-
# * copies of the Software, and to permit persons to whom the Software is
19-
# * furnished to do so, subject to the following conditions:
20-
# *
21-
# * The above copyright notice and this permission notice shall be included in all
22-
# * copies or substantial portions of the Software.
23-
# *
24-
# * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25-
# * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26-
# * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27-
# * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28-
# * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29-
# * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30-
# * SOFTWARE.
31-
32-
33-
# Credit from https://github.com/wernsey/bitmap
34-
# MIT License from
35-
# * Copyright (c) 2017 Werner Stoop <wstoop@gmail.com>
36-
#
37-
# /**
38-
# * #### `void bm_rotate_blit(Bitmap *dst, int ox, int oy, Bitmap *src, int px,
39-
# * int py, double angle, double scale);`
40-
# *
41-
# * Rotates a source bitmap `src` around a pivot point `px,py` and blits it
42-
# * onto a destination bitmap `dst`.
43-
# *
44-
# * The bitmap is positioned such that the point `px,py` on the source is at
45-
# * the offset `ox,oy` on the destination.
46-
# *
47-
# * The `angle` is clockwise, in radians. The bitmap is also scaled by the
48-
# * factor `scale`.
49-
# */
50-
# void bm_rotate_blit(Bitmap *dst, int ox, int oy, Bitmap *src, int px,
51-
# int py, double angle, double scale);
52-
53-
54-
# /*
55-
# Reference:
56-
# "Fast Bitmap Rotation and Scaling" By Steven Mortimer, Dr Dobbs' Journal, July 01, 2001
57-
# http://www.drdobbs.com/architecture-and-design/fast-bitmap-rotation-and-scaling/184416337
58-
# See also http://www.efg2.com/Lab/ImageProcessing/RotateScanline.htm
59-
# */
60-
# This function is provided in case the bitmaptools.rotozoom function is not available
61-
62-
# pylint: disable=invalid-name, too-many-branches, too-many-statements, too-many-locals
63-
# pylint: disable=too-many-arguments
64-
def _blit_rotate_scale(
65-
destination, # destination bitmap
66-
ox=None,
67-
oy=None, # (ox, oy) is the destination point where the source (px,py) is placed
68-
dest_clip0=None,
69-
dest_clip1=None, # clip0,1 is (x,y) corners of clip window on the destination bitmap
70-
source=None, # source bitmap
71-
px=None,
72-
py=None, # (px, py) is the rotation point of the source bitmap
73-
source_clip0=None,
74-
source_clip1=None, # clip0,1 is (x,y) corners of clip window on the source bitmap
75-
angle=0, # in radians, clockwise
76-
scale=1.0, # scale factor (float)
77-
skip_index=None, # color index to ignore
78-
):
79-
80-
if source is None:
81-
pass
82-
83-
# Check the input limits
84-
85-
if ox is None:
86-
ox = destination.width / 2
87-
if oy is None:
88-
oy = destination.height / 2
89-
if px is None:
90-
px = source.width / 2
91-
if py is None:
92-
py = source.height / 2
93-
94-
if dest_clip0 is None:
95-
dest_clip0 = (0, 0)
96-
if dest_clip1 is None:
97-
dest_clip1 = (destination.width, destination.height)
98-
99-
if source_clip0 is None:
100-
source_clip0 = (0, 0)
101-
if source_clip1 is None:
102-
source_clip1 = (source.width, source.height)
103-
104-
minx = dest_clip1[0]
105-
miny = dest_clip1[1]
106-
maxx = dest_clip0[0]
107-
maxy = dest_clip0[1]
108-
109-
sinAngle = math.sin(angle)
110-
cosAngle = math.cos(angle)
111-
112-
dx = -cosAngle * px * scale + sinAngle * py * scale + ox
113-
dy = -sinAngle * px * scale - cosAngle * py * scale + oy
114-
if dx < minx:
115-
minx = int(round(dx))
116-
if dx > maxx:
117-
maxx = int(round(dx))
118-
if dy < miny:
119-
miny = int(round(dy))
120-
if dy > maxy:
121-
maxy = int(dy)
122-
dx = cosAngle * (source.width - px) * scale + sinAngle * py * scale + ox
123-
dy = sinAngle * (source.width - px) * scale - cosAngle * py * scale + oy
124-
if dx < minx:
125-
minx = int(round(dx))
126-
if dx > maxx:
127-
maxx = int(round(dx))
128-
if dy < miny:
129-
miny = int(round(dy))
130-
if dy > maxy:
131-
maxy = int(round(dy))
132-
133-
dx = (
134-
cosAngle * (source.width - px) * scale
135-
- sinAngle * (source.height - py) * scale
136-
+ ox
137-
)
138-
dy = (
139-
sinAngle * (source.width - px) * scale
140-
+ cosAngle * (source.height - py) * scale
141-
+ oy
142-
)
143-
if dx < minx:
144-
minx = int(round(dx))
145-
if dx > maxx:
146-
maxx = int(round(dx))
147-
if dy < miny:
148-
miny = int(round(dy))
149-
if dy > maxy:
150-
maxy = int(round(dy))
151-
152-
dx = -cosAngle * px * scale - sinAngle * (source.height - py) * scale + ox
153-
dy = -sinAngle * px * scale + cosAngle * (source.height - py) * scale + oy
154-
if dx < minx:
155-
minx = int(round(dx))
156-
if dx > maxx:
157-
maxx = int(round(dx))
158-
if dy < miny:
159-
miny = int(round(dy))
160-
if dy > maxy:
161-
maxy = int(round(dy))
162-
163-
# /* Clipping */
164-
if minx < dest_clip0[0]:
165-
minx = dest_clip0[0]
166-
if maxx > dest_clip1[0] - 1:
167-
maxx = dest_clip1[0] - 1
168-
if miny < dest_clip0[1]:
169-
miny = dest_clip0[1]
170-
if maxy > dest_clip1[1] - 1:
171-
maxy = dest_clip1[1] - 1
172-
173-
dvCol = math.cos(angle) / scale
174-
duCol = math.sin(angle) / scale
175-
176-
duRow = dvCol
177-
dvRow = -duCol
178-
179-
startu = px - (ox * dvCol + oy * duCol)
180-
startv = py - (ox * dvRow + oy * duRow)
181-
182-
rowu = startu + miny * duCol
183-
rowv = startv + miny * dvCol
184-
185-
for y in range(miny, maxy + 1): # (y = miny, y <= maxy, y++)
186-
u = rowu + minx * duRow
187-
v = rowv + minx * dvRow
188-
for x in range(minx, maxx + 1): # (x = minx, x <= maxx, x++)
189-
if (source_clip0[0] <= u < source_clip1[0]) and (
190-
source_clip0[1] <= v < source_clip1[1]
191-
):
192-
# get the pixel color (c) from the source bitmap at (u,v)
193-
c = source[
194-
int(u) + source.width * int(v)
195-
] # direct index into bitmap is faster than tuple
196-
# c = source[int(u), int(v)]
197-
198-
if c != skip_index: # ignore any pixels with skip_index
199-
# place the pixel color (c) into the destination bitmap at (x,y)
200-
destination[
201-
x + y * destination.width
202-
] = c # direct index into bitmap is faster than tuple
203-
# destination[x,y] = c
204-
u += duRow
205-
v += dvRow
206-
207-
rowu += duCol
208-
rowv += dvCol

adafruit_displayio_layout/widgets/cartesian.py

Lines changed: 52 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
import board
3030
import terminalio
3131
from adafruit_displayio_layout.widgets.widget import Widget
32-
from adafruit_displayio_layout.widgets import _blit_rotate_scale
3332
import vectorio
3433

3534
try:
@@ -80,6 +79,13 @@ def __init__(
8079
pointer_color: int = 0xFFFFFF,
8180
**kwargs,
8281
) -> None:
82+
# TODO Make axes, separate from data [X]
83+
# TODO Replace with drawline/vectorio [ ]
84+
# TODO Make a rectangle function [ ]
85+
# TODO Include functions to equal space ticks [ ]
86+
# TODO Make labels and text [ ]
87+
# TODO Make Styles applicable [ ]
88+
# TODO Animate when overflow [ ]
8389

8490
super().__init__(**kwargs, max_size=3)
8591
self._origin_x = x
@@ -116,15 +122,23 @@ def __init__(
116122
)
117123
self._tick_bitmap.fill(1)
118124

119-
self._axesx_bitmap = displayio.Bitmap(
120-
self._axes_line_thickness, self._usable_height, 3
125+
axesx_height = (
126+
2
127+
+ self._axes_line_thickness
128+
+ self._font_height
129+
+ self._tick_line_height // 2
121130
)
122-
self._axesx_bitmap.fill(2)
123-
124-
self._axesy_bitmap = displayio.Bitmap(
125-
self._usable_width, self._axes_line_thickness, 3
131+
self._axesx_bitmap = displayio.Bitmap(self._usable_width, axesx_height, 4)
132+
self._axesx_bitmap.fill(0)
133+
134+
self._axesy_width = (
135+
2
136+
+ self._axes_line_thickness
137+
+ self._font_height
138+
+ self._tick_line_height // 2
126139
)
127-
self._axesy_bitmap.fill(2)
140+
self._axesy_bitmap = displayio.Bitmap(self._axesy_width, self._usable_height, 4)
141+
self._axesy_bitmap.fill(0)
128142

129143
self._screen_bitmap = displayio.Bitmap(
130144
self._usable_width, self._usable_height, 3
@@ -134,10 +148,24 @@ def __init__(
134148
self._screen_palette.make_transparent(0)
135149
self._screen_palette[1] = self._tick_color
136150
self._screen_palette[2] = self._axes_line_color
137-
self._screen_palette[3] = 0x00FFFF
151+
self._screen_palette[3] = 0x990099
138152
self._screen_palette[4] = 0xFFFFFF
139153
self._screen_palette[5] = self._display_color
140154

155+
self._axesx_tilegrid = displayio.TileGrid(
156+
self._axesx_bitmap,
157+
pixel_shader=self._screen_palette,
158+
x=self._origin_x,
159+
y=self._origin_y + self._usable_height,
160+
)
161+
162+
self._axesy_tilegrid = displayio.TileGrid(
163+
self._axesy_bitmap,
164+
pixel_shader=self._screen_palette,
165+
x=self._origin_x - self._axesy_width,
166+
y=self._origin_y,
167+
)
168+
141169
self._screen_tilegrid = displayio.TileGrid(
142170
self._screen_bitmap,
143171
pixel_shader=self._screen_palette,
@@ -149,6 +177,8 @@ def __init__(
149177
self._draw_ticks()
150178
self._draw_pointers()
151179
self.append(self._pointer_vector_shape)
180+
self.append(self._axesx_tilegrid)
181+
self.append(self._axesy_tilegrid)
152182
self.append(self._screen_tilegrid)
153183

154184
@staticmethod
@@ -162,24 +192,15 @@ def _get_font_height(font, scale):
162192
return font_width, font_height
163193

164194
def _draw_axes(self):
165-
bitmaptools.rotozoom(
166-
self._screen_bitmap,
167-
ox=self._margin,
168-
oy=self._usable_height,
169-
source_bitmap=self._axesx_bitmap,
170-
px=self._axesx_bitmap.width,
171-
py=self._axesx_bitmap.height,
172-
angle=0.0, # in radians
173-
)
174-
175-
bitmaptools.rotozoom(
176-
self._screen_bitmap,
177-
ox=int(self._usable_width + self._margin),
178-
oy=self._usable_height,
179-
source_bitmap=self._axesy_bitmap,
180-
px=self._axesy_bitmap.width,
181-
py=self._axesy_bitmap.height,
182-
angle=0.0,
195+
y = self._tick_line_height // 2
196+
bitmaptools.draw_line(self._axesx_bitmap, 0, y, self._usable_width - 1, y, 3)
197+
bitmaptools.draw_line(
198+
self._axesy_bitmap,
199+
self._axesy_width - 1,
200+
0,
201+
self._axesy_width - 1,
202+
self._usable_height - 1,
203+
3,
183204
)
184205

185206
def _draw_ticks(self):
@@ -188,19 +209,9 @@ def _draw_ticks(self):
188209
bitmaptools.rotozoom(
189210
self._screen_bitmap,
190211
ox=i,
191-
oy=self._usable_height,
212+
oy=self._usable_height + self._tick_line_height // 2,
192213
source_bitmap=self._tick_bitmap,
193-
px=int(self._tick_bitmap.width / 2),
194-
py=self._tick_bitmap.height,
195-
angle=0.0, # in radians
196-
)
197-
else:
198-
_blit_rotate_scale( # translate and rotate the tick into the target_bitmap
199-
destination=self._screen_bitmap,
200-
ox=i,
201-
oy=0,
202-
source=self._tick_bitmap,
203-
px=int(self._tick_bitmap / 2),
214+
px=int(self._tick_bitmap.width),
204215
py=self._tick_bitmap.height,
205216
angle=0.0, # in radians
206217
)
@@ -209,20 +220,10 @@ def _draw_ticks(self):
209220
if "rotozoom" in dir(bitmaptools): # if core function is available
210221
bitmaptools.rotozoom(
211222
self._screen_bitmap,
212-
ox=self._margin,
223+
ox=0,
213224
oy=i,
214225
source_bitmap=self._tick_bitmap,
215-
px=int(self._tick_bitmap.width / 2),
216-
py=int(self._tick_bitmap.height / 2),
217-
angle=(90 * math.pi / 180), # in radians
218-
)
219-
else:
220-
_blit_rotate_scale( # translate and rotate the tick into the target_bitmap
221-
destination=self._screen_bitmap,
222-
ox=i,
223-
oy=0,
224-
source=self._tick_bitmap,
225-
px=int(self._tick_bitmap.width / 2),
226+
px=int(self._tick_bitmap.width),
226227
py=int(self._tick_bitmap.height / 2),
227228
angle=(90 * math.pi / 180), # in radians
228229
)

0 commit comments

Comments
 (0)