/*- * ---------------------------------------------------------------------------- * "THE BEER-WARE LICENSE" (Revision 69): * wrote this file. As long as you retain this notice you * can do whatever you want with this stuff. If we meet some day, and you think * this stuff is worth it, you can buy me a beer in return. -Shteryana Shopova * ---------------------------------------------------------------------------- */ #include #include #include #include "cg.h" enum cg_circle_method { CG_CIRCLE_INLINE = 0, CG_CIRCLE_SIMPLE = 1, CG_CIRCLE_SIMPLE2 = 2, CG_CIRCLE_BRESENHAIM = 3, CG_CIRCLE_MICHENER = 4, CG_CIRCLE_DELTA2 = 5, }; typedef void (*cg_draw_circle_cb) (GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_); static void cg_circle_draw_inline(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_); static void cg_circle_draw_simple(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_); static void cg_circle_draw_simple2(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_); static void cg_circle_draw_bresenhaim(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_); static void cg_circle_draw_michener(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_); static void cg_circle_draw_delta2(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_); static void cg_circle_draw(enum cg_circle_method method); /* Obligatory basic callbacks for the "Circle" menu items. */ void cg_circle_inline(GtkWidget *w, gpointer data) { g_message ("Hello, cg_circle_inline!\n"); cg_circle_draw(CG_CIRCLE_INLINE); } void cg_circle_simple(GtkWidget *w, gpointer data) { g_message ("Hello, cg_circle_simple!\n"); cg_circle_draw(CG_CIRCLE_SIMPLE); } void cg_circle_simple2(GtkWidget *w, gpointer data) { g_message ("Hello, cg_circle_simple2!\n"); cg_circle_draw(CG_CIRCLE_SIMPLE2); } void cg_circle_bresenhaim(GtkWidget *w, gpointer data) { g_message ("Hello, cg_circle_bresenhaim!\n"); cg_circle_draw(CG_CIRCLE_BRESENHAIM); } void cg_circle_michener(GtkWidget *w, gpointer data) { g_message ("Hello, cg_circle_michener!\n"); cg_circle_draw(CG_CIRCLE_MICHENER); } void cg_circle_delta2(GtkWidget *w, gpointer data) { g_message ("Hello, cg_circle_delta2!\n"); cg_circle_draw(CG_CIRCLE_DELTA2); } /* * A global structure to hold the info for the current circle that * is being drawed. */ static struct _cg_circle { gboolean O_set; /* coordinates of center are established */ gint X; /* center point X axis value */ gint Y; /* center point Y axis value */ gint R; /* raduis */ gint Y2; /* second point Y axis value */ gulong button_id; /* button press/release handler id */ gulong motion_id; /* mouse motion handler id */ cg_draw_circle_cb draw_cb; /* the circle draw callback */ } cg_circle; /* Refresh the needed area where changes were made. */ static void cg_circle_drawing_refresh(gint x, gint y, gint R) { GdkRectangle update_area; update_area.x = x - 2 * R; update_area.y = y - 2 * R; update_area.width = 4 * R; update_area.height = 4 * R; gtk_widget_draw(GTK_WIDGET(drawing_area), &update_area); } static gint cg_circle_motion_notify_event(GtkWidget *widget, GdkEventMotion *event) { int x, y; GdkModifierType state; GtkWidget *toplevel; if (event->is_hint) gdk_window_get_pointer (event->window, &x, &y, &state); else { x = event->x; y = event->y; state = event->state; } if (cg_pixmap == NULL) return (TRUE); if (state & GDK_BUTTON1_MASK) { toplevel = gtk_widget_get_toplevel(GTK_WIDGET(drawing_area)); /* Clear previous circle. */ (cg_circle.draw_cb) (cg_pixmap, toplevel->style->white_gc, cg_circle.X, cg_circle.Y, cg_circle.R); cg_circle_drawing_refresh(cg_circle.X, cg_circle.Y, cg_circle.R); } else toplevel = gtk_widget_get_toplevel(GTK_WIDGET(drawing_area)); cg_circle.R = sqrt((x - cg_circle.X) * (x - cg_circle.X) + (y - cg_circle.Y) * (y - cg_circle.Y)); ; if (state & GDK_BUTTON1_MASK || state & GDK_BUTTON3_MASK) { (cg_circle.draw_cb) (cg_pixmap, toplevel->style->fg_gc[GTK_WIDGET_STATE(widget)], cg_circle.X, cg_circle.Y, cg_circle.R); cg_circle_drawing_refresh(cg_circle.X, cg_circle.Y, cg_circle.R); } return (TRUE); } static gint cg_circle_button_release_event(GtkWidget *widget, GdkEventButton *event) { GtkWidget *toplevel; if (cg_pixmap == NULL || (event->button != 1 && event->button != 3)) return (TRUE); /* Unconnect the motion and the button release signals. */ g_signal_handler_disconnect(GTK_OBJECT(drawing_area), cg_circle.motion_id); g_signal_handler_disconnect(GTK_OBJECT(drawing_area), cg_circle.button_id); cg_circle.R = sqrt((event->x - cg_circle.X) * (event->x - cg_circle.X) + (event->y - cg_circle.Y) * (event->y - cg_circle.Y)); toplevel = gtk_widget_get_toplevel(GTK_WIDGET(drawing_area)); (cg_circle.draw_cb)(cg_pixmap, toplevel->style->fg_gc[GTK_WIDGET_STATE(widget)], cg_circle.X, cg_circle.Y, cg_circle.R); cg_circle_drawing_refresh(cg_circle.X, cg_circle.Y, cg_circle.R); return (TRUE); } static gint cg_circle_button_press_event(GtkWidget *widget, GdkEventButton *event) { if (cg_pixmap == NULL || (event->button != 1 && event->button != 3)) return (TRUE); if (!cg_circle.O_set) { cg_circle.X = event->x; cg_circle.Y = event->y; cg_circle.O_set = TRUE; /* Unconnect the button press signal. */ g_signal_handler_disconnect(GTK_OBJECT(drawing_area), cg_circle.button_id); /* Connect the motion and the button release signal handler. */ cg_circle.button_id = g_signal_connect(GTK_OBJECT(drawing_area), "button_release_event", (GtkSignalFunc) cg_circle_button_release_event, NULL); cg_circle.motion_id = g_signal_connect(GTK_OBJECT(drawing_area), "motion_notify_event", (GtkSignalFunc) cg_circle_motion_notify_event, NULL); } return (TRUE); } static void cg_circle_draw(enum cg_circle_method method) { bzero(&cg_circle, sizeof(cg_circle)); switch (method) { case CG_CIRCLE_SIMPLE: cg_circle.draw_cb = cg_circle_draw_simple; break; case CG_CIRCLE_SIMPLE2: cg_circle.draw_cb = cg_circle_draw_simple2; break; case CG_CIRCLE_BRESENHAIM: cg_circle.draw_cb = cg_circle_draw_bresenhaim; break; case CG_CIRCLE_MICHENER: cg_circle.draw_cb = cg_circle_draw_michener; break; case CG_CIRCLE_DELTA2: cg_circle.draw_cb = cg_circle_draw_delta2; break; default: cg_circle.draw_cb = cg_circle_draw_inline; break; } cg_circle.button_id = g_signal_connect(GTK_OBJECT(drawing_area), "button_press_event", (GtkSignalFunc) cg_circle_button_press_event, NULL); } static void cg_circle_draw_inline(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_) { gdk_draw_arc(drawable, gc, FALSE, x_ - R_ * sqrt(2), y_ - R_ * sqrt(2), 2 * R_, 2 * R_, 0, 360 * 64); } void cg_circle_draw_four_symmetric_pts(GdkDrawable *drawable, GdkGC *gc, gint trans_x, gint trans_y, gint x_, gint y_) { /* 1st quarter (+, +) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, x_), CG_CIRCLE_REV_TRANSLATE(trans_y, y_)); /* 2nd quarter (-, +) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, -x_), CG_CIRCLE_REV_TRANSLATE(trans_y, y_)); /* 3rd quarter (-, -) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, -x_), CG_CIRCLE_REV_TRANSLATE(trans_y, -y_)); /* 4th quarter (+, -) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, x_), CG_CIRCLE_REV_TRANSLATE(trans_y, -y_)); } static void cg_circle_draw_eight_symmetric_pts(GdkDrawable *drawable, GdkGC *gc, gint trans_x, gint trans_y, gint x_, gint y_) { /* 1st semi-quarter (+x, +y) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, x_), CG_CIRCLE_REV_TRANSLATE(trans_y, y_)); /* 2st semi-quarter (+y, +x) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, y_), CG_CIRCLE_REV_TRANSLATE(trans_y, x_)); /* 3rd semi-quarter (-x, +y) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, -x_), CG_CIRCLE_REV_TRANSLATE(trans_y, y_)); /* 4th semi-quarter (-y, +x) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, -y_), CG_CIRCLE_REV_TRANSLATE(trans_y, x_)); /* 5th semi-quarter (-x, -y) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, -x_), CG_CIRCLE_REV_TRANSLATE(trans_y, -y_)); /* 6th semi-quarter (-y, -x) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, -y_), CG_CIRCLE_REV_TRANSLATE(trans_y, -x_)); /* 7th semi-quarter (+x, -y) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, x_), CG_CIRCLE_REV_TRANSLATE(trans_y, -y_)); /* 8th semi-quarter (+y, -x) */ gdk_draw_point(drawable, gc, CG_CIRCLE_REV_TRANSLATE(trans_x, y_), CG_CIRCLE_REV_TRANSLATE(trans_y, -x_)); } static void cg_circle_draw_simple(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_) { gdouble y; gint n, y_i, trans_x, trans_y; /* Change to coordinate system with center (x1_, y1_). */ trans_x = x_; trans_y = y_; x_ = y_ = 0; for (n = 0; n <= R_; n++) { y = sqrt(R_ * R_ - n * n); y_i = y; if (y - y_i > 0.5) y_i += 1; cg_circle_draw_four_symmetric_pts(drawable, gc, trans_x, trans_y, n, y_i); } } static void cg_circle_draw_simple2(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_) { gdouble y; gint n, y_i, trans_x, trans_y; /* Change to coordinate system with center (x1_, y1_). */ trans_x = x_; trans_y = y_; x_ = y_ = 0; for (n = 0, y_i = R_; n < y_i; n++) { y = sqrt(R_ * R_ - n * n); y_i = y; if (y - y_i > 0.5) y_i += 1; cg_circle_draw_eight_symmetric_pts(drawable, gc, trans_x, trans_y, n, y_i); } if (n == y_i) { cg_circle_draw_four_symmetric_pts(drawable, gc, trans_x, trans_y, n, y_i); } } static void cg_circle_draw_bresenhaim(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_) { gint x_i, y_i, delta, trans_x, trans_y; /* Change to coordinate system with center (x1_, y1_). */ trans_x = x_; trans_y = y_; x_ = y_ = 0; delta = 2 - 2 * R_; for (x_i = 0, y_i = R_; x_i <= R_ && y_i >= 0; ) { cg_circle_draw_four_symmetric_pts(drawable, gc, trans_x, trans_y, x_i, y_i); /* XXX: shteryana - FIXME! */ if (delta > -y_i) { y_i -= 1; delta += 1 - 2 * y_i; } if (delta <= x_i) { x_i += 1; delta += 1 + 2 * x_i; } } } static void cg_circle_draw_michener(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_) { gint delta, x_i, y_i, trans_x, trans_y; /* Change to coordinate system with center (x1_, y1_). */ trans_x = x_; trans_y = y_; x_ = y_ = 0; delta = 3 - 2 * R_; for (x_i = 0, y_i = R_; x_i < y_i; x_i++) { cg_circle_draw_eight_symmetric_pts(drawable, gc, trans_x, trans_y, x_i, y_i); /* XXX: shteryana - FIXME! */ if (delta >= 0) { delta += 10 + 4 * x_i - 4 * y_i; y_i -= 1; } else delta += 6 + 4 * x_i; } if (x_i == y_i) { cg_circle_draw_four_symmetric_pts(drawable, gc, trans_x, trans_y, x_i, y_i); } } static void cg_circle_draw_delta2(GdkDrawable *drawable, GdkGC *gc, gint x_, gint y_, gint R_) { gint delta, delta_H, delta_D, x_i, y_i, trans_x, trans_y; /* Change to coordinate system with center (x1_, y1_). */ trans_x = x_; trans_y = y_; x_ = y_ = 0; delta = 1 - R_; delta_H = 3; delta_D = 5 - 2 * R_; for (x_i = 0, y_i = R_; x_i < y_i; x_i++) { cg_circle_draw_eight_symmetric_pts(drawable, gc, trans_x, trans_y, x_i, y_i); /* XXX: shteryana - FIXME! */ if (delta < 0) { delta += delta_H; delta_H += 2; delta_D += 2; } else { delta += delta_D; delta_H += 2; delta_D += 4; y_i -= 1; } } if (x_i == y_i) { cg_circle_draw_four_symmetric_pts(drawable, gc, trans_x, trans_y, x_i, y_i); } }