GWIN Graph - use GDISP point definition

This commit is contained in:
Andrew Hannam 2013-03-18 18:28:31 +10:00
parent cc5729dedd
commit d678352b9a
2 changed files with 569 additions and 570 deletions

View file

@ -1,208 +1,207 @@
/* /*
ChibiOS/GFX - Copyright (C) 2012, 2013 ChibiOS/GFX - Copyright (C) 2012, 2013
Joel Bodenmann aka Tectu <joel@unormal.org> Joel Bodenmann aka Tectu <joel@unormal.org>
This file is part of ChibiOS/GFX. This file is part of ChibiOS/GFX.
ChibiOS/GFX is free software; you can redistribute it and/or modify ChibiOS/GFX is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/GFX is distributed in the hope that it will be useful, ChibiOS/GFX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @file include/gwin/graph.h * @file include/gwin/graph.h
* @brief GWIN GRAPH module header file. * @brief GWIN GRAPH module header file.
* *
* @defgroup Graph Graph * @defgroup Graph Graph
* @ingroup GWIN * @ingroup GWIN
* *
* @details GWIN allows it to easily draw graphs. * @details GWIN allows it to easily draw graphs.
* @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h * @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h
* @pre GWIN_NEED_GRAPH must be set to TRUE in your gfxconf.h * @pre GWIN_NEED_GRAPH must be set to TRUE in your gfxconf.h
* *
* @{ * @{
*/ */
#ifndef _GWIN_GRAPH_H #ifndef _GWIN_GRAPH_H
#define _GWIN_GRAPH_H #define _GWIN_GRAPH_H
#if GWIN_NEED_GRAPH || defined(__DOXYGEN__) #if GWIN_NEED_GRAPH || defined(__DOXYGEN__)
/*===========================================================================*/ /*===========================================================================*/
/* Driver constants. */ /* Driver constants. */
/*===========================================================================*/ /*===========================================================================*/
#define GW_GRAPH 0x0003 #define GW_GRAPH 0x0003
/*===========================================================================*/ /*===========================================================================*/
/* Type definitions */ /* Type definitions */
/*===========================================================================*/ /*===========================================================================*/
typedef struct GGraphPoint_t { // GDISP now has its own point structure
coord_t x, y; #define GGraphPoint point
} GGraphPoint;
typedef enum GGraphPointType_e {
typedef enum GGraphPointType_e { GGRAPH_POINT_NONE, GGRAPH_POINT_DOT, GGRAPH_POINT_SQUARE, GGRAPH_POINT_CIRCLE
GGRAPH_POINT_NONE, GGRAPH_POINT_DOT, GGRAPH_POINT_SQUARE, GGRAPH_POINT_CIRCLE } GGraphPointType;
} GGraphPointType;
typedef struct GGraphPointStyle_t {
typedef struct GGraphPointStyle_t { GGraphPointType type;
GGraphPointType type; coord_t size;
coord_t size; color_t color;
color_t color; } GGraphPointStyle;
} GGraphPointStyle;
typedef enum GGraphLineType_e {
typedef enum GGraphLineType_e { GGRAPH_LINE_NONE, GGRAPH_LINE_SOLID, GGRAPH_LINE_DOT, GGRAPH_LINE_DASH
GGRAPH_LINE_NONE, GGRAPH_LINE_SOLID, GGRAPH_LINE_DOT, GGRAPH_LINE_DASH } GGraphLineType;
} GGraphLineType;
typedef struct GGraphLineStyle_t {
typedef struct GGraphLineStyle_t { GGraphLineType type;
GGraphLineType type; coord_t size;
coord_t size; color_t color;
color_t color; } GGraphLineStyle;
} GGraphLineStyle;
typedef struct GGraphGridStyle_t {
typedef struct GGraphGridStyle_t { GGraphLineType type;
GGraphLineType type; coord_t size;
coord_t size; color_t color;
color_t color; coord_t spacing;
coord_t spacing; } GGraphGridStyle;
} GGraphGridStyle;
typedef struct GGraphStyle_t {
typedef struct GGraphStyle_t { GGraphPointStyle point;
GGraphPointStyle point; GGraphLineStyle line;
GGraphLineStyle line; GGraphLineStyle xaxis;
GGraphLineStyle xaxis; GGraphLineStyle yaxis;
GGraphLineStyle yaxis; GGraphGridStyle xgrid;
GGraphGridStyle xgrid; GGraphGridStyle ygrid;
GGraphGridStyle ygrid; uint16_t flags;
uint16_t flags; #define GWIN_GRAPH_STYLE_XAXIS_POSITIVE_ARROWS 0x0001
#define GWIN_GRAPH_STYLE_XAXIS_POSITIVE_ARROWS 0x0001 #define GWIN_GRAPH_STYLE_XAXIS_NEGATIVE_ARROWS 0x0002
#define GWIN_GRAPH_STYLE_XAXIS_NEGATIVE_ARROWS 0x0002 #define GWIN_GRAPH_STYLE_YAXIS_POSITIVE_ARROWS 0x0004
#define GWIN_GRAPH_STYLE_YAXIS_POSITIVE_ARROWS 0x0004 #define GWIN_GRAPH_STYLE_YAXIS_NEGATIVE_ARROWS 0x0008
#define GWIN_GRAPH_STYLE_YAXIS_NEGATIVE_ARROWS 0x0008 #define GWIN_GRAPH_STYLE_POSITIVE_AXIS_ARROWS (GWIN_GRAPH_STYLE_XAXIS_POSITIVE_ARROWS|GWIN_GRAPH_STYLE_YAXIS_POSITIVE_ARROWS)
#define GWIN_GRAPH_STYLE_POSITIVE_AXIS_ARROWS (GWIN_GRAPH_STYLE_XAXIS_POSITIVE_ARROWS|GWIN_GRAPH_STYLE_YAXIS_POSITIVE_ARROWS) #define GWIN_GRAPH_STYLE_NEGATIVE_AXIS_ARROWS (GWIN_GRAPH_STYLE_XAXIS_NEGATIVE_ARROWS|GWIN_GRAPH_STYLE_YAXIS_NEGATIVE_ARROWS)
#define GWIN_GRAPH_STYLE_NEGATIVE_AXIS_ARROWS (GWIN_GRAPH_STYLE_XAXIS_NEGATIVE_ARROWS|GWIN_GRAPH_STYLE_YAXIS_NEGATIVE_ARROWS) #define GWIN_GRAPH_STYLE_XAXIS_ARROWS (GWIN_GRAPH_STYLE_XAXIS_POSITIVE_ARROWS|GWIN_GRAPH_STYLE_XAXIS_NEGATIVE_ARROWS)
#define GWIN_GRAPH_STYLE_XAXIS_ARROWS (GWIN_GRAPH_STYLE_XAXIS_POSITIVE_ARROWS|GWIN_GRAPH_STYLE_XAXIS_NEGATIVE_ARROWS) #define GWIN_GRAPH_STYLE_YAXIS_ARROWS (GWIN_GRAPH_STYLE_YAXIS_POSITIVE_ARROWS|GWIN_GRAPH_STYLE_YAXIS_NEGATIVE_ARROWS)
#define GWIN_GRAPH_STYLE_YAXIS_ARROWS (GWIN_GRAPH_STYLE_YAXIS_POSITIVE_ARROWS|GWIN_GRAPH_STYLE_YAXIS_NEGATIVE_ARROWS) #define GWIN_GRAPH_STYLE_ALL_AXIS_ARROWS (GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS)
#define GWIN_GRAPH_STYLE_ALL_AXIS_ARROWS (GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS) } GGraphStyle;
} GGraphStyle;
// A graph window
// A graph window typedef struct GGraphObject_t {
typedef struct GGraphObject_t { GWindowObject gwin;
GWindowObject gwin; GGraphStyle style;
GGraphStyle style; coord_t xorigin, yorigin;
coord_t xorigin, yorigin; coord_t lastx, lasty;
coord_t lastx, lasty; } GGraphObject;
} GGraphObject;
/*===========================================================================*/
/*===========================================================================*/ /* External declarations. */
/* External declarations. */ /*===========================================================================*/
/*===========================================================================*/
#ifdef __cplusplus
#ifdef __cplusplus extern "C" {
extern "C" { #endif
#endif
/**
/** * @brief Create a graph window.
* @brief Create a graph window. * @return NULL if there is no resultant drawing area, otherwise a window handle.
* @return NULL if there is no resultant drawing area, otherwise a window handle. *
* * @param[in] gg The GGraphObject structure to initialise. If this is NULL the structure is dynamically allocated.
* @param[in] gg The GGraphObject structure to initialise. If this is NULL the structure is dynamically allocated. * @param[in] x,y The screen co-ordinates for the bottom left corner of the window
* @param[in] x,y The screen co-ordinates for the bottom left corner of the window * @param[in] width The width of the window
* @param[in] width The width of the window * @param[in] height The height of the window
* @param[in] height The height of the window * @note The console is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color)
* @note The console is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color) * @note The coordinate system within the window for graphing operations (but not for any other drawing
* @note The coordinate system within the window for graphing operations (but not for any other drawing * operation) is relative to the bottom left corner and then shifted right and up by the specified
* operation) is relative to the bottom left corner and then shifted right and up by the specified * graphing x and y origin. Note that this system is inverted in the y direction relative to the display.
* graphing x and y origin. Note that this system is inverted in the y direction relative to the display. * This gives the best graphing arrangement ie. increasing y values are closer to the top of the display.
* This gives the best graphing arrangement ie. increasing y values are closer to the top of the display. *
* * @api
* @api */
*/ GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height);
GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height);
/**
/** * @brief Set the style of the graphing operations.
* @brief Set the style of the graphing operations. *
* * @param[in] gh The window handle (must be a graph window)
* @param[in] gh The window handle (must be a graph window) * @param[in] pstyle The graph style to set.
* @param[in] pstyle The graph style to set. * @note The graph is not automatically redrawn. The new style will apply to any new drawing operations.
* @note The graph is not automatically redrawn. The new style will apply to any new drawing operations. *
* * @api
* @api */
*/ void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle);
void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle);
/**
/** * @brief Set the origin for graphing operations.
* @brief Set the origin for graphing operations. *
* * @param[in] gh The window handle (must be a graph window)
* @param[in] gh The window handle (must be a graph window) * @param[in] x, y The new origin for the graph (in graph coordinates relative to the bottom left corner).
* @param[in] x, y The new origin for the graph (in graph coordinates relative to the bottom left corner). * @note The graph is not automatically redrawn. The new origin will apply to any new drawing operations.
* @note The graph is not automatically redrawn. The new origin will apply to any new drawing operations. *
* * @api
* @api */
*/ void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y);
void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y);
/**
/** * @brief Draw the axis and the background grid.
* @brief Draw the axis and the background grid. *
* * @param[in] gh The window handle (must be a graph window)
* @param[in] gh The window handle (must be a graph window) * @note The graph is not automatically cleared. You must do that first by calling gwinClear().
* @note The graph is not automatically cleared. You must do that first by calling gwinClear(). *
* * @api
* @api */
*/ void gwinGraphDrawAxis(GHandle gh);
void gwinGraphDrawAxis(GHandle gh);
/**
/** * @brief Start a new set of graphing data.
* @brief Start a new set of graphing data. * @details This prevents a line being drawn from the last data point to the next point to be drawn.
* @details This prevents a line being drawn from the last data point to the next point to be drawn. *
* * @param[in] gh The window handle (must be a graph window)
* @param[in] gh The window handle (must be a graph window) *
* * @api
* @api */
*/ void gwinGraphStartSet(GHandle gh);
void gwinGraphStartSet(GHandle gh);
/**
/** * @brief Draw a graph point.
* @brief Draw a graph point. * @details A graph point and a line connecting to the previous point will be drawn.
* @details A graph point and a line connecting to the previous point will be drawn. *
* * @param[in] gh The window handle (must be a graph window)
* @param[in] gh The window handle (must be a graph window) * @param[in] x, y The new point for the graph.
* @param[in] x, y The new point for the graph. *
* * @api
* @api */
*/ void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y);
void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y);
/**
/** * @brief Draw multiple graph points.
* @brief Draw multiple graph points. * @details A graph point and a line connecting to each previous point will be drawn.
* @details A graph point and a line connecting to each previous point will be drawn. *
* * @param[in] gh The window handle (must be a graph window)
* @param[in] gh The window handle (must be a graph window) * @param[in] points The array of points for the graph.
* @param[in] points The array of points for the graph. * @param[in] count The number of points in the array.
* @param[in] count The number of points in the array. * @note This is slightly more efficient than calling gwinGraphDrawPoint() repeatedly.
* @note This is slightly more efficient than calling gwinGraphDrawPoint() repeatedly. *
* * @api
* @api */
*/ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count);
void gwinGraphDrawPoints(GHandle gh, const GGraphPoint *points, unsigned count);
#ifdef __cplusplus
#ifdef __cplusplus }
} #endif
#endif
#endif /* GWIN_NEED_GRAPH */
#endif /* GWIN_NEED_GRAPH */
#endif /* _GWIN_GRAPH_H */
#endif /* _GWIN_GRAPH_H */ /** @} */
/** @} */

