aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoel Bodenmann <joel@unormal.org>2013-12-08 21:13:54 +0100
committerJoel Bodenmann <joel@unormal.org>2013-12-08 21:13:54 +0100
commitace1948817becc602079fb95bee45db7266d2142 (patch)
tree1b94ec590a01843d28a0e56ba5b6d558db9da86d
parentab75a7eb6e482e221a784736cd0184cf7540b4a3 (diff)
downloaduGFX-ace1948817becc602079fb95bee45db7266d2142.tar.gz
uGFX-ace1948817becc602079fb95bee45db7266d2142.tar.bz2
uGFX-ace1948817becc602079fb95bee45db7266d2142.zip
added gdispGDrawThickLine()
-rw-r--r--include/gdisp/gdisp.h18
-rw-r--r--releases.txt1
-rw-r--r--src/gdisp/gdisp.c125
3 files changed, 144 insertions, 0 deletions
diff --git a/include/gdisp/gdisp.h b/include/gdisp/gdisp.h
index 99b1a504..ef5115a9 100644
--- a/include/gdisp/gdisp.h
+++ b/include/gdisp/gdisp.h
@@ -624,6 +624,24 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co
*/
void gdispGFillConvexPoly(GDisplay *g, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt, color_t color);
#define gdispFillConvexPoly(x,y,p,i,c) gdispGFillConvexPoly(GDISP,x,y,p,i,c)
+
+ /**
+ * @brief Draw a line with a specified thickness
+ * @details The line thickness is specified in pixels. The line ends can
+ * be selected to be either flat or round.
+ * @note Uses gdispGFillConvexPoly() internally to perform the drawing.
+ *
+ * @param[in] g The display to use
+ * @param[in] x0,y0 The start position
+ * @param[in] x1,y1 The end position
+ * @param[in] color The color to use
+ * @param[in] width The width of the line
+ * @param[in] round Use round ends for the line
+ *
+ * @api
+ */
+ void gdispGDrawThickLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color, coord_t width, bool_t round);
+ #define gdispDrawThickLine(x0,y0,x1,y1,c,w,r) gdispGDrawThickLine(GDISP,x0,y0,x1,y1,c,w,r)
#endif
/* Text Functions */
diff --git a/releases.txt b/releases.txt
index e8ac0e03..85d7c506 100644
--- a/releases.txt
+++ b/releases.txt
@@ -6,6 +6,7 @@ current release: 2.0
FIX: Significant improvements to the way the MCU touch driver works.
FEATURE: Add support for edge to edge touch calibration.
FEATURE: Added progressbar widget
+FEATURE: Added gdispGDrawThickLine() by user jpa-
*** changes after 1.9 ***
diff --git a/src/gdisp/gdisp.c b/src/gdisp/gdisp.c
index 1eb5a41b..b625f8a7 100644
--- a/src/gdisp/gdisp.c
+++ b/src/gdisp/gdisp.c
@@ -2565,6 +2565,131 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co
}
}
}
+
+ static int32_t rounding_div(const int32_t n, const int32_t d)
+ {
+ if ((n < 0) != (d < 0))
+ return (n - d/2) / d;
+ else
+ return (n + d/2) / d;
+ }
+
+ void gdispGDrawThickLine(GDisplay *g, coord_t x0, coord_t y0, coord_t x1, coord_t y1, color_t color, coord_t width, bool_t round) {
+ coord_t dx, dy, nx, ny;
+
+ /* Compute the direction vector for the line */
+ dx = x1 - x0;
+ dy = y1 - y0;
+
+ /* Compute vector for the normal of the line */
+ nx = dy;
+ ny = -dx;
+
+ /* Normalize the normal vector to length width.
+ * This uses Newton-Rhapson to avoid the need for floating point sqrt.
+ * We try to solve f(div) = div^2 - len/width^2.
+ */
+ {
+ int32_t div, len, tmp;
+ uint8_t i;
+
+ len = nx*nx + ny*ny;
+ div = 100; /* Initial guess for divider; not critical */
+
+ for (i = 0; i < 5; i++) {
+ tmp = width * width * div;
+ div -= (tmp * div - len) / (2 * tmp);
+ }
+
+ nx = rounding_div(nx, div);
+ ny = rounding_div(ny, div);
+ }
+
+ /* Offset the x0,y0 by half the width of the line. This way we
+ * can keep the width of the line accurate even if it is not evenly
+ * divisible by 2.
+ */
+ {
+ x0 -= rounding_div(nx, 2);
+ y0 -= rounding_div(ny, 2);
+ }
+
+ /* Fill in the point array */
+ if (!round) {
+ /* We use 4 points for the basic line shape:
+ *
+ * pt1 pt2
+ * (+n) ------------------------------------ (d+n)
+ * | |
+ * (0,0) ----------------------------------- (d)
+ * pt0 pt3
+ */
+ point pntarray[4];
+
+ pntarray[0].x = 0;
+ pntarray[0].y = 0;
+ pntarray[1].x = nx;
+ pntarray[1].y = ny;
+ pntarray[2].x = dx + nx;
+ pntarray[2].y = dy + ny;
+ pntarray[3].x = dx;
+ pntarray[3].y = dy;
+
+ gdispGFillConvexPoly(g, x0, y0, pntarray, 4, color);
+ } else {
+ /* We use 4 points for basic shape, plus 4 extra points for ends:
+ *
+ * pt3 ------------------ pt4
+ * / \
+ * pt2 pt5
+ * | |
+ * pt1 pt6
+ * \ /
+ * pt0 -------------------pt7
+ */
+ point pntarray[8];
+ coord_t nx2, ny2;
+
+ /* Magic numbers:
+ * 75/256 = sin(45) / (1 + sqrt(2)) diagonal octagon segments
+ * 106/256 = 1 / (1 + sqrt(2)) octagon side
+ * 53/256 = 0.5 / (1 + sqrt(2)) half of octagon side
+ * 150/256 = 1 - 1 / (1 + sqrt(2)) octagon height minus one side
+ */
+
+ /* Rotate the normal vector 45 deg counter-clockwise and reduce
+ * to 1 / (1 + sqrt(2)) length, for forming octagonal ends. */
+ nx2 = rounding_div((nx * 75 + ny * 75), 256);
+ ny2 = rounding_div((-nx * 75 + ny * 75), 256);
+
+ /* Offset and extend the line so that the center of the octagon
+ * is at the specified points. */
+ x0 += ny * 53 / 256;
+ y0 -= nx * 53 / 256;
+ dx -= ny * 106 / 256;
+ dy += nx * 106 / 256;
+
+ /* Now fill in the points by summing the calculated vectors. */
+ pntarray[0].x = 0;
+ pntarray[0].y = 0;
+ pntarray[1].x = nx2;
+ pntarray[1].y = ny2;
+ pntarray[2].x = nx2 + nx * 106/256;
+ pntarray[2].y = ny2 + ny * 106/256;
+ pntarray[3].x = nx;
+ pntarray[3].y = ny;
+ pntarray[4].x = dx + nx;
+ pntarray[4].y = dy + ny;
+ pntarray[5].x = dx + nx - nx2;
+ pntarray[5].y = dy + ny - ny2;
+ pntarray[6].x = dx + nx * 150/256 - nx2;
+ pntarray[6].y = dy + ny * 150/256 - ny2;
+ pntarray[7].x = dx;
+ pntarray[7].y = dy;
+
+ gdispGFillConvexPoly(g, x0, y0, pntarray, 8, color);
+ }
+ }
#endif
#if GDISP_NEED_TEXT