[python] merge '6fcab395' and fix a bug in fill_polygon()

This commit is contained in:
Laury
2021-08-30 19:38:40 +02:00
18 changed files with 236 additions and 3 deletions

View File

@@ -45,15 +45,19 @@ PythonCosh = "Hyperbolic cosine"
PythonCount = "Zählt wie oft x vorkommt"
PythonDegrees = "x von Radian zu Grad umwandeln"
PythonDivMod = "Quotient und Rest"
PythonDrawLine = "Draw a line"
PythonDrawCircle = "Zeichne einen Kreis"
PythonDrawLine = "Zeichnen einer Linie"
PythonDrawString = "Schreibt Text bei (x,y)"
PythonErf = "Fehlerfunktion"
PythonErfc = "Complementary error function"
PythonEval = "Return the evaluated expression"
PythonErf = "Fehlerfunktion"
PythonExp = "Exponentialfunktion"
PythonExpm1 = "Berechne exp(x)-1"
PythonFabs = "Absoluter Wert"
PythonFillRect = "Malt ein Rechteck bei Pixel (x,y)"
PythonFillCircle = "Füllt einen Kreis"
PythonFillPolygon = "Füllt ein Polygon"
PythonFloat = "Wandelt x zu float um"
PythonFloor = "Floor"
PythonFmod = "a modulo b"

View File

@@ -45,6 +45,7 @@ PythonCosh = "Hyperbolic cosine"
PythonCount = "Count the occurrences of x"
PythonDegrees = "Convert x from radians to degrees"
PythonDivMod = "Quotient and remainder"
PythonDrawCircle = "Draw a circle"
PythonDrawLine = "Draw a line"
PythonDrawString = "Display a text from pixel (x,y)"
PythonErf = "Error function"
@@ -53,6 +54,8 @@ PythonEval = "Return the evaluated expression"
PythonExp = "Exponential function"
PythonExpm1 = "Compute exp(x)-1"
PythonFabs = "Absolute value"
PythonFillCircle = "Fill a circle"
PythonFillPolygon = "Fill a polygon"
PythonFillRect = "Fill a rectangle at pixel (x,y)"
PythonFloat = "Convert x to a float"
PythonFloor = "Floor"

View File

@@ -45,6 +45,7 @@ PythonCosh = "Hyperbolic cosine"
PythonCount = "Count the occurrences of x"
PythonDegrees = "Convert x from radians to degrees"
PythonDivMod = "Quotient and remainder"
PythonDrawCircle = "Draw a circle"
PythonDrawLine = "Draw a line"
PythonDrawString = "Display a text from pixel (x,y)"
PythonErf = "Error function"
@@ -53,6 +54,8 @@ PythonEval = "Return the evaluated expression"
PythonExp = "Exponential function"
PythonExpm1 = "Compute exp(x)-1"
PythonFabs = "Absolute value"
PythonFillCircle = "Fill a circle"
PythonFillPolygon = "Fill a polygon"
PythonFillRect = "Fill a rectangle at pixel (x,y)"
PythonFloat = "Convert x to a float"
PythonFloor = "Floor"

View File

@@ -45,6 +45,7 @@ PythonCosh = "Cosinus hyperbolique"
PythonCount = "Compte les occurrences de x"
PythonDegrees = "Conversion de radians en degrés"
PythonDivMod = "Quotient et reste"
PythonDrawCircle = "Trace un cercle"
PythonDrawLine = "Trace une ligne"
PythonDrawString = "Affiche un texte au pixel (x,y)"
PythonErf = "Fonction d'erreur"
@@ -53,6 +54,8 @@ PythonEval = "Evalue l'expression en argument "
PythonExp = "Fonction exponentielle"
PythonExpm1 = "Calcul de exp(x)-1"
PythonFabs = "Valeur absolue"
PythonFillCircle = "Remplit un cercle"
PythonFillPolygon = "Remplit un polygone"
PythonFillRect = "Remplit un rectangle"
PythonFloat = "Conversion en flottant"
PythonFloor = "Partie entière"

View File

