Skip to content

Commit

Permalink
Add Ellipse command
Browse files Browse the repository at this point in the history
This patch illustrates how to extend the ggtag protocol by adding a new
command for drawing an ellipse. The ellipse is defined by its center, X
radius and Y radius.
  • Loading branch information
rgerganov committed Oct 8, 2023
1 parent c1ec706 commit 304d27f
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 3 deletions.
2 changes: 2 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
<a class="dropdown-item" href="#">FillRect</a>
<a class="dropdown-item" href="#">Circle</a>
<a class="dropdown-item" href="#">FillCircle</a>
<a class="dropdown-item" href="#">Ellipse</a>
<a class="dropdown-item" href="#">Line</a>
<a class="dropdown-item" href="#">QR code</a>
<a class="dropdown-item" href="#">Image</a>
Expand Down Expand Up @@ -134,6 +135,7 @@ <h5 class="modal-title" id="helpModalLabel">Help</h5>
<b>FillRect:</b> <tt>X,Y,width,height</tt><br>
<b>Circle:</b> <tt>X,Y,radius</tt><br>
<b>FillCircle:</b> <tt>X,Y,radius</tt><br>
<b>Ellipse:</b> <tt>X,Y,radius_x,radius_y</tt><br>
<b>Line:</b> <tt>X1,Y1,X2,Y2</tt><br>
<b>QRcode:</b> <tt>X,Y,pointWidth,text</tt><br>
<b>Image:</b> <tt>X,Y,width,height,dither,url</tt><br>
Expand Down
Binary file modified docs/js/ggtag.wasm
Binary file not shown.
9 changes: 7 additions & 2 deletions docs/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ const ESC2CMD = {"\\t": "Text",
"\\P": "PNGImage",
"\\i": "BMPImage",
"\\a": "Icon",
"\\f": "RFID"}
"\\f": "RFID",
"\\e": "Ellipse"}

const CMD2ESC = {"Text": "\\t",
"Rect": "\\r",
Expand All @@ -24,7 +25,8 @@ const CMD2ESC = {"Text": "\\t",
"PNGImage": "\\P",
"BMPImage": "\\i",
"Icon": "\\a",
"RFID": "\\f"}
"RFID": "\\f",
"Ellipse": "\\e"}

var dragging = false;
// keeps the initial position when dragging starts
Expand Down Expand Up @@ -172,6 +174,9 @@ function onCmdChange() {
remaining = randomInt(16,40) + "," + randomIcon();
} else if (newCmd == "RFID") {
remaining = "em,12,3456789A";
} else if (newCmd == "Ellipse") {
// random radius
remaining = randomInt(10, 50) + "," + randomInt(10, 50);
}
$(curr).find("button").text(newCmd);
$(curr).find("input[type=text]").val(xyCoord+remaining);
Expand Down
71 changes: 71 additions & 0 deletions host/src/ggtag.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ struct CircleCmd {
int r;
};

struct EllipseCmd {
int x;
int y;
int rx;
int ry;
};

struct LineCmd {
int x1;
int y1;
Expand Down Expand Up @@ -327,6 +334,25 @@ struct BitBuffer {
}
return true;
}
bool addCmd(const EllipseCmd &cmd)
{
if (!addValue(ELLIPSE_CMD, CMD_BITS)) {
return false;
}
if (!addValue(cmd.x, X_BITS)) {
return false;
}
if (!addValue(cmd.y, Y_BITS)) {
return false;
}
if (!addValue(cmd.rx, R_BITS)) {
return false;
}
if (!addValue(cmd.ry, R_BITS)) {
return false;
}
return true;
}
bool addCmd(const LineCmd &cmd)
{
if (!addValue(LINE_CMD, CMD_BITS)) {
Expand Down Expand Up @@ -418,6 +444,9 @@ bool parseCommand(const char *input, int *cmd, int *curr_offset)
case 'f':
*cmd = RFID_CMD;
break;
case 'e':
*cmd = ELLIPSE_CMD;
break;
default:
return false;
}
Expand Down Expand Up @@ -743,6 +772,38 @@ bool parseCircleCmd(const char *input, CircleCmd *cmd, int *curr_offset)
return true;
}

// EllipseCommand: <x>,<y>,<rx>,<ry>
bool parseEllipseCmd(const char* input, EllipseCmd *cmd, int *curr_offset)
{
int offset = *curr_offset;
if (!input[offset]) {
return false;
}
if (!parseInt(input, &cmd->x, &offset)) {
return false;
}
if (input[offset++] != ',') {
return false;
}
if (!parseInt(input, &cmd->y, &offset)) {
return false;
}
if (input[offset++] != ',') {
return false;
}
if (!parseInt(input, &cmd->rx, &offset)) {
return false;
}
if (input[offset++] != ',') {
return false;
}
if (!parseInt(input, &cmd->ry, &offset)) {
return false;
}
*curr_offset = offset;
return true;
}

