mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
Add Graphics.fill/drawEllipse and move fill/drawCircle to use the same code
This commit is contained in:
parent
dd76859049
commit
0dc0390e42
@ -32,6 +32,7 @@
|
||||
Add setNBCellOn for RAK8211-NB (fix #1581)
|
||||
Now escape chars <8 as octal, and add escape of vertical tab
|
||||
Add Graphics.createArrayBuffer(... {interleavex:true}) to allow faster support for P3 LED panels
|
||||
Add Graphics.fill/drawEllipse and move fill/drawCircle to use the same code
|
||||
|
||||
2v00 : Allow changeInterval with large (>32 bit) intervals (fix #1438)
|
||||
changeInterval now changes the interval immediately when it's called inside the interval it is changing (fix #1440)
|
||||
|
||||
@ -244,57 +244,68 @@ void graphicsDrawRect(JsGraphics *gfx, short x1, short y1, short x2, short y2) {
|
||||
graphicsFillRectDevice(gfx,x1,y2,x1,y1);
|
||||
}
|
||||
|
||||
void graphicsDrawCircle(JsGraphics *gfx, short posX, short posY, short rad) {
|
||||
graphicsToDeviceCoordinates(gfx, &posX, &posY);
|
||||
|
||||
int radY = 0,
|
||||
radX = rad;
|
||||
// Decision criterion divided by 2 evaluated at radX=radX, radY=0
|
||||
int decisionOver2 = 1 - radX;
|
||||
|
||||
while (radX >= radY) {
|
||||
graphicsSetPixelDevice(gfx, radX + posX, radY + posY, gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx, radY + posX, radX + posY, gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx, -radX + posX, radY + posY, gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx, -radY + posX, radX + posY, gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx, -radX + posX, -radY + posY, gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx, -radY + posX, -radX + posY, gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx, radX + posX, -radY + posY, gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx, radY + posX, -radX + posY, gfx->data.fgColor);
|
||||
radY++;
|
||||
|
||||
if (decisionOver2 <= 0) {
|
||||
// Change in decision criterion for radY -> radY+1
|
||||
decisionOver2 += 2 * radY + 1;
|
||||
}
|
||||
else {
|
||||
radX--;
|
||||
// Change for radY -> radY+1, radX -> radX-1
|
||||
decisionOver2 += 2 * (radY - radX) + 1;
|
||||
void graphicsDrawEllipse(JsGraphics *gfx, short posX1, short posY1, short posX2, short posY2){
|
||||
graphicsToDeviceCoordinates(gfx, &posX1, &posY1);
|
||||
graphicsToDeviceCoordinates(gfx, &posX2, &posY2);
|
||||
int posX = (posX1+posX2)/2;
|
||||
int posY = (posY1+posY2)/2;
|
||||
int width = (posX2-posX1)/2;
|
||||
int height = (posY2-posY1)/2;
|
||||
if (width<0) width=-width;
|
||||
if (height<0) height=-height;
|
||||
int hh = height * height;
|
||||
int ww = width * width;
|
||||
int hhww = hh * ww;
|
||||
int x0 = width;
|
||||
int dx = 0;
|
||||
int y;
|
||||
graphicsSetPixelDevice(gfx,posX - width,posY,gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx,posX + width,posY,gfx->data.fgColor);
|
||||
for (y = 1; y <= height; y++) {
|
||||
int x1 = x0 - (dx - 1);
|
||||
for(; x1> 0; x1--)
|
||||
if (x1 * x1 * hh + y * y * ww <= hhww)
|
||||
break;
|
||||
dx = x0 - x1;
|
||||
x0 = x1;
|
||||
if(dx<2){
|
||||
graphicsSetPixelDevice(gfx,posX - x0, posY - y,gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx,posX + x0, posY - y,gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx,posX - x0, posY + y,gfx->data.fgColor);
|
||||
graphicsSetPixelDevice(gfx,posX + x0, posY + y,gfx->data.fgColor);
|
||||
} else {
|
||||
graphicsFillRectDevice(gfx,posX - x0, posY - y, posX - x0 - dx + 1, posY - y);
|
||||
graphicsFillRectDevice(gfx,posX + x0, posY - y, posX + x0 + dx - 1, posY - y);
|
||||
graphicsFillRectDevice(gfx,posX - x0, posY + y, posX - x0 - dx + 1, posY + y);
|
||||
graphicsFillRectDevice(gfx,posX + x0, posY + y, posX + x0 + dx - 1, posY + y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void graphicsFillCircle(JsGraphics *gfx, short x, short y, short rad) {
|
||||
graphicsToDeviceCoordinates(gfx, &x, &y);
|
||||
|
||||
int radY = 0;
|
||||
int decisionOver2 = 1 - rad;
|
||||
|
||||
while (rad >= radY) {
|
||||
graphicsFillRectDevice(gfx, rad + x, radY + y, -rad + x, -radY + y);
|
||||
graphicsFillRectDevice(gfx, radY + x, rad + y, -radY + x, -rad + y);
|
||||
graphicsFillRectDevice(gfx, -rad + x, radY + y, rad + x, -radY + y);
|
||||
graphicsFillRectDevice(gfx, -radY + x, rad + y, radY + x, -rad + y);
|
||||
radY++;
|
||||
if (decisionOver2 <= 0){
|
||||
// Change in decision criterion for radY -> radY+1
|
||||
decisionOver2 += 2 * radY + 1;
|
||||
}else{
|
||||
rad--;
|
||||
// Change for radY -> radY+1, rad -> rad-1
|
||||
decisionOver2 += 2 * (radY - rad) + 1;
|
||||
}
|
||||
void graphicsFillEllipse(JsGraphics *gfx, short posX1, short posY1, short posX2, short posY2){
|
||||
graphicsToDeviceCoordinates(gfx, &posX1, &posY1);
|
||||
graphicsToDeviceCoordinates(gfx, &posX2, &posY2);
|
||||
int posX = (posX1+posX2)/2;
|
||||
int posY = (posY1+posY2)/2;
|
||||
int width = (posX2-posX1)/2;
|
||||
int height = (posY2-posY1)/2;
|
||||
if (width<0) width=-width;
|
||||
if (height<0) height=-height;
|
||||
int hh = height * height;
|
||||
int ww = width * width;
|
||||
int hhww = hh * ww;
|
||||
int x0 = width;
|
||||
int dx = 0;
|
||||
graphicsFillRectDevice(gfx, posX - width, posY, posX + width, posY);
|
||||
for (int y = 1; y <= height; y++) {
|
||||
int x1 = x0 - (dx - 1);
|
||||
for ( ; x1 > 0; x1--)
|
||||
if (x1*x1*hh + y*y*ww <= hhww)
|
||||
break;
|
||||
dx = x0 - x1;
|
||||
x0 = x1;
|
||||
graphicsFillRectDevice(gfx, posX - x0, posY - y, posX + x0, posY - y);
|
||||
graphicsFillRectDevice(gfx, posX - x0, posY + y, posX + x0, posY + y);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -121,8 +121,8 @@ void graphicsClear(JsGraphics *gfx);
|
||||
void graphicsFillRect(JsGraphics *gfx, short x1, short y1, short x2, short y2);
|
||||
void graphicsFallbackFillRect(JsGraphics *gfx, short x1, short y1, short x2, short y2); // Simple fillrect - doesn't call device-specific FR
|
||||
void graphicsDrawRect(JsGraphics *gfx, short x1, short y1, short x2, short y2);
|
||||
void graphicsDrawCircle(JsGraphics *gfx, short posX, short posY, short rad);
|
||||
void graphicsFillCircle(JsGraphics *gfx, short x, short y, short rad);
|
||||
void graphicsDrawEllipse(JsGraphics *gfx, short x, short y, short x2, short y2);
|
||||
void graphicsFillEllipse(JsGraphics *gfx, short x, short y, short x2, short y2);
|
||||
void graphicsDrawString(JsGraphics *gfx, short x1, short y1, const char *str);
|
||||
void graphicsDrawLine(JsGraphics *gfx, short x1, short y1, short x2, short y2);
|
||||
void graphicsFillPoly(JsGraphics *gfx, int points, short *vertices); // may overwrite vertices...
|
||||
|
||||
@ -421,10 +421,10 @@ void jswrap_graphics_clear(JsVar *parent) {
|
||||
"name" : "fillRect",
|
||||
"generate" : "jswrap_graphics_fillRect",
|
||||
"params" : [
|
||||
["x1","int32","The left"],
|
||||
["y1","int32","The top"],
|
||||
["x2","int32","The right"],
|
||||
["y2","int32","The bottom"]
|
||||
["x1","int32","The left X coordinate"],
|
||||
["y1","int32","The top Y coordinate"],
|
||||
["x2","int32","The right X coordinate"],
|
||||
["y2","int32","The bottom Y coordinate"]
|
||||
]
|
||||
}
|
||||
Fill a rectangular area in the Foreground Color
|
||||
@ -441,10 +441,10 @@ void jswrap_graphics_fillRect(JsVar *parent, int x1, int y1, int x2, int y2) {
|
||||
"name" : "drawRect",
|
||||
"generate" : "jswrap_graphics_drawRect",
|
||||
"params" : [
|
||||
["x1","int32","The left"],
|
||||
["y1","int32","The top"],
|
||||
["x2","int32","The right"],
|
||||
["y2","int32","The bottom"]
|
||||
["x1","int32","The left X coordinate"],
|
||||
["y1","int32","The top Y coordinate"],
|
||||
["x2","int32","The right X coordinate"],
|
||||
["y2","int32","The bottom Y coordinate"]
|
||||
]
|
||||
}
|
||||
Draw an unfilled rectangle 1px wide in the Foreground Color
|
||||
@ -470,9 +470,7 @@ void jswrap_graphics_drawRect(JsVar *parent, int x1, int y1, int x2, int y2) {
|
||||
Draw a filled circle in the Foreground Color
|
||||
*/
|
||||
void jswrap_graphics_fillCircle(JsVar *parent, int x, int y, int rad) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return;
|
||||
graphicsFillCircle(&gfx, (short)x,(short)y,(short)rad);
|
||||
graphicsSetVar(&gfx); // gfx data changed because modified area
|
||||
jswrap_graphics_fillEllipse(parent, x-rad, y-rad, x+rad, y+rad);
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
@ -490,12 +488,52 @@ Draw a filled circle in the Foreground Color
|
||||
Draw an unfilled circle 1px wide in the Foreground Color
|
||||
*/
|
||||
void jswrap_graphics_drawCircle(JsVar *parent, int x, int y, int rad) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return;
|
||||
graphicsDrawCircle(&gfx, (short)x,(short)y,(short)rad);
|
||||
graphicsSetVar(&gfx); // gfx data changed because modified area
|
||||
jswrap_graphics_drawEllipse(parent, x-rad, y-rad, x+rad, y+rad);
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "method",
|
||||
"class" : "Graphics",
|
||||
"name" : "fillEllipse",
|
||||
"ifndef" : "SAVE_ON_FLASH",
|
||||
"generate" : "jswrap_graphics_fillEllipse",
|
||||
"params" : [
|
||||
["x1","int32","The left X coordinate"],
|
||||
["y1","int32","The top Y coordinate"],
|
||||
["x2","int32","The right X coordinate"],
|
||||
["y2","int32","The bottom Y coordinate"]
|
||||
]
|
||||
}
|
||||
Draw a filled ellipse in the Foreground Color
|
||||
*/
|
||||
void jswrap_graphics_fillEllipse(JsVar *parent, int x, int y, int x2, int y2) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return;
|
||||
graphicsFillEllipse(&gfx, (short)x,(short)y,(short)x2,(short)y2);
|
||||
graphicsSetVar(&gfx); // gfx data changed because modified area
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "method",
|
||||
"class" : "Graphics",
|
||||
"name" : "drawEllipse",
|
||||
"ifndef" : "SAVE_ON_FLASH",
|
||||
"generate" : "jswrap_graphics_drawEllipse",
|
||||
"params" : [
|
||||
["x1","int32","The left X coordinate"],
|
||||
["y1","int32","The top Y coordinate"],
|
||||
["x2","int32","The right X coordinate"],
|
||||
["y2","int32","The bottom Y coordinate"]
|
||||
]
|
||||
}
|
||||
Draw an ellipse in the Foreground Color
|
||||
*/
|
||||
void jswrap_graphics_drawEllipse(JsVar *parent, int x, int y, int x2, int y2) {
|
||||
JsGraphics gfx; if (!graphicsGetFromVar(&gfx, parent)) return;
|
||||
graphicsDrawEllipse(&gfx, (short)x,(short)y,(short)x2,(short)y2);
|
||||
graphicsSetVar(&gfx); // gfx data changed because modified area
|
||||
}
|
||||
|
||||
/*JSON{
|
||||
"type" : "method",
|
||||
"class" : "Graphics",
|
||||
"name" : "getPixel",
|
||||
|
||||
@ -37,6 +37,8 @@ void jswrap_graphics_fillRect(JsVar *parent, int x1, int y1, int x2, int y2);
|
||||
void jswrap_graphics_drawRect(JsVar *parent, int x1, int y1, int x2, int y2);
|
||||
void jswrap_graphics_drawCircle(JsVar *parent, int x, int y, int rad);
|
||||
void jswrap_graphics_fillCircle(JsVar *parent, int x, int y, int rad);
|
||||
void jswrap_graphics_drawEllipse(JsVar *parent, int x, int y, int x2, int y2);
|
||||
void jswrap_graphics_fillEllipse(JsVar *parent, int x, int y, int x2, int y2);
|
||||
int jswrap_graphics_getPixel(JsVar *parent, int x, int y);
|
||||
void jswrap_graphics_setPixel(JsVar *parent, int x, int y, JsVar *color);
|
||||
void jswrap_graphics_setColorX(JsVar *parent, JsVar *r, JsVar *g, JsVar *b, bool isForeground);
|
||||
|
||||
146
tests/test_graphics_ellipse.js
Normal file
146
tests/test_graphics_ellipse.js
Normal file
@ -0,0 +1,146 @@
|
||||
var g = Graphics.createArrayBuffer(16,16,8);
|
||||
|
||||
g.dump = _=>{
|
||||
var s = "";
|
||||
var b = new Uint8Array(g.buffer);
|
||||
var n = 0;
|
||||
for (var y=0;y<g.getHeight();y++) {
|
||||
s+="\n";
|
||||
for (var x=0;x<g.getWidth();x++)
|
||||
s+=b[n++]?"#":".";
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
g.print = _=>{
|
||||
print("`"+g.dump()+"`");
|
||||
}
|
||||
|
||||
g.clear();
|
||||
g.drawEllipse(0,0,14,14);
|
||||
if (g.dump()!=`
|
||||
.....#####......
|
||||
....#.....#.....
|
||||
...#.......#....
|
||||
..#.........#...
|
||||
.#...........#..
|
||||
.#...........#..
|
||||
.#...........#..
|
||||
#.............#.
|
||||
.#...........#..
|
||||
.#...........#..
|
||||
.#...........#..
|
||||
..#.........#...
|
||||
...#.......#....
|
||||
....#.....#.....
|
||||
.....#####......
|
||||
................`) throw "drawEllipse circle";
|
||||
|
||||
g.clear();
|
||||
g.fillEllipse(0,0,14,14);
|
||||
if (g.dump()!=`
|
||||
.......#........
|
||||
....#######.....
|
||||
...#########....
|
||||
..###########...
|
||||
.#############..
|
||||
.#############..
|
||||
.#############..
|
||||
###############.
|
||||
.#############..
|
||||
.#############..
|
||||
.#############..
|
||||
..###########...
|
||||
...#########....
|
||||
....#######.....
|
||||
.......#........
|
||||
................`) throw "fillEllipse circle";
|
||||
|
||||
g.clear();
|
||||
g.drawEllipse(0,0,6,14);
|
||||
if (g.dump()!=`
|
||||
...#............
|
||||
..#.#...........
|
||||
.#...#..........
|
||||
.#...#..........
|
||||
.#...#..........
|
||||
.#...#..........
|
||||
.#...#..........
|
||||
#.....#.........
|
||||
.#...#..........
|
||||
.#...#..........
|
||||
.#...#..........
|
||||
.#...#..........
|
||||
.#...#..........
|
||||
..#.#...........
|
||||
...#............
|
||||
................`) throw "drawEllipse ellipse";
|
||||
|
||||
|
||||
g.clear();
|
||||
g.fillEllipse(0,0,6,14);
|
||||
if (g.dump()!=`
|
||||
...#............
|
||||
..###...........
|
||||
.#####..........
|
||||
.#####..........
|
||||
.#####..........
|
||||
.#####..........
|
||||
.#####..........
|
||||
#######.........
|
||||
.#####..........
|
||||
.#####..........
|
||||
.#####..........
|
||||
.#####..........
|
||||
.#####..........
|
||||
..###...........
|
||||
...#............
|
||||
................`) throw "fillEllipse ellipse";
|
||||
|
||||
|
||||
g.setRotation(1);
|
||||
|
||||
g.clear();
|
||||
g.drawEllipse(0,0,6,14);
|
||||
if (g.dump()!=`
|
||||
....#########...
|
||||
...#.........#..
|
||||
..#...........#.
|
||||
.#.............#
|
||||
..#...........#.
|
||||
...#.........#..
|
||||
....#########...
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................`) throw "drawEllipse ellipse rotated";
|
||||
|
||||
|
||||
g.clear();
|
||||
g.fillEllipse(0,0,6,14);
|
||||
if (g.dump()!=`
|
||||
........#.......
|
||||
...###########..
|
||||
..#############.
|
||||
.###############
|
||||
..#############.
|
||||
...###########..
|
||||
........#.......
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................
|
||||
................`) throw "fillEllipse ellipse rotated";
|
||||
|
||||
|
||||
//g.print();
|
||||
result=1;
|
||||
Loading…
x
Reference in New Issue
Block a user