@@ -45,6 +45,7 @@ PythonCosh = "Hiperbolikus koszinusz"
PythonCount = "Számolja az x elöfordulását"
PythonDegrees = "x konvertálása radiánokrol fokokra"
PythonDivMod = "Hányados és maradék"
PythonDrawCircle = "Rajzolj egy kört"
PythonDrawLine = "Húzzon egy vonalat "
PythonDrawString = "Szöveg megjelenítése (x, y)-en"
PythonErf = "Hiba funkció"
@@ -54,6 +55,8 @@ PythonExp = "Exponenciális függvény"
PythonExpm1 = "exp(x)-1 sámitása"
PythonFabs = "Abszolút érték"
PythonFillRect = "Téglalap töltése"
PythonFillCircle = "Kitölti a kört"
PythonFillPolygon = "Kitölti a poligont"
PythonFloat = "Konvertálása tizedes számra"
PythonFloor = "Egész része"
PythonFmod = "a modulo b"

View File

@@ -45,6 +45,7 @@ PythonCosh = "Coseno iperbolico"
PythonCount = "Conta le ricorrenze di x"
PythonDegrees = "Conversione di radianti in gradi"
PythonDivMod = "Quoziente e resto"
PythonDrawCircle = "Disegnare un cerchio"
PythonDrawLine = "Disegna una linea"
PythonDrawString = "Visualizza il testo dal pixel x,y"
PythonErf = "Funzione d'errore"
@@ -53,6 +54,8 @@ PythonEval = "Valuta l'espressione nell'argomento "
PythonExp = "Funzione esponenziale"
PythonExpm1 = "Calcola exp(x)-1"
PythonFabs = "Valore assoluto"
PythonFillCircle = "Riempire un cerchio"
PythonFillPolygon = "Riempire un poligono"
PythonFillRect = "Riempie un rettangolo"
PythonFloat = "Conversione in flottanti"
PythonFloor = "Parte intera"

View File

@@ -45,6 +45,7 @@ PythonCosh = "Cosinus hyperbolicus"
PythonCount = "Tel voorkomen van x"
PythonDegrees = "Zet x om van radialen naar graden"
PythonDivMod = "Quotiënt en rest"
PythonDrawCircle = "Teken een cirkel"
PythonDrawLine = "Teken een lijn"
PythonDrawString = "Geef een tekst weer van pixel (x,y)"
PythonErf = "Error functie"
@@ -53,6 +54,8 @@ PythonEval = "Geef de geëvalueerde uitdrukking"
PythonExp = "Exponentiële functie"
PythonExpm1 = "Bereken exp(x)-1"
PythonFabs = "Absolute waarde"
PythonFillCircle = "Vul een cirkel"
PythonFillPolygon = "Vul een veelhoek"
PythonFillRect = "Vul een rechthoek bij pixel (x,y)"
PythonFloat = "Zet x om in een float"
PythonFloor = "Vloer"

View File

@@ -45,6 +45,7 @@ PythonCosh = "Cosseno hiperbólico"
PythonCount = "Contar as ocorrências de x"
PythonDegrees = "Converter x de radianos para graus"
PythonDivMod = "Quociente e resto"
PythonDrawCircle = "Desenha um círculo"
PythonDrawLine = "Desenhe uma linha"
PythonDrawString = "Mostrar o texto do pixel (x,y)"
PythonErf = "Função erro"
@@ -53,6 +54,8 @@ PythonEval = "Devolve a expressão avaliada"
PythonExp = "Função exponencial"
PythonExpm1 = "Calcular exp(x)-1"
PythonFabs = "Valor absoluto"
PythonFillCircle = "Preencher um círculo"
PythonFillPolygon = "Preencher um polígono"
PythonFillRect = "Preencher um retângulo em (x,y)"
PythonFloat = "Converter x num flutuante"
PythonFloor = "Parte inteira"

View File

@@ -50,6 +50,7 @@ PythonCommandCount = "list.count(x)"
PythonCommandCountWithoutArg = ".count(\x11)"
PythonCommandDegrees = "degrees(x)"
PythonCommandDivMod = "divmod(a,b)"
PythonCommandDrawCircle = "draw_circle(x,y,r,color)"
PythonCommandDrawLine = "draw_line(x1,y1,x2,y2,color)"
PythonCommandDrawString = "draw_string(\"text\",x,y)"
PythonCommandConstantE = "e"
@@ -60,6 +61,8 @@ PythonCommandExp = "exp(x)"
PythonCommandExpComplex = "exp(z)"
PythonCommandExpm1 = "expm1(x)"
PythonCommandFabs = "fabs(x)"
PythonCommandFillCircle = "fill_circle(x,y,r,color)"
PythonCommandFillPolygon = "fill_polygon([(x1,y1),...],color)"
PythonCommandFillRect = "fill_rect(x,y,width,height,color)"
PythonCommandFloat = "float(x)"
PythonCommandFloor = "floor(x)"

