I botched together the following code to do a simple rotating radar display.
Q1) How can I eliminate the flicker of the line being drawn and then drawn over. Can I use double buffering somehow ?
Q2) How can I get Mouse and Keyborad 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 Deg. I also cant 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.
Any help would be appreciated.
Pls don't jump on me. Just trying to learn.
Here is my code. I used a tutorial as a base and kind of guessed my way through.
CODE:
/*
* 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 seperate 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);
}
Simply trying to draw a moving line without flicker. I understand the concept but am a crap coder. Any help would be appreciated.
Thanks, John.