View file

@ -1,362 +1,362 @@
/* /*
ChibiOS/GFX - Copyright (C) 2012, 2013 ChibiOS/GFX - Copyright (C) 2012, 2013
Joel Bodenmann aka Tectu <joel@unormal.org> Joel Bodenmann aka Tectu <joel@unormal.org>
This file is part of ChibiOS/GFX. This file is part of ChibiOS/GFX.
ChibiOS/GFX is free software; you can redistribute it and/or modify ChibiOS/GFX is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/GFX is distributed in the hope that it will be useful, ChibiOS/GFX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @file src/gwin/graph.c * @file src/gwin/graph.c
* @brief GWIN sub-system button code. * @brief GWIN sub-system button code.
* *
* @defgroup Graph Graph * @defgroup Graph Graph
* @ingroup GWIN * @ingroup GWIN
* *
* @{ * @{
*/ */
#include "ch.h" #include "ch.h"
#include "hal.h" #include "hal.h"
#include "gfx.h" #include "gfx.h"
#if (GFX_USE_GWIN && GWIN_NEED_GRAPH) || defined(__DOXYGEN__) #if (GFX_USE_GWIN && GWIN_NEED_GRAPH) || defined(__DOXYGEN__)
#include "gwin/internal.h" #include "gwin/internal.h"
#define GGRAPH_FLG_CONNECTPOINTS (GWIN_FIRST_CONTROL_FLAG<<0) #define GGRAPH_FLG_CONNECTPOINTS (GWIN_FIRST_CONTROL_FLAG<<0)
#define GGRAPH_ARROW_SIZE 5 #define GGRAPH_ARROW_SIZE 5
static const GGraphStyle GGraphDefaultStyle = { static const GGraphStyle GGraphDefaultStyle = {
{ GGRAPH_POINT_DOT, 0, White }, // point { GGRAPH_POINT_DOT, 0, White }, // point
{ GGRAPH_LINE_DOT, 2, Gray }, // line { GGRAPH_LINE_DOT, 2, Gray }, // line
{ GGRAPH_LINE_SOLID, 0, White }, // x axis { GGRAPH_LINE_SOLID, 0, White }, // x axis
{ GGRAPH_LINE_SOLID, 0, White }, // y axis { GGRAPH_LINE_SOLID, 0, White }, // y axis
{ GGRAPH_LINE_NONE, 0, White, 0 }, // x grid { GGRAPH_LINE_NONE, 0, White, 0 }, // x grid
{ GGRAPH_LINE_NONE, 0, White, 0 }, // y grid { GGRAPH_LINE_NONE, 0, White, 0 }, // y grid
GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS // flags GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS // flags
}; };
static void pointto(GGraphObject *gg, coord_t x, coord_t y, const GGraphPointStyle *style) { static void pointto(GGraphObject *gg, coord_t x, coord_t y, const GGraphPointStyle *style) {
if (style->type == GGRAPH_POINT_NONE) if (style->type == GGRAPH_POINT_NONE)
return; return;
// Convert to device space. Note the y-axis is inverted. // Convert to device space. Note the y-axis is inverted.
x += gg->gwin.x + gg->xorigin; x += gg->gwin.x + gg->xorigin;
y = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y; y = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y;
if (style->size <= 1) { if (style->size <= 1) {
gdispDrawPixel(x, y, style->color); gdispDrawPixel(x, y, style->color);
return; return;
} }
switch(style->type) { switch(style->type) {
case GGRAPH_POINT_SQUARE: case GGRAPH_POINT_SQUARE:
gdispDrawBox(x-style->size, y-style->size, 2*style->size, 2*style->size, style->color); gdispDrawBox(x-style->size, y-style->size, 2*style->size, 2*style->size, style->color);
break; break;
#if GDISP_NEED_CIRCLE #if GDISP_NEED_CIRCLE
case GGRAPH_POINT_CIRCLE: case GGRAPH_POINT_CIRCLE:
gdispDrawCircle(x, y, style->size, style->color); gdispDrawCircle(x, y, style->size, style->color);
break; break;
#endif #endif
case GGRAPH_POINT_DOT: case GGRAPH_POINT_DOT:
default: default:
gdispDrawPixel(x, y, style->color); gdispDrawPixel(x, y, style->color);
break; break;
} }
} }
static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t y1, const GGraphLineStyle *style) { static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t y1, const GGraphLineStyle *style) {
coord_t dy, dx; coord_t dy, dx;
coord_t addx, addy; coord_t addx, addy;
coord_t P, diff, i; coord_t P, diff, i;
coord_t run_on, run_off, run; coord_t run_on, run_off, run;
if (style->type == GGRAPH_LINE_NONE) if (style->type == GGRAPH_LINE_NONE)
return; return;
// Convert to device space. Note the y-axis is inverted. // Convert to device space. Note the y-axis is inverted.
x0 += gg->gwin.x + gg->xorigin; x0 += gg->gwin.x + gg->xorigin;
y0 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y0; y0 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y0;
x1 += gg->gwin.x + gg->xorigin; x1 += gg->gwin.x + gg->xorigin;
y1 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y1; y1 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y1;
if (style->size <= 0) { if (style->size <= 0) {
// Use the driver to draw a solid line // Use the driver to draw a solid line
gdispDrawLine(x0, y0, x1, y1, style->color); gdispDrawLine(x0, y0, x1, y1, style->color);
return; return;
} }
switch (style->type) { switch (style->type) {
case GGRAPH_LINE_DOT: case GGRAPH_LINE_DOT:
run_on = 1; run_on = 1;
run_off = -style->size; run_off = -style->size;
break; break;
case GGRAPH_LINE_DASH: case GGRAPH_LINE_DASH:
run_on = style->size; run_on = style->size;
run_off = -style->size; run_off = -style->size;
break; break;
case GGRAPH_LINE_SOLID: case GGRAPH_LINE_SOLID:
default: default:
// Use the driver to draw a solid line // Use the driver to draw a solid line
gdispDrawLine(x0, y0, x1, y1, style->color); gdispDrawLine(x0, y0, x1, y1, style->color);
return; return;
} }
// Use Bresenham's algorithm modified to draw a stylized line // Use Bresenham's algorithm modified to draw a stylized line
run = 0; run = 0;
if (x1 >= x0) { if (x1 >= x0) {
dx = x1 - x0; dx = x1 - x0;
addx = 1; addx = 1;
} else { } else {
dx = x0 - x1; dx = x0 - x1;
addx = -1; addx = -1;
} }
if (y1 >= y0) { if (y1 >= y0) {
dy = y1 - y0; dy = y1 - y0;
addy = 1; addy = 1;
} else { } else {
dy = y0 - y1; dy = y0 - y1;
addy = -1; addy = -1;
} }
if (dx >= dy) { if (dx >= dy) {
dy *= 2; dy *= 2;
P = dy - dx; P = dy - dx;
diff = P - dx; diff = P - dx;
for(i=0; i<=dx; ++i) { for(i=0; i<=dx; ++i) {
if (run++ >= 0) { if (run++ >= 0) {
if (run >= run_on) if (run >= run_on)
run = run_off; run = run_off;
gdispDrawPixel(x0, y0, style->color); gdispDrawPixel(x0, y0, style->color);
} }
if (P < 0) { if (P < 0) {
P += dy; P += dy;
x0 += addx; x0 += addx;
} else { } else {
P += diff; P += diff;
x0 += addx; x0 += addx;
y0 += addy; y0 += addy;
} }
} }
} else { } else {
dx *= 2; dx *= 2;
P = dx - dy; P = dx - dy;
diff = P - dy; diff = P - dy;
for(i=0; i<=dy; ++i) { for(i=0; i<=dy; ++i) {
if (run++ >= 0) { if (run++ >= 0) {
if (run >= run_on) if (run >= run_on)
run = run_off; run = run_off;
gdispDrawPixel(x0, y0, style->color); gdispDrawPixel(x0, y0, style->color);
} }
if (P < 0) { if (P < 0) {
P += dx; P += dx;
y0 += addy; y0 += addy;
} else { } else {
P += diff; P += diff;
x0 += addx; x0 += addx;
y0 += addy; y0 += addy;
} }
} }
} }
} }
GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height) { GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height) {
if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject)))) if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject))))
return 0; return 0;
gg->gwin.type = GW_GRAPH; gg->gwin.type = GW_GRAPH;
gg->xorigin = gg->yorigin = 0; gg->xorigin = gg->yorigin = 0;
gg->lastx = gg->lasty = 0; gg->lastx = gg->lasty = 0;
gwinGraphSetStyle(&gg->gwin, &GGraphDefaultStyle); gwinGraphSetStyle(&gg->gwin, &GGraphDefaultStyle);
return (GHandle)gg; return (GHandle)gg;
} }
void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) { void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH) if (gh->type != GW_GRAPH)
return; return;
gg->style.point.type = pstyle->point.type; gg->style.point.type = pstyle->point.type;
gg->style.point.size = pstyle->point.size; gg->style.point.size = pstyle->point.size;
gg->style.point.color = pstyle->point.color; gg->style.point.color = pstyle->point.color;
gg->style.line.type = pstyle->line.type; gg->style.line.type = pstyle->line.type;
gg->style.line.size = pstyle->line.size; gg->style.line.size = pstyle->line.size;
gg->style.line.color = pstyle->line.color; gg->style.line.color = pstyle->line.color;
gg->style.xaxis.type = pstyle->xaxis.type; gg->style.xaxis.type = pstyle->xaxis.type;
gg->style.xaxis.size = pstyle->xaxis.size; gg->style.xaxis.size = pstyle->xaxis.size;
gg->style.xaxis.color = pstyle->xaxis.color; gg->style.xaxis.color = pstyle->xaxis.color;
gg->style.yaxis.type = pstyle->yaxis.type; gg->style.yaxis.type = pstyle->yaxis.type;
gg->style.yaxis.size = pstyle->yaxis.size; gg->style.yaxis.size = pstyle->yaxis.size;
gg->style.yaxis.color = pstyle->yaxis.color; gg->style.yaxis.color = pstyle->yaxis.color;
gg->style.xgrid.type = pstyle->xgrid.type; gg->style.xgrid.type = pstyle->xgrid.type;
gg->style.xgrid.size = pstyle->xgrid.size; gg->style.xgrid.size = pstyle->xgrid.size;
gg->style.xgrid.color = pstyle->xgrid.color; gg->style.xgrid.color = pstyle->xgrid.color;
gg->style.xgrid.spacing = pstyle->xgrid.spacing; gg->style.xgrid.spacing = pstyle->xgrid.spacing;
gg->style.ygrid.type = pstyle->ygrid.type; gg->style.ygrid.type = pstyle->ygrid.type;
gg->style.ygrid.size = pstyle->ygrid.size; gg->style.ygrid.size = pstyle->ygrid.size;
gg->style.ygrid.color = pstyle->ygrid.color; gg->style.ygrid.color = pstyle->ygrid.color;
gg->style.ygrid.spacing = pstyle->ygrid.spacing; gg->style.ygrid.spacing = pstyle->ygrid.spacing;
gg->style.flags = pstyle->flags; gg->style.flags = pstyle->flags;
#undef gg #undef gg
} }
void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y) { void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH) if (gh->type != GW_GRAPH)
return; return;
gg->xorigin = x; gg->xorigin = x;
gg->yorigin = y; gg->yorigin = y;
#undef gg #undef gg
} }
void gwinGraphDrawAxis(GHandle gh) { void gwinGraphDrawAxis(GHandle gh) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
coord_t i, xmin, ymin, xmax, ymax; coord_t i, xmin, ymin, xmax, ymax;
if (gh->type != GW_GRAPH) if (gh->type != GW_GRAPH)
return; return;
xmin = -gg->xorigin; xmin = -gg->xorigin;
xmax = gh->width-gg->xorigin-1; xmax = gh->width-gg->xorigin-1;
ymin = -gg->yorigin; ymin = -gg->yorigin;
ymax = gh->height-gg->yorigin-1; ymax = gh->height-gg->yorigin-1;
// x grid - this code assumes that the GGraphGridStyle is a superset of GGraphListStyle // x grid - this code assumes that the GGraphGridStyle is a superset of GGraphListStyle
if (gg->style.xgrid.type != GGRAPH_LINE_NONE && gg->style.xgrid.spacing >= 2) { if (gg->style.xgrid.type != GGRAPH_LINE_NONE && gg->style.xgrid.spacing >= 2) {
for(i = gg->style.xgrid.spacing; i <= xmax; i += gg->style.xgrid.spacing) for(i = gg->style.xgrid.spacing; i <= xmax; i += gg->style.xgrid.spacing)
lineto(gg, i, ymin, i, ymax, (GGraphLineStyle *)&gg->style.xgrid); lineto(gg, i, ymin, i, ymax, (GGraphLineStyle *)&gg->style.xgrid);
for(i = -gg->style.xgrid.spacing; i >= xmin; i -= gg->style.xgrid.spacing) for(i = -gg->style.xgrid.spacing; i >= xmin; i -= gg->style.xgrid.spacing)
lineto(gg, i, ymin, i, ymax, (GGraphLineStyle *)&gg->style.xgrid); lineto(gg, i, ymin, i, ymax, (GGraphLineStyle *)&gg->style.xgrid);
} }
// y grid - this code assumes that the GGraphGridStyle is a superset of GGraphListStyle // y grid - this code assumes that the GGraphGridStyle is a superset of GGraphListStyle
if (gg->style.ygrid.type != GGRAPH_LINE_NONE && gg->style.ygrid.spacing >= 2) { if (gg->style.ygrid.type != GGRAPH_LINE_NONE && gg->style.ygrid.spacing >= 2) {
for(i = gg->style.ygrid.spacing; i <= ymax; i += gg->style.ygrid.spacing) for(i = gg->style.ygrid.spacing; i <= ymax; i += gg->style.ygrid.spacing)
lineto(gg, xmin, i, xmax, i, (GGraphLineStyle *)&gg->style.ygrid); lineto(gg, xmin, i, xmax, i, (GGraphLineStyle *)&gg->style.ygrid);
for(i = -gg->style.ygrid.spacing; i >= ymin; i -= gg->style.ygrid.spacing) for(i = -gg->style.ygrid.spacing; i >= ymin; i -= gg->style.ygrid.spacing)
lineto(gg, xmin, i, xmax, i, (GGraphLineStyle *)&gg->style.ygrid); lineto(gg, xmin, i, xmax, i, (GGraphLineStyle *)&gg->style.ygrid);
} }
// x axis // x axis
lineto(gg, xmin, 0, xmax, 0, &gg->style.xaxis); lineto(gg, xmin, 0, xmax, 0, &gg->style.xaxis);
if ((gg->style.flags & GWIN_GRAPH_STYLE_XAXIS_NEGATIVE_ARROWS)) { if ((gg->style.flags & GWIN_GRAPH_STYLE_XAXIS_NEGATIVE_ARROWS)) {
if (xmin > 0 || xmin < -(GGRAPH_ARROW_SIZE+1)) { if (xmin > 0 || xmin < -(GGRAPH_ARROW_SIZE+1)) {
lineto(gg, xmin, 0, xmin+GGRAPH_ARROW_SIZE, GGRAPH_ARROW_SIZE, &gg->style.xaxis); lineto(gg, xmin, 0, xmin+GGRAPH_ARROW_SIZE, GGRAPH_ARROW_SIZE, &gg->style.xaxis);
lineto(gg, xmin, 0, xmin+GGRAPH_ARROW_SIZE, -GGRAPH_ARROW_SIZE, &gg->style.xaxis); lineto(gg, xmin, 0, xmin+GGRAPH_ARROW_SIZE, -GGRAPH_ARROW_SIZE, &gg->style.xaxis);
} }
} }
if ((gg->style.flags & GWIN_GRAPH_STYLE_XAXIS_POSITIVE_ARROWS)) { if ((gg->style.flags & GWIN_GRAPH_STYLE_XAXIS_POSITIVE_ARROWS)) {
if (xmax < 0 || xmax > (GGRAPH_ARROW_SIZE+1)) { if (xmax < 0 || xmax > (GGRAPH_ARROW_SIZE+1)) {
lineto(gg, xmax, 0, xmax-GGRAPH_ARROW_SIZE, GGRAPH_ARROW_SIZE, &gg->style.xaxis); lineto(gg, xmax, 0, xmax-GGRAPH_ARROW_SIZE, GGRAPH_ARROW_SIZE, &gg->style.xaxis);
lineto(gg, xmax, 0, xmax-GGRAPH_ARROW_SIZE, -GGRAPH_ARROW_SIZE, &gg->style.xaxis); lineto(gg, xmax, 0, xmax-GGRAPH_ARROW_SIZE, -GGRAPH_ARROW_SIZE, &gg->style.xaxis);
} }
} }
// y axis // y axis
lineto(gg, 0, ymin, 0, ymax, &gg->style.yaxis); lineto(gg, 0, ymin, 0, ymax, &gg->style.yaxis);
if ((gg->style.flags & GWIN_GRAPH_STYLE_YAXIS_NEGATIVE_ARROWS)) { if ((gg->style.flags & GWIN_GRAPH_STYLE_YAXIS_NEGATIVE_ARROWS)) {
if (ymin > 0 || ymin < -(GGRAPH_ARROW_SIZE+1)) { if (ymin > 0 || ymin < -(GGRAPH_ARROW_SIZE+1)) {
lineto(gg, 0, ymin, GGRAPH_ARROW_SIZE, ymin+GGRAPH_ARROW_SIZE, &gg->style.yaxis); lineto(gg, 0, ymin, GGRAPH_ARROW_SIZE, ymin+GGRAPH_ARROW_SIZE, &gg->style.yaxis);
lineto(gg, 0, ymin, -GGRAPH_ARROW_SIZE, ymin+GGRAPH_ARROW_SIZE, &gg->style.yaxis); lineto(gg, 0, ymin, -GGRAPH_ARROW_SIZE, ymin+GGRAPH_ARROW_SIZE, &gg->style.yaxis);
} }
} }
if ((gg->style.flags & GWIN_GRAPH_STYLE_YAXIS_POSITIVE_ARROWS)) { if ((gg->style.flags & GWIN_GRAPH_STYLE_YAXIS_POSITIVE_ARROWS)) {
if (ymax < 0 || ymax > (GGRAPH_ARROW_SIZE+1)) { if (ymax < 0 || ymax > (GGRAPH_ARROW_SIZE+1)) {
lineto(gg, 0, ymax, GGRAPH_ARROW_SIZE, ymax-GGRAPH_ARROW_SIZE, &gg->style.yaxis); lineto(gg, 0, ymax, GGRAPH_ARROW_SIZE, ymax-GGRAPH_ARROW_SIZE, &gg->style.yaxis);
lineto(gg, 0, ymax, -GGRAPH_ARROW_SIZE, ymax-GGRAPH_ARROW_SIZE, &gg->style.yaxis); lineto(gg, 0, ymax, -GGRAPH_ARROW_SIZE, ymax-GGRAPH_ARROW_SIZE, &gg->style.yaxis);
} }
} }
#undef gg #undef gg
} }
void gwinGraphStartSet(GHandle gh) { void gwinGraphStartSet(GHandle gh) {
if (gh->type != GW_GRAPH) if (gh->type != GW_GRAPH)
return; return;
gh->flags &= ~GGRAPH_FLG_CONNECTPOINTS; gh->flags &= ~GGRAPH_FLG_CONNECTPOINTS;
} }
void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) { void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
if (gh->type != GW_GRAPH) if (gh->type != GW_GRAPH)
return; return;
if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) { if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) {
// Draw the line // Draw the line
lineto(gg, gg->lastx, gg->lasty, x, y, &gg->style.line); lineto(gg, gg->lastx, gg->lasty, x, y, &gg->style.line);
// Redraw the previous point because the line may have overwritten it // Redraw the previous point because the line may have overwritten it
pointto(gg, gg->lastx, gg->lasty, &gg->style.point); pointto(gg, gg->lastx, gg->lasty, &gg->style.point);
} else } else
gh->flags |= GGRAPH_FLG_CONNECTPOINTS; gh->flags |= GGRAPH_FLG_CONNECTPOINTS;
// Save this point for next time. // Save this point for next time.
gg->lastx = x; gg->lastx = x;
gg->lasty = y; gg->lasty = y;
// Draw this point. // Draw this point.
pointto(gg, x, y, &gg->style.point); pointto(gg, x, y, &gg->style.point);
#undef gg #undef gg
} }
void gwinGraphDrawPoints(GHandle gh, const GGraphPoint *points, unsigned count) { void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {
#define gg ((GGraphObject *)gh) #define gg ((GGraphObject *)gh)
unsigned i; unsigned i;
const GGraphPoint *p; const point *p;
if (gh->type != GW_GRAPH) if (gh->type != GW_GRAPH)
return; return;
// Draw the connecting lines // Draw the connecting lines
for(p = points, i = 0; i < count; p++, i++) { for(p = points, i = 0; i < count; p++, i++) {
if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) { if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) {
// Draw the line // Draw the line
lineto(gg, gg->lastx, gg->lasty, p->x, p->y, &gg->style.line); lineto(gg, gg->lastx, gg->lasty, p->x, p->y, &gg->style.line);
// Redraw the previous point because the line may have overwritten it // Redraw the previous point because the line may have overwritten it
if (i == 0) if (i == 0)
pointto(gg, gg->lastx, gg->lasty, &gg->style.point); pointto(gg, gg->lastx, gg->lasty, &gg->style.point);
} else } else
gh->flags |= GGRAPH_FLG_CONNECTPOINTS; gh->flags |= GGRAPH_FLG_CONNECTPOINTS;
// Save this point for next time. // Save this point for next time.
gg->lastx = p->x; gg->lastx = p->x;
gg->lasty = p->y; gg->lasty = p->y;
} }
// Draw the points. // Draw the points.
for(p = points, i = 0; i < count; p++, i++) for(p = points, i = 0; i < count; p++, i++)
pointto(gg, p->x, p->y, &gg->style.point); pointto(gg, p->x, p->y, &gg->style.point);
#undef gg #undef gg
} }
#endif /* GFX_USE_GWIN && GWIN_NEED_GRAPH */ #endif /* GFX_USE_GWIN && GWIN_NEED_GRAPH */
/** @} */ /** @} */