View File

@@ -194,7 +194,10 @@ const ToolboxMessageTree KandinskyModuleChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColor, I18n::Message::PythonColor),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawLine, I18n::Message::PythonDrawLine),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect)
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawCircle, I18n::Message::PythonDrawCircle),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillCircle, I18n::Message::PythonFillCircle),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillPolygon, I18n::Message::PythonFillPolygon)
};
const ToolboxMessageTree IonModuleChildren[] = {
@@ -272,6 +275,7 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandCosh, I18n::Message::PythonCosh),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDegrees, I18n::Message::PythonDegrees),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDivMod, I18n::Message::PythonDivMod),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawCircle, I18n::Message::PythonDrawCircle),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawLine, I18n::Message::PythonDrawLine),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandDrawString, I18n::Message::PythonDrawString),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandConstantE, I18n::Message::PythonConstantE, false),
@@ -281,6 +285,8 @@ const ToolboxMessageTree catalogChildren[] = {
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandExp, I18n::Message::PythonExp),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandExpm1, I18n::Message::PythonExpm1),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFabs, I18n::Message::PythonFabs),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillCircle, I18n::Message::PythonFillCircle),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillPolygon, I18n::Message::PythonFillPolygon),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFillRect, I18n::Message::PythonFillRect),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFloat, I18n::Message::PythonFloat),
ToolboxMessageTree::Leaf(I18n::Message::PythonCommandFloor, I18n::Message::PythonFloor),

View File

