I botched together the following code to do a simple rotating radar display.
How can I eliminate the flicker of the line being drawn and then drawn over? Can I use double buffering somehow?
How can I get mouse and keyboard inputs and process/parse them?
My goal is to read angle and distance data from an ultrasonic sensor and display that as a sweep. This data comes from an Arduino with an ultrasonic rangefinder mounted on a servo sweeping backwards and forwards 180 degrees. I also can't quite get the math right. I'd like it to go from 0 to 180, left to right and back depending on the angle data from the Arduino. 0 Deg is 90 Deg off to the right. So I know I have to offset it by 180 Deg but am hopeless at math. The sweep would have to start at 270 Deg and sweep through to 0 Deg. I will have to learn how to read the serial port and parse the data for the display.
Here is my code. I used a tutorial as a base and kind of guessed my way through.
/*
* simple-drawing.c - demonstrate drawing of pixels, lines, arcs, etc.
* on a window. All drawings are done in black color
* over a white background.
*/
#include <X11/Xlib.h>
#include <stdio.h>
#include <stdlib.h> /* getenv(), etc. /
#include <unistd.h> / sleep(), etc. */
// Include math library functions.
#include <math.h>
/*
- function: create_simple_window. Creates a window with a white background
in the given size.
- input: display, size of the window (in pixels), and location of the window
(in pixels).
- output: the window's ID.
- notes: window is created with a black border, 2 pixels wide.
the window is automatically mapped after its creation.
/
Window
create_simple_window(Display display, int width, int height, int x, int y)
{
int screen_num = DefaultScreen(display);
int win_border_width = 2;
Window win;
/* create a simple window, as a direct child of the screen's /
/ root window. Use the screen's black and white colors as /
/ the foreground and background colors of the window, /
/ respectively. Place the new window's top-left corner at /
/ the given 'x,y' coordinates. */
win = XCreateSimpleWindow(display, RootWindow(display, screen_num),
x, y, width, height, win_border_width,
BlackPixel(display, screen_num),
WhitePixel(display, screen_num));
/* make the window actually appear on the screen. */
XMapWindow(display, win);
/* flush all pending requests to the X server. */
XFlush(display);
return win;
}
GC
create_gc(Display* display, Window win, int reverse_video)
{
GC gc; /* handle of newly created GC. /
unsigned long valuemask = 0; / which values in 'values' to /
/ check when creating the GC. /
XGCValues values; / initial values for the GC. /
unsigned int line_width = 2; / line width for the GC. /
int line_style = LineSolid; / style for lines drawing and /
int cap_style = CapButt; / style of the line's edje and /
int join_style = JoinBevel; / joined lines. */
int screen_num = DefaultScreen(display);
gc = XCreateGC(display, win, valuemask, &values);
if (gc < 0) {
fprintf(stderr, "XCreateGC: \n");
}
/* allocate foreground and background colors for this GC. */
if (reverse_video) {
XSetForeground(display, gc, WhitePixel(display, screen_num));
XSetBackground(display, gc, BlackPixel(display, screen_num));
}
else {
XSetForeground(display, gc, BlackPixel(display, screen_num));
XSetBackground(display, gc, WhitePixel(display, screen_num));
}
/* define the style of lines that will be drawn using this GC. */
XSetLineAttributes(display, gc,
line_width, line_style, cap_style, join_style);
/* define the fill style for the GC. to be 'solid filling'. */
XSetFillStyle(display, gc, FillSolid);
return gc;
}
void
main(int argc, char* argv[])
{
Display* display; /* pointer to X Display structure. /
int screen_num; / number of screen to place the window on. /
Window win; / pointer to the newly created window. /
unsigned int display_width,
display_height; / height and width of the X display. /
unsigned int width, height; / height and width for the new window. /
char display_name = getenv("DISPLAY"); /* address of the X display. /
GC gc; / GC (graphics context) used for drawing /
/ in our window. */
// Added code to select simple black or white color to draw.
Colormap screen_colormap; /* color map to use for allocating colors. /
XColor black, white;
/ used for allocation of the given color /
/ map entries. /
Status rc; / return status of various Xlib functions. */
// Johns stuff. This code draws a line from starting co-ordinates at an angle
//
int angle=0;
int x1,x2,y1,y2;
int px,py;
// End
/* open connection with the X server. */
display = XOpenDisplay(display_name);
if (display == NULL) {
fprintf(stderr, "%s: cannot connect to X server '%s'\n",
argv[0], display_name);
exit(1);
}
/* get the geometry of the default screen for our display. */
screen_num = DefaultScreen(display);
display_width = DisplayWidth(display, screen_num);
display_height = DisplayHeight(display, screen_num);
/* make the new window occupy 1/9 of the screen's size. */
width = (display_width / 2);
height = (display_height / 2);
printf("window width - '%d'; height - '%d'\n", width, height);
/* create a simple window, as a direct child of the screen's /
/ root window. Use the screen's white color as the background /
/ color of the window. Place the new window's top-left corner /
/ at the given 'x,y' coordinates. */
win = create_simple_window(display, width, height, 50, 50);
/* allocate a new GC (graphics context) for drawing in the window. */
gc = create_gc(display, win, 0);
XSync(display, False);
// Following 3 lines needed or else we just see white background.
/* catch expose events */
XSelectInput(display, win, ExposureMask);
/* wait for the expose event */
XEvent ev;
XNextEvent(display, &ev);
// Follwing code borrowed to get colors to draw.
/* get access to the screen's color map. */
screen_colormap = DefaultColormap(display, DefaultScreen(display));
/* allocate the set of colors we will want to use for the drawing. */
rc = XAllocNamedColor(display, screen_colormap, "black", &black, &black);
if (rc == 0) {
fprintf(stderr, "XAllocNamedColor - failed to allocated 'black' color.\n");
exit(1);
}
rc = XAllocNamedColor(display, screen_colormap, "white", &white, &white);
if (rc == 0) {
fprintf(stderr, "XAllocNamedColor - failed to allocated 'white' color.\n");
exit(1);
}
/* draw one pixel near each corner of the window */
XDrawPoint(display, win, gc, 5, 5);
XDrawPoint(display, win, gc, 5, height-5);
XDrawPoint(display, win, gc, width-5, 5);
XDrawPoint(display, win, gc, width-5, height-5);
// Do our display. Loop forever because I don't know how to process keystrokes.
// If we start from the center of the display, 0 is to the right (E), 90 is to the
// bottom (S), 180 (W),270 (N). Don't quite know how to "rotate" the "beam" 180 Deg.
// Needs double buffering to remove the flicker.
// I would like to make a separate subroutine eg: DrawRadar( int angle, int distance);
x1=width / 2; //Find center of display.
y1=height / 2;
px=x1; // Previous X and Y
py=y1;
while(1){
for(angle=0; angle < 360; angle++)
{
// Distance set to 150 pixels. Radar returns value up to 3300 mm.
// Will have to scale down.
x2=x1 + cos((angle * M_PI) / 180) * 150; // Must convert to radians.
y2=y1 + sin((angle * M_PI) / 180) * 150; // " " " "
XSetForeground(display, gc, black.pixel); //
XDrawLine(display, win, gc, x1, y1, x2, y2);
px=x2;
py=y2;
XFlush(display); // Display what we've drawn.
usleep(3500); // Wait so eye can see it.
XSetForeground(display, gc, white.pixel); // Rub out the line we just drew.
XDrawLine(display, win, gc, x1, y1, px ,py);
XFlush(display); // Causes flickering but only way at the moment.
XSetForeground(display, gc, black.pixel);
usleep(3500);
}
}
// End. Never get past here.
/* flush all pending requests to the X server. */
XFlush(display);
XSync(display, False);
/* make a delay for a short period. */
sleep(4);
/* close the connection to the X server. */
XCloseDisplay(display);
}
I'm simply trying to draw a moving line without flicker. I understand the concept but am a crap coder. Any help would be appreciated.