// LineCommand: <x1>,<y1>,<x2>,<y2>
bool parseLineCmd(const char *input, LineCmd *cmd, int *curr_offset)
{
Expand Down Expand Up @@ -826,6 +887,16 @@ bool parse(const char *input, BitBuffer *buf, int *curr_offset)
return false;
}
break;
case ELLIPSE_CMD:
EllipseCmd ellipse_cmd;
if (!parseEllipseCmd(input, &ellipse_cmd, &offset)) {
sprintf(lastError, "Failed to parse Ellipse command");
return false;
}
if (!buf->addCmd(ellipse_cmd)) {
return false;
}
break;
case LINE_CMD:
LineCmd line_cmd;
if (!parseLineCmd(input, &line_cmd, &offset)) {
Expand Down
1 change: 1 addition & 0 deletions shared/include/GUI_Paint.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ void Paint_DrawPoint(UWORD Xpoint, UWORD Ypoint, UWORD Color, DOT_PIXEL Dot_Pixe
void Paint_DrawLine(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color, DOT_PIXEL Line_width, LINE_STYLE Line_Style);
void Paint_DrawRectangle(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend, UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill);
void Paint_DrawCircle(UWORD X_Center, UWORD Y_Center, UWORD Radius, UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill);
void Paint_DrawEllipse(UWORD X_Center, UWORD Y_Center, UWORD Radius, UWORD Radius2, UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill);

//Display string
void Paint_DrawChar(UWORD Xstart, UWORD Ystart, const char Acsii_Char, sFONT* Font, UWORD Color_Foreground, UWORD Color_Background);
Expand Down
4 changes: 3 additions & 1 deletion shared/include/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,10 @@ struct BitReader {
#define RFID_CMD 9
// draw image (run length encoded)
#define RLE_IMAGE_CMD 10
// draw ellipse
#define ELLIPSE_CMD 11

#define EOF_CMD 11
#define EOF_CMD 12

// bits for command
#define CMD_BITS 4
Expand Down
51 changes: 51 additions & 0 deletions shared/src/GUI_Paint.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,57 @@ void Paint_DrawRectangle(UWORD Xstart, UWORD Ystart, UWORD Xend, UWORD Yend,
}
}

void Paint_DrawEllipse(UWORD X_Center, UWORD Y_Center, UWORD Radius_x, UWORD Radius_y, UWORD Color, DOT_PIXEL Line_width, DRAW_FILL Draw_Fill)
{
if (X_Center >= Paint.Width || Y_Center >= Paint.Height) {
debug("Input exceeds the normal display range\r\n");
return;
}
// draw ellipse using the midpoint ellipse algorithm
int x = 0, y = Radius_y;
int rx = Radius_x, ry = Radius_y;
int p = ry * ry - rx * rx * ry + rx * rx / 4;
int dx = 2 * ry * ry * x;
int dy = 2 * rx * rx * y;
// region 1
while (dx < dy) {
Paint_DrawPoint(X_Center + x, Y_Center + y, Color, Line_width, DOT_STYLE_DFT);
Paint_DrawPoint(X_Center - x, Y_Center + y, Color, Line_width, DOT_STYLE_DFT);
Paint_DrawPoint(X_Center + x, Y_Center - y, Color, Line_width, DOT_STYLE_DFT);
Paint_DrawPoint(X_Center - x, Y_Center - y, Color, Line_width, DOT_STYLE_DFT);
if (p < 0) {
x++;
dx = dx + 2 * ry * ry;
p = p + dx + ry * ry;
} else {
x++;
y--;
dx = dx + 2 * ry * ry;
dy = dy - 2 * rx * rx;
p = p + dx - dy + ry * ry;
}
}
// region 2
p = ry * ry * (x + 1 / 2) * (x + 1 / 2) + rx * rx * (y - 1) * (y - 1) - rx * rx * ry * ry;
while (y >= 0) {
Paint_DrawPoint(X_Center + x, Y_Center + y, Color, Line_width, DOT_STYLE_DFT);
Paint_DrawPoint(X_Center - x, Y_Center + y, Color, Line_width, DOT_STYLE_DFT);
Paint_DrawPoint(X_Center + x, Y_Center - y, Color, Line_width, DOT_STYLE_DFT);
Paint_DrawPoint(X_Center - x, Y_Center - y, Color, Line_width, DOT_STYLE_DFT);
if (p > 0) {
y--;
dy = dy - 2 * rx * rx;
p = p + rx * rx - dy;
} else {
y--;
x++;
dx = dx + 2 * ry * ry;
dy = dy - 2 * rx * rx;
p = p + dx - dy + rx * rx;
}
}
}

/******************************************************************************
function: Use the 8-point method to draw a circle of the
specified size at the specified position->
Expand Down
12 changes: 12 additions & 0 deletions shared/src/protocol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@ void renderBits(const uint8_t *input, int bits_count)
Paint_DrawRectangle(x, y, x+w, y+h, BLACK, DOT_PIXEL_1X1, fill);
break;
}
case ELLIPSE_CMD: {
int x = br.read(X_BITS);
int y = br.read(Y_BITS);
int rx = br.read(R_BITS);
int ry = br.read(R_BITS);
if (x < 0 || y < 0 || rx < 0 || ry < 0) {
return;
}
debug("Render ellipse x=%d y=%d rx=%d ry=%d\n", x, y, rx, ry);
Paint_DrawEllipse(x, y, rx, ry, BLACK, DOT_PIXEL_1X1, DRAW_FILL_EMPTY);
break;
}
case CIRCLE_CMD:
case FILL_CIRCLE_CMD: {
int x = br.read(X_BITS);
Expand Down

0 comments on commit 304d27f

Please sign in to comment.