From c9a8d5ef491339e3221ac4865c623894871ba1ce Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Tue, 8 Aug 2023 17:06:40 +0100 Subject: [PATCH] PicoVector: Move polygon drawing to a new home. --- micropython/modules/micropython-common.cmake | 1 + .../modules/micropython-tufty2040.cmake | 1 + .../modules/picographics/picographics.c | 2 - .../modules/picographics/picographics.cpp | 52 ------- .../modules/picographics/picographics.h | 1 - .../modules/picovector/micropython.cmake | 16 +++ micropython/modules/picovector/picovector.c | 48 +++++++ micropython/modules/picovector/picovector.cpp | 129 ++++++++++++++++++ micropython/modules/picovector/picovector.h | 9 ++ 9 files changed, 204 insertions(+), 55 deletions(-) create mode 100644 micropython/modules/picovector/micropython.cmake create mode 100644 micropython/modules/picovector/picovector.c create mode 100644 micropython/modules/picovector/picovector.cpp create mode 100644 micropython/modules/picovector/picovector.h diff --git a/micropython/modules/micropython-common.cmake b/micropython/modules/micropython-common.cmake index e6f82633..7ad640ea 100644 --- a/micropython/modules/micropython-common.cmake +++ b/micropython/modules/micropython-common.cmake @@ -10,6 +10,7 @@ include(picographics/micropython) # Pico Graphics Extra include(pngdec/micropython) include(jpegdec/micropython) +include(picovector/micropython) include(qrcode/micropython/micropython) # Sensors & Breakouts diff --git a/micropython/modules/micropython-tufty2040.cmake b/micropython/modules/micropython-tufty2040.cmake index 475db55f..11f28bc0 100644 --- a/micropython/modules/micropython-tufty2040.cmake +++ b/micropython/modules/micropython-tufty2040.cmake @@ -14,6 +14,7 @@ include(pimoroni_bus/micropython) # Pico Graphics Essential include(hershey_fonts/micropython) include(bitmap_fonts/micropython) +include(picovector/micropython) include(picographics/micropython) # Pico Graphics Extra diff --git a/micropython/modules/picographics/picographics.c b/micropython/modules/picographics/picographics.c index e223b851..01c58763 100644 --- a/micropython/modules/picographics/picographics.c +++ b/micropython/modules/picographics/picographics.c @@ -36,7 +36,6 @@ MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_character_obj, 1, ModPicoGraphics_cha MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_text_obj, 1, ModPicoGraphics_text); MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_measure_text_obj, 1, ModPicoGraphics_measure_text); MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_polygon_obj, 2, ModPicoGraphics_polygon); -MP_DEFINE_CONST_FUN_OBJ_KW(ModPicoGraphics_pretty_polygon_obj, 2, ModPicoGraphics_pretty_polygon); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_triangle_obj, 7, 7, ModPicoGraphics_triangle); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(ModPicoGraphics_line_obj, 5, 6, ModPicoGraphics_line); @@ -73,7 +72,6 @@ STATIC const mp_rom_map_elem_t ModPicoGraphics_locals_dict_table[] = { { MP_ROM_QSTR(MP_QSTR_text), MP_ROM_PTR(&ModPicoGraphics_text_obj) }, { MP_ROM_QSTR(MP_QSTR_measure_text), MP_ROM_PTR(&ModPicoGraphics_measure_text_obj) }, { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&ModPicoGraphics_polygon_obj) }, - { MP_ROM_QSTR(MP_QSTR_pretty_polygon), MP_ROM_PTR(&ModPicoGraphics_pretty_polygon_obj) }, { MP_ROM_QSTR(MP_QSTR_triangle), MP_ROM_PTR(&ModPicoGraphics_triangle_obj) }, { MP_ROM_QSTR(MP_QSTR_line), MP_ROM_PTR(&ModPicoGraphics_line_obj) }, diff --git a/micropython/modules/picographics/picographics.cpp b/micropython/modules/picographics/picographics.cpp index 189235fa..3c8a791a 100644 --- a/micropython/modules/picographics/picographics.cpp +++ b/micropython/modules/picographics/picographics.cpp @@ -1022,58 +1022,6 @@ mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, m return mp_obj_new_int(width); } -/* -pretty_polygon(( - (0, 0), - (0, 0) -), ( - -), ( - -)) -*/ - -mp_obj_t ModPicoGraphics_pretty_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { - size_t num_tuples = n_args - 1; - const mp_obj_t *lists = pos_args + 1; - - ModPicoGraphics_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], ModPicoGraphics_obj_t); - - std::vector> contours; - - for(auto i = 0u; i < num_tuples; i++) { - mp_obj_t c_obj = lists[i]; - - if(!mp_obj_is_exact_type(c_obj, &mp_type_list)) mp_raise_ValueError("Not a list"); - - mp_obj_list_t *t_contour = MP_OBJ_TO_PTR2(c_obj, mp_obj_list_t); - - pretty_poly::point_t *points = new pretty_poly::point_t[t_contour->len]; - - for(auto p = 0u; p < t_contour->len; p++) { - mp_obj_t p_obj = t_contour->items[p]; - - if(!mp_obj_is_exact_type(p_obj, &mp_type_tuple)) mp_raise_ValueError("Not a tuple"); - - mp_obj_tuple_t *t_point = MP_OBJ_TO_PTR2(p_obj, mp_obj_tuple_t); - points[p] = { - mp_obj_get_int(t_point->items[0]), - mp_obj_get_int(t_point->items[1]), - }; - } - - contours.push_back({points, t_contour->len}); - } - - self->graphics->polygon(contours); - - for(auto contour : contours) { - delete contour.points; - } - - return mp_const_none; -} - mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { size_t num_tuples = n_args - 1; const mp_obj_t *tuples = pos_args + 1; diff --git a/micropython/modules/picographics/picographics.h b/micropython/modules/picographics/picographics.h index 167b6e02..2503cbbf 100644 --- a/micropython/modules/picographics/picographics.h +++ b/micropython/modules/picographics/picographics.h @@ -93,7 +93,6 @@ extern mp_obj_t ModPicoGraphics_character(size_t n_args, const mp_obj_t *pos_arg extern mp_obj_t ModPicoGraphics_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t ModPicoGraphics_measure_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t ModPicoGraphics_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); -extern mp_obj_t ModPicoGraphics_pretty_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); extern mp_obj_t ModPicoGraphics_triangle(size_t n_args, const mp_obj_t *args); extern mp_obj_t ModPicoGraphics_line(size_t n_args, const mp_obj_t *args); diff --git a/micropython/modules/picovector/micropython.cmake b/micropython/modules/picovector/micropython.cmake new file mode 100644 index 00000000..5c054921 --- /dev/null +++ b/micropython/modules/picovector/micropython.cmake @@ -0,0 +1,16 @@ +add_library(usermod_picovector INTERFACE) + +target_sources(usermod_picovector INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/picovector.c + ${CMAKE_CURRENT_LIST_DIR}/picovector.cpp +) + +target_include_directories(usermod_picovector INTERFACE + ${CMAKE_CURRENT_LIST_DIR} +) + +target_compile_definitions(usermod_picovector INTERFACE + MODULE_PICOVECTOR_ENABLED=1 +) + +target_link_libraries(usermod INTERFACE usermod_picovector) diff --git a/micropython/modules/picovector/picovector.c b/micropython/modules/picovector/picovector.c new file mode 100644 index 00000000..a716c737 --- /dev/null +++ b/micropython/modules/picovector/picovector.c @@ -0,0 +1,48 @@ +#include "picovector.h" + +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(VECTOR_polygon_obj, 2, VECTOR_polygon); +STATIC MP_DEFINE_CONST_FUN_OBJ_KW(VECTOR_regular_polygon_obj, 6, VECTOR_regular_polygon); + +// class +STATIC const mp_rom_map_elem_t VECTOR_locals_dict_table[] = { + { MP_ROM_QSTR(MP_QSTR_polygon), MP_ROM_PTR(&VECTOR_polygon_obj) }, + { MP_ROM_QSTR(MP_QSTR_regular_polygon), MP_ROM_PTR(&VECTOR_regular_polygon_obj) }, +}; + +STATIC MP_DEFINE_CONST_DICT(VECTOR_locals_dict, VECTOR_locals_dict_table); + +#ifdef MP_DEFINE_CONST_OBJ_TYPE +MP_DEFINE_CONST_OBJ_TYPE( + VECTOR_type, + MP_QSTR_picovector, + MP_TYPE_FLAG_NONE, + make_new, VECTOR_make_new, + locals_dict, (mp_obj_dict_t*)&VECTOR_locals_dict +); +#else +const mp_obj_type_t VECTOR_type = { + { &mp_type_type }, + .name = MP_QSTR_picovector, + .make_new = VECTOR_make_new, + .locals_dict = (mp_obj_dict_t*)&VECTOR_locals_dict, +}; +#endif + +// module +STATIC const mp_map_elem_t VECTOR_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_picovector) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_PicoVector), (mp_obj_t)&VECTOR_type }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_VECTOR_globals, VECTOR_globals_table); + +const mp_obj_module_t VECTOR_user_cmodule = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_VECTOR_globals, +}; + +#if MICROPY_VERSION <= 70144 +MP_REGISTER_MODULE(MP_QSTR_picovector, VECTOR_user_cmodule, MODULE_PICOVECTOR_ENABLED); +#else +MP_REGISTER_MODULE(MP_QSTR_picovector, VECTOR_user_cmodule); +#endif \ No newline at end of file diff --git a/micropython/modules/picovector/picovector.cpp b/micropython/modules/picovector/picovector.cpp new file mode 100644 index 00000000..eace364c --- /dev/null +++ b/micropython/modules/picovector/picovector.cpp @@ -0,0 +1,129 @@ +#include "micropython/modules/util.hpp" +#include "libraries/pico_graphics/pico_graphics.hpp" + +using namespace pimoroni; + +extern "C" { +#include "picovector.h" +#include "micropython/modules/picographics/picographics.h" +#include "py/stream.h" +#include "py/reader.h" +#include "extmod/vfs.h" + +typedef struct _ModPicoGraphics_obj_t { + mp_obj_base_t base; + PicoGraphics *graphics; + DisplayDriver *display; + void *buffer; +} ModPicoGraphics_obj_t; + +typedef struct _VECTOR_obj_t { + mp_obj_base_t base; + ModPicoGraphics_obj_t *graphics; +} _VECTOR_obj_t; + +mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) { + enum { + ARG_picographics + }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_picographics, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!MP_OBJ_IS_TYPE(args[ARG_picographics].u_obj, &ModPicoGraphics_type)) mp_raise_ValueError(MP_ERROR_TEXT("PicoGraphics Object Required")); + + _VECTOR_obj_t *self = m_new_obj(_VECTOR_obj_t); + self->base.type = &VECTOR_type; + self->graphics = (ModPicoGraphics_obj_t *)MP_OBJ_TO_PTR(args[ARG_picographics].u_obj); + + return self; +} + +mp_obj_t VECTOR_regular_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + enum { ARG_self, ARG_x, ARG_y, ARG_sides, ARG_radius, ARG_rotation }; + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_sides, MP_ARG_REQUIRED | MP_ARG_INT }, + { MP_QSTR_radius, MP_ARG_REQUIRED | MP_ARG_OBJ }, + { MP_QSTR_rotation, MP_ARG_REQUIRED | MP_ARG_OBJ }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + _VECTOR_obj_t *self = MP_OBJ_TO_PTR2(args[ARG_self].u_obj, _VECTOR_obj_t); + + Point origin(args[ARG_x].u_int, args[ARG_y].u_int); + unsigned int sides = args[ARG_sides].u_int; + float radius = mp_obj_get_float(args[ARG_radius].u_obj); + float rotation = mp_obj_get_float(args[ARG_rotation].u_obj); + int o_x = args[ARG_x].u_int; + int o_y = args[ARG_y].u_int; + + float angle = (360.0f / sides) * (M_PI / 180.0f); + + pretty_poly::point_t *points = new pretty_poly::point_t[sides]; + + for(auto s = 0u; s < sides; s++) { + float current_angle = angle * s + rotation; + points[s] = { + int(cos(current_angle) * radius + o_x), + int(sin(current_angle) * radius + o_y) + }; + } + + std::vector> contours; + contours.push_back({points, sides}); + self->graphics->graphics->polygon(contours); + + delete points; + + return mp_const_none; +} + +mp_obj_t VECTOR_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + size_t num_tuples = n_args - 1; + const mp_obj_t *lists = pos_args + 1; + + _VECTOR_obj_t *self = MP_OBJ_TO_PTR2(pos_args[0], _VECTOR_obj_t); + + std::vector> contours; + + for(auto i = 0u; i < num_tuples; i++) { + mp_obj_t c_obj = lists[i]; + + if(!mp_obj_is_exact_type(c_obj, &mp_type_list)) mp_raise_ValueError("Not a list"); + + mp_obj_list_t *t_contour = MP_OBJ_TO_PTR2(c_obj, mp_obj_list_t); + + pretty_poly::point_t *points = new pretty_poly::point_t[t_contour->len]; + + for(auto p = 0u; p < t_contour->len; p++) { + mp_obj_t p_obj = t_contour->items[p]; + + if(!mp_obj_is_exact_type(p_obj, &mp_type_tuple)) mp_raise_ValueError("Not a tuple"); + + mp_obj_tuple_t *t_point = MP_OBJ_TO_PTR2(p_obj, mp_obj_tuple_t); + points[p] = { + mp_obj_get_int(t_point->items[0]), + mp_obj_get_int(t_point->items[1]), + }; + } + + contours.push_back({points, t_contour->len}); + } + + self->graphics->graphics->polygon(contours); + + for(auto contour : contours) { + delete contour.points; + } + + return mp_const_none; +} + +} diff --git a/micropython/modules/picovector/picovector.h b/micropython/modules/picovector/picovector.h new file mode 100644 index 00000000..436196c5 --- /dev/null +++ b/micropython/modules/picovector/picovector.h @@ -0,0 +1,9 @@ +#include "py/runtime.h" +#include "py/objstr.h" + +extern const mp_obj_type_t VECTOR_type; + +extern mp_obj_t VECTOR_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args); + +extern mp_obj_t VECTOR_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); +extern mp_obj_t VECTOR_regular_polygon(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args); \ No newline at end of file