summaryrefslogtreecommitdiff
path: root/shared-module/vectorio
diff options
context:
space:
mode:
authorScott Shawcroft <scott@adafruit.com>2020-05-18 14:37:05 -0700
committerGitHub <noreply@github.com>2020-05-18 14:37:05 -0700
commit2e950a059cf732ebdeb8bb77251aaef79e4ef8c4 (patch)
tree2f5fcd0c75e7eee72c0c4f2310a70760d269c647 /shared-module/vectorio
parent2314f988b180615439635ec30e81f80085724c2f (diff)
parenta78f245ea649c2bf67e2748d068b531b352cc4aa (diff)
Merge pull request #2888 from WarriorOfWire/vectorio-polygon-speed
vectorio: speed up polygon
Diffstat (limited to 'shared-module/vectorio')
-rw-r--r--shared-module/vectorio/Polygon.c75
-rw-r--r--shared-module/vectorio/Polygon.h5
2 files changed, 59 insertions, 21 deletions
diff --git a/shared-module/vectorio/Polygon.c b/shared-module/vectorio/Polygon.c
index 6722912c2..aadf47911 100644
--- a/shared-module/vectorio/Polygon.c
+++ b/shared-module/vectorio/Polygon.c
@@ -4,6 +4,8 @@
#include "shared-module/displayio/area.h"
#include "py/runtime.h"
+#include "py/gc.h"
+
#include "stdlib.h"
#include <stdio.h>
@@ -12,10 +14,53 @@
// #define VECTORIO_POLYGON_DEBUG(...) mp_printf(&mp_plat_print __VA_OPT__(,) __VA_ARGS__)
+// Converts a list of points tuples to a flat list of ints for speedier internal use.
+// Also validates the points.
+static void _clobber_points_list(vectorio_polygon_t *self, mp_obj_t points_tuple_list) {
+ size_t len = 0;
+ mp_obj_t *items;
+ mp_obj_list_get(points_tuple_list, &len, &items);
+ VECTORIO_POLYGON_DEBUG("polygon_points_list len: %d\n", len);
+
+ if ( len < 3 ) {
+ mp_raise_TypeError_varg(translate("Polygon needs at least 3 points"));
+ }
+
+ if ( self->len < 2*len ) {
+ if ( self->points_list != NULL ) {
+ gc_free( self->points_list );
+ }
+ self->points_list = gc_alloc( 2 * len * sizeof(int), false, false );
+ }
+ self->len = 2*len;
+
+ for ( size_t i = 0; i < len; ++i) {
+ size_t tuple_len = 0;
+ mp_obj_t *tuple_items;
+ mp_obj_tuple_get(items[i], &tuple_len, &tuple_items);
+
+ if (tuple_len != 2) {
+ mp_raise_ValueError_varg(translate("%q must be a tuple of length 2"), MP_QSTR_point);
+ }
+ if ( !mp_obj_get_int_maybe(tuple_items[ 0 ], &self->points_list[2*i ])
+ || !mp_obj_get_int_maybe(tuple_items[ 1 ], &self->points_list[2*i + 1])
+ ) {
+ self->len = 0;
+ gc_free( self->points_list );
+ self->points_list = NULL;
+ mp_raise_ValueError_varg(translate("unsupported %q type"), MP_QSTR_point);
+ }
+ }
+}
+
+
+
void common_hal_vectorio_polygon_construct(vectorio_polygon_t *self, mp_obj_t points_list) {
VECTORIO_POLYGON_DEBUG("%p polygon_construct\n", self);
- self->points_list = points_list;
+ self->points_list = NULL;
+ self->len = 0;
self->on_dirty.obj = NULL;
+ _clobber_points_list( self, points_list );
}
@@ -23,7 +68,7 @@ mp_obj_t common_hal_vectorio_polygon_get_points(vectorio_polygon_t *self) {
return self->points_list;
}
void common_hal_vectorio_polygon_set_points(vectorio_polygon_t *self, mp_obj_t points_list) {
- self->points_list = points_list;
+ _clobber_points_list( self, points_list );
if (self->on_dirty.obj != NULL) {
self->on_dirty.event(self->on_dirty.obj);
}
@@ -38,21 +83,16 @@ void common_hal_vectorio_polygon_set_on_dirty(vectorio_polygon_t *self, vectorio
void common_hal_vectorio_polygon_get_area(void *polygon, displayio_area_t *area) {
- VECTORIO_POLYGON_DEBUG("%p polygon get_area", polygon);
vectorio_polygon_t *self = polygon;
- size_t len;
- mp_obj_t *points;
- mp_obj_list_get(self->points_list, &len, &points);
- VECTORIO_POLYGON_DEBUG(" len: %2d, points: %d\n", len, len/2);
area->x1 = SHRT_MAX;
area->y1 = SHRT_MAX;
area->x2 = SHRT_MIN;
area->y2 = SHRT_MIN;
- for (size_t i=0; i < len; ++i) {
- mp_int_t x = mp_obj_get_int(points[i]);
+ for (size_t i=0; i < self->len; ++i) {
+ int x = self->points_list[i];
++i;
- mp_int_t y = mp_obj_get_int(points[i]);
+ int y = self->points_list[i];
if (x <= area->x1) area->x1 = x-1;
if (y <= area->y1) area->y1 = y-1;
if (x >= area->x2) area->x2 = x+1;
@@ -73,22 +113,19 @@ __attribute__((always_inline)) static inline int line_side( mp_int_t x1, mp_int_
uint32_t common_hal_vectorio_polygon_get_pixel(void *obj, int16_t x, int16_t y) {
VECTORIO_POLYGON_DEBUG("%p polygon get_pixel %d, %d\n", obj, x, y);
vectorio_polygon_t *self = obj;
- size_t len;
- mp_obj_t *points;
- mp_obj_list_get(self->points_list, &len, &points);
- if (len == 0) {
+ if (self->len == 0) {
return 0;
}
int winding_number = 0;
- mp_int_t x1 = mp_obj_get_int(points[0]);
- mp_int_t y1 = mp_obj_get_int(points[1]);
- for (size_t i=2; i <= len + 1; ++i) {
+ int x1 = self->points_list[0];
+ int y1 = self->points_list[1];
+ for (size_t i=2; i <= self->len + 1; ++i) {
VECTORIO_POLYGON_DEBUG(" {(%3d, %3d),", x1, y1);
- mp_int_t x2 = mp_obj_get_int(points[i % len]);
+ int x2 = self->points_list[i % self->len];
++i;
- mp_int_t y2 = mp_obj_get_int(points[i % len]);
+ int y2 = self->points_list[i % self->len];
VECTORIO_POLYGON_DEBUG(" (%3d, %3d)}\n", x2, y2);
if ( y1 <= y ) {
if ( y2 > y && line_side(x1, y1, x2, y2, x, y) > 0 ) {
diff --git a/shared-module/vectorio/Polygon.h b/shared-module/vectorio/Polygon.h
index 1aef854a7..70de9036d 100644
--- a/shared-module/vectorio/Polygon.h
+++ b/shared-module/vectorio/Polygon.h
@@ -8,8 +8,9 @@
typedef struct {
mp_obj_base_t base;
- // A micropython List[ x, y, ... ]
- mp_obj_t points_list;
+ // An int array[ x, y, ... ]
+ int *points_list;
+ size_t len;
vectorio_event_t on_dirty;
} vectorio_polygon_t;