@@ -3,8 +3,10 @@ SFLAGS += -Ikandinsky/include
kandinsky_src += $(addprefix kandinsky/src/,\
color.cpp \
context.cpp \
context_circle.cpp \
context_line.cpp \
context_pixel.cpp \
context_polygon.cpp \
context_rect.cpp \
context_text.cpp \
font.cpp \

View File

@@ -28,6 +28,10 @@ public:
// Line. Not anti-aliased.
void drawLine(KDPoint p1, KDPoint p2, KDColor c);
// Circle
void drawCircle(KDPoint c, KDCoordinate r, KDColor color);
void fillCircle(KDPoint c, KDCoordinate r, KDColor color);
// Rect
void fillRect(KDRect rect, KDColor color);
void fillRectWithPixels(KDRect rect, const KDColor * pixels, KDColor * workingBuffer);
@@ -36,6 +40,10 @@ public:
virtual void pushRect(KDRect, const KDColor * pixels) = 0;
virtual void pushRectUniform(KDRect rect, KDColor color) = 0;
virtual void pullRect(KDRect rect, KDColor * pixels) = 0;
//Polygon
static const int k_polygonMaxNumberOfPoints = 32;
void fillPolygon(KDCoordinate pointsX[], KDCoordinate pointsY[], int numberOfPoints, KDColor color);
protected:
KDContext(KDPoint origin, KDRect clippingRect);
private:

View File

@@ -0,0 +1,49 @@
#include <kandinsky/context.h>
#include <assert.h>
#include <math.h>
void KDContext::drawCircle(KDPoint c, KDCoordinate r, KDColor color) {
//The used algorithm is the Bresenham's arc tracing algorithm
KDCoordinate x, y, m;
x = 0;
y = r;
m = 5 - 4*r;
while(x <= y) {
setPixel(c.translatedBy(KDPoint(x,y)), color);
setPixel(c.translatedBy(KDPoint(y,x)), color);
setPixel(c.translatedBy(KDPoint(-x,y)), color);
setPixel(c.translatedBy(KDPoint(-y,x)), color);
setPixel(c.translatedBy(KDPoint(x,-y)), color);
setPixel(c.translatedBy(KDPoint(y,-x)), color);
setPixel(c.translatedBy(KDPoint(-x,-y)), color);
setPixel(c.translatedBy(KDPoint(-y,-x)), color);
if(m > 0) {
y = y - 1;
m = m - 8*y;
}
x = x + 1;
m = m + 8*x + 4;
}
}
void KDContext::fillCircle(KDPoint c, KDCoordinate r, KDColor color) {
KDCoordinate left = c.x()-r;
KDCoordinate right = c.x()+r;
if(left < 0) {
left = 0;
}
if(right > m_clippingRect.width()) {
right = m_clippingRect.width();
}
for(KDCoordinate x=left; x<=right; x++) {
KDCoordinate semiHeight = sqrt((r*r)-((c.x()-x)*(c.x()-x)));
fillRect(KDRect(x, c.y()-semiHeight, 1, semiHeight * 2 ), color);
}
}

View File

@@ -0,0 +1,67 @@
#include <kandinsky/context.h>
#include <assert.h>
#include <math.h>
void KDContext::fillPolygon(KDCoordinate pointsX[], KDCoordinate pointsY[], int numberOfPoints, KDColor color)
{
//The used algorithm is the scan-line algorithm
KDCoordinate top = KDCOORDINATE_MAX;
KDCoordinate bottom = KDCOORDINATE_MIN;
KDCoordinate right = m_clippingRect.width();
KDCoordinate left = 0;
for (int i = 0; i < numberOfPoints; i++) {
if (pointsY[i] < top) {
top = pointsY[i];
}
if (pointsY[i] > bottom) {
bottom = pointsY[i];
}
}
if (top < 0) {
top = 0;
}
if (bottom > m_clippingRect.height()) {
bottom = m_clippingRect.height();
}
for (int y=top; y<=bottom; y++) {
int switches=0;
KDCoordinate switchesX[KDContext::k_polygonMaxNumberOfPoints];
int lastPointIndex = numberOfPoints-1;
for (int i=0; i<numberOfPoints; i++) {
if (((pointsY[i]<=y && pointsY[lastPointIndex]>=y) || (pointsY[lastPointIndex]<= y && pointsY[i]>=y)) && pointsY[i] != pointsY[lastPointIndex]) {
switchesX[switches++] = (int) round(pointsX[i]+1.0*(y-pointsY[i])/(pointsY[lastPointIndex]-pointsY[i])*(pointsX[lastPointIndex]-pointsX[i]));
}
lastPointIndex=i;
}
//Sorting switches by a bubble sort
int i=0;
while (i<switches-1) {
if (switchesX[i]>switchesX[i+1]) {
KDCoordinate temp = switchesX[i];
switchesX[i]=switchesX[i+1];
switchesX[i+1]=temp;
if (i) i--;
}
else {
i++;
}
}
for (i=0; i<switches; i+=2) {
if (switchesX[i]>=right) {
break;
}
if (switchesX[i+1]>left) {
fillRect( KDRect( switchesX[ i ] , y, switchesX[ i+1 ] - switchesX[ i ], 1 ), color ) ;
}
}
}
}

View File

@@ -375,7 +375,10 @@ Q(kandinsky)
Q(color)
Q(draw_line)
Q(draw_string)
Q(draw_circle)
Q(fill_rect)
Q(fill_circle)
Q(fill_polygon)
Q(get_pixel)
Q(set_pixel)
Q(large_font)

View File

@@ -80,6 +80,21 @@ mp_obj_t modkandinsky_draw_line(size_t n_args, const mp_obj_t * args) {
return mp_const_none;
}
mp_obj_t modkandinsky_draw_circle(size_t n_args, const mp_obj_t * args) {
mp_int_t cx = mp_obj_get_int(args[0]);
mp_int_t cy = mp_obj_get_int(args[1]);
mp_int_t r = mp_obj_get_int(args[2]);
if(r<0)
{
r = -r;
}
KDPoint center = KDPoint(cx, cy);
KDColor color = MicroPython::Color::Parse(args[3]);
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
KDIonContext::sharedContext()->drawCircle(center, r, color);
return mp_const_none;
}
mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t * args) {
mp_int_t x = mp_obj_get_int(args[0]);
mp_int_t y = mp_obj_get_int(args[1]);
@@ -100,6 +115,52 @@ mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t * args) {
return mp_const_none;
}
mp_obj_t modkandinsky_fill_circle(size_t n_args, const mp_obj_t * args) {
mp_int_t cx = mp_obj_get_int(args[0]);
mp_int_t cy = mp_obj_get_int(args[1]);
mp_int_t r = mp_obj_get_int(args[2]);
if(r<0)
{
r = -r;
}
KDPoint center = KDPoint(cx, cy);
KDColor color = MicroPython::Color::Parse(args[3]);
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
KDIonContext::sharedContext()->fillCircle(center, r, color);
return mp_const_none;
}
mp_obj_t modkandinsky_fill_polygon(size_t n_args, const mp_obj_t * args) {
KDCoordinate pointsX[KDContext::k_polygonMaxNumberOfPoints];
KDCoordinate pointsY[KDContext::k_polygonMaxNumberOfPoints];
size_t itemLength;
mp_obj_t * items;
mp_obj_get_array(args[0], &itemLength, &items);
if (itemLength < 3) {
mp_raise_ValueError("polygon must have at least 3 points");
}
else if (itemLength > KDContext::k_polygonMaxNumberOfPoints) {
mp_raise_ValueError("polygon is defined by too many points");
}
for(unsigned int i=0; i<itemLength; i++)
{
mp_obj_t * coordinates;
mp_obj_get_array_fixed_n(items[i], 2, &coordinates);
pointsX[i] = mp_obj_get_int(coordinates[0]);
pointsY[i] = mp_obj_get_int(coordinates[1]);
}
KDColor color = MicroPython::Color::Parse(args[1]);
MicroPython::ExecutionEnvironment::currentExecutionEnvironment()->displaySandbox();
KDIonContext::sharedContext()->fillPolygon(pointsX, pointsY, itemLength, color);
return mp_const_none;
}
mp_obj_t modkandinsky_wait_vblank() {
micropython_port_interrupt_if_needed();
Ion::Display::waitForVBlank();

View File

@@ -5,6 +5,9 @@ mp_obj_t modkandinsky_get_pixel(mp_obj_t x, mp_obj_t y);
mp_obj_t modkandinsky_set_pixel(mp_obj_t x, mp_obj_t y, mp_obj_t color);
mp_obj_t modkandinsky_draw_string(size_t n_args, const mp_obj_t *args);
mp_obj_t modkandinsky_draw_line(size_t n_args, const mp_obj_t *args);
mp_obj_t modkandinsky_draw_circle(size_t n_args, const mp_obj_t *args);
mp_obj_t modkandinsky_fill_rect(size_t n_args, const mp_obj_t *args);
mp_obj_t modkandinsky_fill_circle(size_t n_args, const mp_obj_t *args);
mp_obj_t modkandinsky_fill_polygon(size_t n_args, const mp_obj_t *args);
mp_obj_t modkandinsky_wait_vblank();
mp_obj_t modkandinsky_get_keys();

View File

@@ -3,9 +3,12 @@
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_color_obj, 1, 3, modkandinsky_color);
STATIC MP_DEFINE_CONST_FUN_OBJ_2(modkandinsky_get_pixel_obj, modkandinsky_get_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_3(modkandinsky_set_pixel_obj, modkandinsky_set_pixel);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_draw_string_obj, 3, 6, modkandinsky_draw_string);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_draw_string_obj, 3, 5, modkandinsky_draw_string);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_draw_line_obj, 5, 5, modkandinsky_draw_line);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_draw_circle_obj, 4, 4, modkandinsky_draw_circle);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_fill_rect_obj, 5, 5, modkandinsky_fill_rect);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_fill_circle_obj, 4, 4, modkandinsky_fill_circle);
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(modkandinsky_fill_polygon_obj, 2, 2, modkandinsky_fill_polygon);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modkandinsky_wait_vblank_obj, modkandinsky_wait_vblank);
STATIC MP_DEFINE_CONST_FUN_OBJ_0(modkandinsky_get_keys_obj, modkandinsky_get_keys);
@@ -16,7 +19,10 @@ STATIC const mp_rom_map_elem_t modkandinsky_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR_set_pixel), (mp_obj_t)&modkandinsky_set_pixel_obj },
{ MP_ROM_QSTR(MP_QSTR_draw_string), (mp_obj_t)&modkandinsky_draw_string_obj },
{ MP_ROM_QSTR(MP_QSTR_draw_line), (mp_obj_t)&modkandinsky_draw_line_obj },
{ MP_ROM_QSTR(MP_QSTR_draw_circle), (mp_obj_t)&modkandinsky_draw_circle_obj },
{ MP_ROM_QSTR(MP_QSTR_fill_rect), (mp_obj_t)&modkandinsky_fill_rect_obj },
{ MP_ROM_QSTR(MP_QSTR_fill_circle), (mp_obj_t)&modkandinsky_fill_circle_obj },
{ MP_ROM_QSTR(MP_QSTR_fill_polygon), (mp_obj_t)&modkandinsky_fill_polygon_obj },
{ MP_ROM_QSTR(MP_QSTR_large_font), mp_const_true },
{ MP_ROM_QSTR(MP_QSTR_small_font), mp_const_false },
{ MP_ROM_QSTR(MP_QSTR_wait_vblank), (mp_obj_t)&modkandinsky_wait_vblank_obj },