Skip to content

Commit 8de5f90

Browse files
committed
vectorio contains(x, y)
new utility function for all vectorio shape specializations for testing whether a screen-space x,y point falls within a shape's x,y. This respects the current orientation of the screen in the manner of displayio and vectorio - so your x,y requests are in the same coordinate domain as your x,y locations and your width/height etc. properties that ou set on other shapes. I.e., if you're using this for touch points then you will need to make sure the touch events are in the same x,y domain as your display. ``` contains(2, 4) -> true ------------------ | | | | | -- | | | \ | | |. \ | | | \ | | |____\ | | | ------------------ contains(5, 4) -> false ------------------ | | | | | -- | | | \ | | | \. | | | \ | | |____\ | | | ------------------ ``` This helps provide low overhead introspection of shape coverage on screen. It's envisioned that this will be used for things like touch-and-drag widget controls, touch "areas" and may help with random ornament placement on toy Christmas trees.
1 parent f5fa4ae commit 8de5f90

File tree

6 files changed

+82
-45
lines changed

6 files changed

+82
-45
lines changed

shared-bindings/vectorio/Circle.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ const mp_obj_property_t vectorio_circle_radius_obj = {
9797
//|
9898

9999
STATIC const mp_rom_map_elem_t vectorio_circle_locals_dict_table[] = {
100+
// Functions
101+
{ MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
100102
// Properties
101103
{ MP_ROM_QSTR(MP_QSTR_radius), MP_ROM_PTR(&vectorio_circle_radius_obj) },
102104
{ MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },

shared-bindings/vectorio/Polygon.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ const mp_obj_property_t vectorio_polygon_points_obj = {
103103
//|
104104

105105
STATIC const mp_rom_map_elem_t vectorio_polygon_locals_dict_table[] = {
106+
// Functions
107+
{ MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
106108
// Properties
107109
{ MP_ROM_QSTR(MP_QSTR_points), MP_ROM_PTR(&vectorio_polygon_points_obj) },
108110
{ MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },

shared-bindings/vectorio/Rectangle.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,8 @@ const mp_obj_property_t vectorio_rectangle_height_obj = {
122122
//|
123123

124124
STATIC const mp_rom_map_elem_t vectorio_rectangle_locals_dict_table[] = {
125+
// Functions
126+
{ MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
125127
// Properties
126128
{ MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
127129
{ MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },

shared-bindings/vectorio/VectorShape.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,21 @@ vectorio_draw_protocol_impl_t vectorio_vector_shape_draw_protocol_impl = {
8080
.draw_get_refresh_areas = (draw_get_refresh_areas_fun)vectorio_vector_shape_get_refresh_areas,
8181
};
8282

83+
// Stub checker does not approve of these shared properties.
84+
// x: int
85+
// y: int
86+
// """true if x,y lies inside the shape."""
87+
//
88+
STATIC mp_obj_t vectorio_vector_shape_obj_contains(mp_obj_t wrapper_shape, mp_obj_t x_obj, mp_obj_t y_obj) {
89+
// Relies on the fact that only vector_shape impl gets matched with a VectorShape.
90+
const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
91+
vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
92+
93+
mp_int_t x = mp_obj_get_int(x_obj);
94+
mp_int_t y = mp_obj_get_int(y_obj);
95+
return mp_obj_new_bool(common_hal_vectorio_vector_shape_contains(self, x, y));
96+
}
97+
MP_DEFINE_CONST_FUN_OBJ_3(vectorio_vector_shape_contains_obj, vectorio_vector_shape_obj_contains);
8398

8499
// Stub checker does not approve of these shared properties.
85100
// x: int

shared-bindings/vectorio/VectorShape.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ void common_hal_vectorio_vector_shape_construct(vectorio_vector_shape_t *self,
1818
vectorio_ishape_t ishape,
1919
mp_obj_t pixel_shader, int32_t x, int32_t y);
2020

21+
bool common_hal_vectorio_vector_shape_contains(vectorio_vector_shape_t *self, mp_int_t x, mp_int_t y);
22+
2123
void common_hal_vectorio_vector_shape_set_dirty(void *self);
2224

2325
mp_int_t common_hal_vectorio_vector_shape_get_x(vectorio_vector_shape_t *self);
@@ -40,5 +42,6 @@ extern const mp_obj_property_t vectorio_vector_shape_x_obj;
4042
extern const mp_obj_property_t vectorio_vector_shape_y_obj;
4143
extern const mp_obj_property_t vectorio_vector_shape_location_obj;
4244
extern const mp_obj_property_t vectorio_vector_shape_pixel_shader_obj;
45+
extern const mp_obj_fun_builtin_fixed_t vectorio_vector_shape_contains_obj;
4346

4447
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H

shared-module/vectorio/VectorShape.c

Lines changed: 58 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,12 @@ static uint32_t min(uint32_t a, uint32_t b) {
7272
return a < b ? a : b;
7373
}
7474

75+
static void short_bound_check(mp_int_t i, qstr name) {
76+
if (i < SHRT_MIN || i > SHRT_MAX) {
77+
mp_raise_ValueError_varg(translate("%q must be between %d and %d"), name, SHRT_MIN, SHRT_MAX);
78+
}
79+
}
80+
7581
inline __attribute__((always_inline))
7682
static void area_transpose(displayio_area_t *to_transpose) {
7783
int16_t swap = to_transpose->y1;
@@ -124,21 +130,50 @@ static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *ou
124130
VECTORIO_SHAPE_DEBUG(" out:{(%5d,%5d), (%5d,%5d)}\n", out_area->x1, out_area->y1, out_area->x2, out_area->y2);
125131
}
126132

133+
// Get the target pixel based on the shape's coordinate space
134+
static void screen_to_shape_coordinates(vectorio_vector_shape_t *self, uint16_t x, uint16_t y, int16_t *out_shape_x, int16_t *out_shape_y) {
135+
if (self->absolute_transform->transpose_xy) {
136+
*out_shape_x = y - self->absolute_transform->y - self->absolute_transform->dy * self->x;
137+
*out_shape_y = x - self->absolute_transform->x - self->absolute_transform->dx * self->y;
127138

128-
STATIC
129-
void check_bounds_and_set_x(vectorio_vector_shape_t *self, mp_int_t x) {
130-
if (x < SHRT_MIN || x > SHRT_MAX) {
131-
mp_raise_ValueError_varg(translate("%q must be between %d and %d"), MP_QSTR_x, SHRT_MIN, SHRT_MAX);
139+
VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", *out_shape_x, *out_shape_y);
140+
if (self->absolute_transform->dx < 1) {
141+
*out_shape_y *= -1;
142+
}
143+
if (self->absolute_transform->dy < 1) {
144+
*out_shape_x *= -1;
145+
}
146+
VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", *out_shape_x, *out_shape_y);
147+
} else {
148+
*out_shape_x = x - self->absolute_transform->x - self->absolute_transform->dx * self->x;
149+
*out_shape_y = y - self->absolute_transform->y - self->absolute_transform->dy * self->y;
150+
151+
VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", *out_shape_x, *out_shape_y);
152+
if (self->absolute_transform->dx < 1) {
153+
*out_shape_x *= -1;
154+
}
155+
if (self->absolute_transform->dy < 1) {
156+
*out_shape_y *= -1;
157+
}
158+
VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", *out_shape_x, *out_shape_y);
159+
160+
// It's mirrored via dx. Maybe we need to add support for also separately mirroring?
161+
// if (self->absolute_transform->mirror_x) {
162+
// pixel_to_get_x = (shape_area.x2 - shape_area.x1) - (pixel_to_get_x - shape_area.x1) + shape_area.x1 - 1;
163+
// }
164+
// if (self->absolute_transform->mirror_y) {
165+
// pixel_to_get_y = (shape_area.y2 - shape_area.y1) - (pixel_to_get_y - shape_area.y1) + +shape_area.y1 - 1;
166+
// }
132167
}
133-
self->x = x;
134168
}
135169

170+
static void check_bounds_and_set_x(vectorio_vector_shape_t *self, mp_int_t x) {
171+
short_bound_check(x, MP_QSTR_x);
172+
self->x = x;
173+
}
136174

137-
STATIC
138-
void check_bounds_and_set_y(vectorio_vector_shape_t *self, mp_int_t y) {
139-
if (y < SHRT_MIN || y > SHRT_MAX) {
140-
mp_raise_ValueError_varg(translate("%q must be between %d and %d"), MP_QSTR_y, SHRT_MIN, SHRT_MAX);
141-
}
175+
static void check_bounds_and_set_y(vectorio_vector_shape_t *self, mp_int_t y) {
176+
short_bound_check(y, MP_QSTR_y);
142177
self->y = y;
143178
}
144179

@@ -195,6 +230,17 @@ void common_hal_vectorio_vector_shape_construct(vectorio_vector_shape_t *self,
195230
_get_screen_area(self, &self->current_area);
196231
}
197232

233+
bool common_hal_vectorio_vector_shape_contains(vectorio_vector_shape_t *self, mp_int_t x, mp_int_t y) {
234+
VECTORIO_SHAPE_DEBUG("%p contains(%d, %d)", self);
235+
short_bound_check(x, MP_QSTR_x);
236+
short_bound_check(y, MP_QSTR_y);
237+
int16_t shape_x;
238+
int16_t shape_y;
239+
screen_to_shape_coordinates(self, x, y, &shape_x, &shape_y);
240+
bool shape_contains_coordinates = 0 != self->ishape.get_pixel(self->ishape.shape, shape_x, shape_y);
241+
return shape_contains_coordinates;
242+
}
243+
198244

199245
mp_int_t common_hal_vectorio_vector_shape_get_x(vectorio_vector_shape_t *self) {
200246
VECTORIO_SHAPE_DEBUG("%p get_x\n", self);
@@ -277,7 +323,6 @@ void common_hal_vectorio_vector_shape_set_pixel_shader(vectorio_vector_shape_t *
277323
common_hal_vectorio_vector_shape_set_dirty(self);
278324
}
279325

280-
281326
bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displayio_colorspace_t *colorspace, const displayio_area_t *area, uint32_t *mask, uint32_t *buffer) {
282327
// Shape areas are relative to 0,0. This will allow rotation about a known axis.
283328
// The consequence is that the area reported by the shape itself is _relative_ to 0,0.
@@ -335,42 +380,10 @@ bool vectorio_vector_shape_fill_area(vectorio_vector_shape_t *self, const _displ
335380
}
336381
output_pixel.pixel = 0;
337382

338-
// Get the target pixel based on the shape's coordinate space
383+
// Cast input screen coordinates to shape coordinates to pick the pixel to draw
339384
int16_t pixel_to_get_x;
340385
int16_t pixel_to_get_y;
341-
if (self->absolute_transform->transpose_xy) {
342-
pixel_to_get_x = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->x;
343-
pixel_to_get_y = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->y;
344-
345-
VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y);
346-
if (self->absolute_transform->dx < 1) {
347-
pixel_to_get_y *= -1;
348-
}
349-
if (self->absolute_transform->dy < 1) {
350-
pixel_to_get_x *= -1;
351-
}
352-
VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", pixel_to_get_x, pixel_to_get_y);
353-
} else {
354-
pixel_to_get_x = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->x;
355-
pixel_to_get_y = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->y;
356-
357-
VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y);
358-
if (self->absolute_transform->dx < 1) {
359-
pixel_to_get_x *= -1;
360-
}
361-
if (self->absolute_transform->dy < 1) {
362-
pixel_to_get_y *= -1;
363-
}
364-
VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", pixel_to_get_x, pixel_to_get_y);
365-
366-
// It's mirrored via dx. Maybe we need to add support for also separately mirroring?
367-
// if (self->absolute_transform->mirror_x) {
368-
// pixel_to_get_x = (shape_area.x2 - shape_area.x1) - (pixel_to_get_x - shape_area.x1) + shape_area.x1 - 1;
369-
// }
370-
// if (self->absolute_transform->mirror_y) {
371-
// pixel_to_get_y = (shape_area.y2 - shape_area.y1) - (pixel_to_get_y - shape_area.y1) + +shape_area.y1 - 1;
372-
// }
373-
}
386+
screen_to_shape_coordinates(self, input_pixel.x, input_pixel.y, &pixel_to_get_x, &pixel_to_get_y);
374387

375388
VECTORIO_SHAPE_PIXEL_DEBUG(" get_pixel %p (%3d, %3d) -> ( %3d, %3d )", self->ishape.shape, input_pixel.x, input_pixel.y, pixel_to_get_x, pixel_to_get_y);
376389
#ifdef VECTORIO_PERF

0 commit comments

Comments
 (0)