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.
This commit is contained in:
parent
f5fa4ae237
commit
8de5f90086
|
@ -97,6 +97,8 @@ const mp_obj_property_t vectorio_circle_radius_obj = {
|
|||
//|
|
||||
|
||||
STATIC const mp_rom_map_elem_t vectorio_circle_locals_dict_table[] = {
|
||||
// Functions
|
||||
{ MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
|
||||
// Properties
|
||||
{ MP_ROM_QSTR(MP_QSTR_radius), MP_ROM_PTR(&vectorio_circle_radius_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
|
||||
|
|
|
@ -103,6 +103,8 @@ const mp_obj_property_t vectorio_polygon_points_obj = {
|
|||
//|
|
||||
|
||||
STATIC const mp_rom_map_elem_t vectorio_polygon_locals_dict_table[] = {
|
||||
// Functions
|
||||
{ MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
|
||||
// Properties
|
||||
{ MP_ROM_QSTR(MP_QSTR_points), MP_ROM_PTR(&vectorio_polygon_points_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
|
||||
|
|
|
@ -122,6 +122,8 @@ const mp_obj_property_t vectorio_rectangle_height_obj = {
|
|||
//|
|
||||
|
||||
STATIC const mp_rom_map_elem_t vectorio_rectangle_locals_dict_table[] = {
|
||||
// Functions
|
||||
{ MP_ROM_QSTR(MP_QSTR_contains), MP_ROM_PTR(&vectorio_vector_shape_contains_obj) },
|
||||
// Properties
|
||||
{ MP_ROM_QSTR(MP_QSTR_x), MP_ROM_PTR(&vectorio_vector_shape_x_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_y), MP_ROM_PTR(&vectorio_vector_shape_y_obj) },
|
||||
|
|
|
@ -80,6 +80,21 @@ vectorio_draw_protocol_impl_t vectorio_vector_shape_draw_protocol_impl = {
|
|||
.draw_get_refresh_areas = (draw_get_refresh_areas_fun)vectorio_vector_shape_get_refresh_areas,
|
||||
};
|
||||
|
||||
// Stub checker does not approve of these shared properties.
|
||||
// x: int
|
||||
// y: int
|
||||
// """true if x,y lies inside the shape."""
|
||||
//
|
||||
STATIC mp_obj_t vectorio_vector_shape_obj_contains(mp_obj_t wrapper_shape, mp_obj_t x_obj, mp_obj_t y_obj) {
|
||||
// Relies on the fact that only vector_shape impl gets matched with a VectorShape.
|
||||
const vectorio_draw_protocol_t *draw_protocol = mp_proto_get(MP_QSTR_protocol_draw, wrapper_shape);
|
||||
vectorio_vector_shape_t *self = MP_OBJ_TO_PTR(draw_protocol->draw_get_protocol_self(wrapper_shape));
|
||||
|
||||
mp_int_t x = mp_obj_get_int(x_obj);
|
||||
mp_int_t y = mp_obj_get_int(y_obj);
|
||||
return mp_obj_new_bool(common_hal_vectorio_vector_shape_contains(self, x, y));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_3(vectorio_vector_shape_contains_obj, vectorio_vector_shape_obj_contains);
|
||||
|
||||
// Stub checker does not approve of these shared properties.
|
||||
// x: int
|
||||
|
|
|
@ -18,6 +18,8 @@ void common_hal_vectorio_vector_shape_construct(vectorio_vector_shape_t *self,
|
|||
vectorio_ishape_t ishape,
|
||||
mp_obj_t pixel_shader, int32_t x, int32_t y);
|
||||
|
||||
bool common_hal_vectorio_vector_shape_contains(vectorio_vector_shape_t *self, mp_int_t x, mp_int_t y);
|
||||
|
||||
void common_hal_vectorio_vector_shape_set_dirty(void *self);
|
||||
|
||||
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;
|
|||
extern const mp_obj_property_t vectorio_vector_shape_y_obj;
|
||||
extern const mp_obj_property_t vectorio_vector_shape_location_obj;
|
||||
extern const mp_obj_property_t vectorio_vector_shape_pixel_shader_obj;
|
||||
extern const mp_obj_fun_builtin_fixed_t vectorio_vector_shape_contains_obj;
|
||||
|
||||
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_VECTORIO_SHAPE_H
|
||||
|
|
|
@ -72,6 +72,12 @@ static uint32_t min(uint32_t a, uint32_t b) {
|
|||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
static void short_bound_check(mp_int_t i, qstr name) {
|
||||
if (i < SHRT_MIN || i > SHRT_MAX) {
|
||||
mp_raise_ValueError_varg(translate("%q must be between %d and %d"), name, SHRT_MIN, SHRT_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
inline __attribute__((always_inline))
|
||||
static void area_transpose(displayio_area_t *to_transpose) {
|
||||
int16_t swap = to_transpose->y1;
|
||||
|
@ -124,21 +130,50 @@ static void _get_screen_area(vectorio_vector_shape_t *self, displayio_area_t *ou
|
|||
VECTORIO_SHAPE_DEBUG(" out:{(%5d,%5d), (%5d,%5d)}\n", out_area->x1, out_area->y1, out_area->x2, out_area->y2);
|
||||
}
|
||||
|
||||
// Get the target pixel based on the shape's coordinate space
|
||||
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) {
|
||||
if (self->absolute_transform->transpose_xy) {
|
||||
*out_shape_x = y - self->absolute_transform->y - self->absolute_transform->dy * self->x;
|
||||
*out_shape_y = x - self->absolute_transform->x - self->absolute_transform->dx * self->y;
|
||||
|
||||
STATIC
|
||||
void check_bounds_and_set_x(vectorio_vector_shape_t *self, mp_int_t x) {
|
||||
if (x < SHRT_MIN || x > SHRT_MAX) {
|
||||
mp_raise_ValueError_varg(translate("%q must be between %d and %d"), MP_QSTR_x, SHRT_MIN, SHRT_MAX);
|
||||
VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", *out_shape_x, *out_shape_y);
|
||||
if (self->absolute_transform->dx < 1) {
|
||||
*out_shape_y *= -1;
|
||||
}
|
||||
if (self->absolute_transform->dy < 1) {
|
||||
*out_shape_x *= -1;
|
||||
}
|
||||
VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", *out_shape_x, *out_shape_y);
|
||||
} else {
|
||||
*out_shape_x = x - self->absolute_transform->x - self->absolute_transform->dx * self->x;
|
||||
*out_shape_y = y - self->absolute_transform->y - self->absolute_transform->dy * self->y;
|
||||
|
||||
VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", *out_shape_x, *out_shape_y);
|
||||
if (self->absolute_transform->dx < 1) {
|
||||
*out_shape_x *= -1;
|
||||
}
|
||||
if (self->absolute_transform->dy < 1) {
|
||||
*out_shape_y *= -1;
|
||||
}
|
||||
VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", *out_shape_x, *out_shape_y);
|
||||
|
||||
// It's mirrored via dx. Maybe we need to add support for also separately mirroring?
|
||||
// if (self->absolute_transform->mirror_x) {
|
||||
// pixel_to_get_x = (shape_area.x2 - shape_area.x1) - (pixel_to_get_x - shape_area.x1) + shape_area.x1 - 1;
|
||||
// }
|
||||
// if (self->absolute_transform->mirror_y) {
|
||||
// pixel_to_get_y = (shape_area.y2 - shape_area.y1) - (pixel_to_get_y - shape_area.y1) + +shape_area.y1 - 1;
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
static void check_bounds_and_set_x(vectorio_vector_shape_t *self, mp_int_t x) {
|
||||
short_bound_check(x, MP_QSTR_x);
|
||||
self->x = x;
|
||||
}
|
||||
|
||||
|
||||
STATIC
|
||||
void check_bounds_and_set_y(vectorio_vector_shape_t *self, mp_int_t y) {
|
||||
if (y < SHRT_MIN || y > SHRT_MAX) {
|
||||
mp_raise_ValueError_varg(translate("%q must be between %d and %d"), MP_QSTR_y, SHRT_MIN, SHRT_MAX);
|
||||
}
|
||||
static void check_bounds_and_set_y(vectorio_vector_shape_t *self, mp_int_t y) {
|
||||
short_bound_check(y, MP_QSTR_y);
|
||||
self->y = y;
|
||||
}
|
||||
|
||||
|
@ -195,6 +230,17 @@ void common_hal_vectorio_vector_shape_construct(vectorio_vector_shape_t *self,
|
|||
_get_screen_area(self, &self->current_area);
|
||||
}
|
||||
|
||||
bool common_hal_vectorio_vector_shape_contains(vectorio_vector_shape_t *self, mp_int_t x, mp_int_t y) {
|
||||
VECTORIO_SHAPE_DEBUG("%p contains(%d, %d)", self);
|
||||
short_bound_check(x, MP_QSTR_x);
|
||||
short_bound_check(y, MP_QSTR_y);
|
||||
int16_t shape_x;
|
||||
int16_t shape_y;
|
||||
screen_to_shape_coordinates(self, x, y, &shape_x, &shape_y);
|
||||
bool shape_contains_coordinates = 0 != self->ishape.get_pixel(self->ishape.shape, shape_x, shape_y);
|
||||
return shape_contains_coordinates;
|
||||
}
|
||||
|
||||
|
||||
mp_int_t common_hal_vectorio_vector_shape_get_x(vectorio_vector_shape_t *self) {
|
||||
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 *
|
|||
common_hal_vectorio_vector_shape_set_dirty(self);
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
// Shape areas are relative to 0,0. This will allow rotation about a known axis.
|
||||
// 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
|
|||
}
|
||||
output_pixel.pixel = 0;
|
||||
|
||||
// Get the target pixel based on the shape's coordinate space
|
||||
// Cast input screen coordinates to shape coordinates to pick the pixel to draw
|
||||
int16_t pixel_to_get_x;
|
||||
int16_t pixel_to_get_y;
|
||||
if (self->absolute_transform->transpose_xy) {
|
||||
pixel_to_get_x = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->x;
|
||||
pixel_to_get_y = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->y;
|
||||
|
||||
VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y);
|
||||
if (self->absolute_transform->dx < 1) {
|
||||
pixel_to_get_y *= -1;
|
||||
}
|
||||
if (self->absolute_transform->dy < 1) {
|
||||
pixel_to_get_x *= -1;
|
||||
}
|
||||
VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", pixel_to_get_x, pixel_to_get_y);
|
||||
} else {
|
||||
pixel_to_get_x = input_pixel.x - self->absolute_transform->x - self->absolute_transform->dx * self->x;
|
||||
pixel_to_get_y = input_pixel.y - self->absolute_transform->y - self->absolute_transform->dy * self->y;
|
||||
|
||||
VECTORIO_SHAPE_PIXEL_DEBUG(" a(%3d, %3d)", pixel_to_get_x, pixel_to_get_y);
|
||||
if (self->absolute_transform->dx < 1) {
|
||||
pixel_to_get_x *= -1;
|
||||
}
|
||||
if (self->absolute_transform->dy < 1) {
|
||||
pixel_to_get_y *= -1;
|
||||
}
|
||||
VECTORIO_SHAPE_PIXEL_DEBUG(" b(%3d, %3d)", pixel_to_get_x, pixel_to_get_y);
|
||||
|
||||
// It's mirrored via dx. Maybe we need to add support for also separately mirroring?
|
||||
// if (self->absolute_transform->mirror_x) {
|
||||
// pixel_to_get_x = (shape_area.x2 - shape_area.x1) - (pixel_to_get_x - shape_area.x1) + shape_area.x1 - 1;
|
||||
// }
|
||||
// if (self->absolute_transform->mirror_y) {
|
||||
// pixel_to_get_y = (shape_area.y2 - shape_area.y1) - (pixel_to_get_y - shape_area.y1) + +shape_area.y1 - 1;
|
||||
// }
|
||||
}
|
||||
screen_to_shape_coordinates(self, input_pixel.x, input_pixel.y, &pixel_to_get_x, &pixel_to_get_y);
|
||||
|
||||
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);
|
||||
#ifdef VECTORIO_PERF
|
||||
|
|
Loading…
Reference in New Issue