diff --git a/shared-bindings/vectorio/Circle.c b/shared-bindings/vectorio/Circle.c index 43845937c4..9711c53e0d 100644 --- a/shared-bindings/vectorio/Circle.c +++ b/shared-bindings/vectorio/Circle.c @@ -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) }, diff --git a/shared-bindings/vectorio/Polygon.c b/shared-bindings/vectorio/Polygon.c index d1078b2d2d..dfe50ffd01 100644 --- a/shared-bindings/vectorio/Polygon.c +++ b/shared-bindings/vectorio/Polygon.c @@ -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) }, diff --git a/shared-bindings/vectorio/Rectangle.c b/shared-bindings/vectorio/Rectangle.c index dc7415e0ba..67367eb538 100644 --- a/shared-bindings/vectorio/Rectangle.c +++ b/shared-bindings/vectorio/Rectangle.c @@ -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) }, diff --git a/shared-bindings/vectorio/VectorShape.c b/shared-bindings/vectorio/VectorShape.c index 3f8c105d0e..3293466cc4 100644 --- a/shared-bindings/vectorio/VectorShape.c +++ b/shared-bindings/vectorio/VectorShape.c @@ -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 diff --git a/shared-bindings/vectorio/VectorShape.h b/shared-bindings/vectorio/VectorShape.h index 12c7e628ad..959a38dff0 100644 --- a/shared-bindings/vectorio/VectorShape.h +++ b/shared-bindings/vectorio/VectorShape.h @@ -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 diff --git a/shared-module/vectorio/VectorShape.c b/shared-module/vectorio/VectorShape.c index be14fca5ac..52d3354946 100644 --- a/shared-module/vectorio/VectorShape.c +++ b/shared-module/vectorio/VectorShape.c @@ -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