[GRASS-dev] Modules

Glynn Clements glynn at gclements.plus.com
Wed Feb 21 23:56:57 EST 2007


Glynn Clements wrote:

> > > It's looking as if the most practical replacement is going to be to
> > > take the existing v.digit, and replace R_*, D_* and Tcl_* with a real
> > > GUI toolkit.
> > 
> > To this end, I've started refactoring v.digit in the hope of making it
> > easier to use a conventional GUI toolkit.
> > 
> > So far, I've modified attr.c and line.c, corresponding to the
> > following "tools":
> > 
> > 	copy cats
> > 	display attributes
> > 	display cats
> > 	new line
> > 	edit line
> > 	move line
> > 	delete line
> 
> I've now modified the remaining tools, namely:
> 
> 	split line
> 	add vertex
> 	move vertex
> 	remove vertex
> 	zoom pan
> 	zoom window
> 
> All usage of R_get_location_with_* is now localised to a single
> function.

The next bit is somewhat more radical, so I haven't committed it to
CVS yet.

The attached patch completely eliminates the use of the raster library
and display drivers by v.digit, in favour of a Tk canvas widget. The
patch needs to be applied from within the v.digit directory.

Testing and comments would be appreciated.

-- 
Glynn Clements <glynn at gclements.plus.com>

-------------- next part --------------
Index: c_face.c
===================================================================
RCS file: /grassrepository/grass6/vector/v.digit/c_face.c,v
retrieving revision 1.17
diff -u -r1.17 c_face.c
--- c_face.c	4 May 2006 19:37:26 -0000	1.17
+++ c_face.c	22 Feb 2007 04:19:33 -0000
@@ -20,7 +20,7 @@
 c_cancel ( ClientData cdata, Tcl_Interp *interp, int argc, char *argv[])
 {
     G_debug (3, "c_cancel()");
-    R_set_cancel ( 1 );
+    cancel_tool ();
     Tool_next = TOOL_NOTHING;
     return TCL_OK;
 }
@@ -90,7 +90,7 @@
     G_debug (2, "  Tool_next = %d", Tool_next);
     
     /* Stop running if any */
-    R_set_cancel ( 1 );
+    cancel_tool ();
     
     return TCL_OK;
 }
Index: display.c
===================================================================
RCS file: /grassrepository/grass6/vector/v.digit/display.c,v
retrieving revision 1.12
diff -u -r1.12 display.c
--- display.c	18 Feb 2007 20:16:33 -0000	1.12
+++ display.c	22 Feb 2007 04:19:33 -0000
@@ -3,6 +3,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <time.h> 
+#include <math.h> 
 #include <grass/gis.h>
 #include <grass/Vect.h>
 #include <grass/raster.h>
@@ -24,13 +25,70 @@
     
     G_debug (2, "display_points()");
 
-    R_line_width ( var_geti( VAR_LINEWIDTH ) );
-    for(i=1; i < Points->n_points; i++) {
-        G_plot_line ( Points->x[i-1], Points->y[i-1], Points->x[i], Points->y[i]);
-    }
-    R_line_width ( 0 );
-   
-    if ( flsh ) R_flush();
+    driver_line_width ( var_geti( VAR_LINEWIDTH ) );
+    for(i=1; i < Points->n_points; i++)
+	driver_plot_line(Points->x[i-1], Points->y[i-1],
+		  Points->x[i  ], Points->y[i  ]);
+    driver_line_width( 0 );
+}
+
+static int trans ( double *x, double *y, int n_points, double angle, double scale, 
+                     double xc, double yc ) {
+    int i;
+    double r, a;
+
+    for ( i = 0; i < n_points; i++) {
+	r = scale * hypot ( x[i], y[i] );
+	a = atan2 ( y[i], x[i] );
+	a += angle;   
+	x[i] = r * cos(a) + xc;
+	y[i] = r * sin(a) + yc;
+    }
+
+    return 1;
+}
+
+/* Plot icon */
+static void plot_icon(double xc, double yc, int type, double angle, double scale) 
+{
+    int    i, np = 0;
+    double x[10], y[10];
+    
+    
+    /* diamond, box */
+    switch(type) {
+	case G_ICON_CROSS: 
+	    x[0] = -0.5; y[0] =  0.0;
+	    x[1] =  0.5; y[1] =  0.0;
+	    x[2] =  0.0; y[2] = -0.5;
+	    x[3] =  0.0; y[3] =  0.5;
+	    np = 4;
+	    break;
+	case G_ICON_BOX: 
+	     G_debug (1, "box");
+	    x[0] = -0.5; y[0] = -0.5;
+	    x[1] =  0.5; y[1] = -0.5;
+	    x[2] =  0.5; y[2] = -0.5;
+	    x[3] =  0.5; y[3] =  0.5;
+	    x[4] =  0.5; y[4] =  0.5;
+	    x[5] = -0.5; y[5] =  0.5;
+	    x[6] = -0.5; y[6] =  0.5;
+	    x[7] = -0.5; y[7] = -0.5;
+	    np = 8;
+	    break;
+	case G_ICON_ARROW: 
+	    x[0] = -1; y[0] =  0.5;
+	    x[1] =  0; y[1] =  0.0;
+	    x[2] = -1; y[2] = -0.5;
+	    x[3] =  0; y[3] =  0.0;
+	    np = 4;
+	    break;
+    }
+    
+    trans ( x, y, np, angle, scale, xc, yc);
+	    
+    for ( i = 0; i < np; i += 2 )
+        driver_plot_line(x[i], y[i], x[i+1], y[i+1]);
 }
 
 /* Display icon */
@@ -38,11 +96,9 @@
 {
     G_debug (2, "display_icon()");
 
-    R_line_width ( var_geti( VAR_LINEWIDTH ) );
-    G_plot_icon(x, y, icon, angle, Scale * size);
-    R_line_width ( 0 );
-
-    if ( flsh ) R_flush();
+    driver_line_width ( var_geti( VAR_LINEWIDTH ) );
+    plot_icon(x, y, icon, angle, Scale * size);
+    driver_line_width ( 0 );
 }
 
 /* Display vector line 
@@ -91,7 +147,6 @@
         if ( !Vect_line_alive ( &Map, line ) ) continue;
         display_line ( line, symb, 0 );
    }
-   R_flush();
 }
 
 /* Display node, color may be given but shape and size is read from symbology table,
@@ -130,7 +185,6 @@
 	if ( NodeSymb[node] == SYMB_NODE_0 ) continue;
 	display_node ( node, symb, 0);
     }
-    R_flush();
 }
 
 /* Display vector map */
@@ -155,7 +209,6 @@
 	if ( !Symb[symb].on ) continue;
 	display_line ( i , SYMB_DEFAULT, 0 );
     }
-    R_flush();
     
     /* Nodes: first nodes with more than 1 line, then nodes with only 1 line, 
      *   so that dangles are not hidden, and nodes without lines (points, 
@@ -169,7 +222,6 @@
 	    if ( NodeSymb[i] != SYMB_NODE_2 ) continue;
 	    display_node(i, NodeSymb[i], 0);
 	}
-	R_flush();
     }
 
     if ( Symb[SYMB_NODE_1].on ) {
@@ -180,34 +232,28 @@
 	    if ( NodeSymb[i] != SYMB_NODE_1 ) continue;
 	    display_node(i, NodeSymb[i], 0);
         }
-	R_flush();
     }
 }
 
 /* Display bacground */
 void display_bg ( void )
 {
+#if 0
     int i;
     
     G_debug (2, "display_bg()");
 
-    driver_close();
     for(i=0; i < nbgcmd; i++) {
 	if ( Bgcmd[i].on ) 
 	    system ( Bgcmd[i].cmd );
     }
-    driver_open();
+#endif
 }
 
 /* Erase */
 void display_erase ( void )
 {
-    char command[128];
-    
-    driver_close();
-    sprintf(command, "d.erase color=white");
-    system( command ); /* It does everything and command is registered */
-    driver_open();
+    Tcl_Eval(Toolbox, ".screen.canvas delete all");
 
     /* As erase must be run after each zoom by v.digit, here is good place to reset plot.
     *  Other such place is display_map() */
Index: driver.c
===================================================================
RCS file: /grassrepository/grass6/vector/v.digit/driver.c,v
retrieving revision 1.6
diff -u -r1.6 driver.c
--- driver.c	18 Feb 2007 20:16:33 -0000	1.6
+++ driver.c	22 Feb 2007 04:19:33 -0000
@@ -5,57 +5,97 @@
 #include "global.h"
 #include "proto.h"
 
+static char color[16];
+static int width;
+
+void driver_rgb_color(int r, int g, int b)
+{
+    sprintf(color, "#%02x%02x%02x", r, g, b);
+}
+
+void driver_line_width(int w)
+{
+    width = w ? w : 1;
+}
+
+static int round(double x)
+{
+    return (int) floor(x + 0.5);
+}
+
+void driver_plot_line(double x1, double y1, double x2, double y2)
+{
+    char buf[1024];
+
+    sprintf(buf, ".screen.canvas create line %d %d %d %d -width %d -fill %s",
+	    round(D_u_to_d_col(x1)),
+	    round(D_u_to_d_row(y1)),
+	    round(D_u_to_d_col(x2)),
+	    round(D_u_to_d_row(y2)),
+	    width, color);
+
+    Tcl_Eval(Toolbox, buf);
+}
+
+static void get_window(int *t, int *b, int *l, int *r)
+{
+    Tcl_Eval(Toolbox, "list 0 [.screen.canvas cget -width] 0 [.screen.canvas cget -height]");
+    sscanf(Toolbox->result, "%d %d %d %d", t, b, l, r);
+}
+
+static void setup(void)
+{
+    struct Cell_head region;
+    int t, b, l, r;
+
+    get_window(&t, &b, &l, &r);
+
+    /* Set the map region associated with graphics frame */
+    G_get_set_window(&region);
+    if(G_set_window(&region) < 0)
+	G_fatal_error ("Invalid graphics coordinates");
+
+    /* Determine conversion factors */
+    if (D_do_conversions(&region, t, b, l, r))
+	G_fatal_error("Error calculating graphics-region conversions") ;
+}
 
 int driver_refresh (void)
 {
-    D_setup (0);
-    G_setup_plot (D_get_d_north(), D_get_d_south(), D_get_d_west(), D_get_d_east(),
-		                  D_move_abs, D_cont_abs);
+    setup();
     return 1;
 }
-    
+   
 int driver_open (void)
 {
     int top, bot, left, right;
     double n, s, e, w;
     
-    G_debug (5, "driver_open()");
-    if (R_open_driver() != 0) G_fatal_error ("No graphics device selected");
-    G_debug (5, " -> opened");
-
-    D_setup (0);
-    D_get_screen_window ( &top, &bot, &left, &right); 
-    G_debug (2, "top = %d bot = %d, left = %d right = %d", top, bot, left, right);
+    Tcl_Eval(Toolbox,
+	     "if {![winfo exists .screen]} {\n"
+	     "	toplevel .screen\n"
+	     "	canvas .screen.canvas -background white -width 640 -height 480\n"
+	     "	pack .screen.canvas -fill both -expand yes\n"
+	     "	wm withdraw .screen.canvas\n"
+	     "	wm deiconify .screen.canvas\n"
+	     "	update\n"
+	     "}");
+
+    setup();
+    get_window ( &top, &bot, &left, &right); 
+
+    n = D_d_to_u_row(D_get_d_north());
+    s = D_d_to_u_row(D_get_d_south());
+    w = D_d_to_u_col(D_get_d_west());
+    e = D_d_to_u_col(D_get_d_east());
 
-    
-    G_debug (2, "n = %f s = %f, w = %f e = %f", D_get_d_north(), D_get_d_south(), D_get_d_west(), D_get_d_east() );
-    n = D_d_to_u_row ( D_get_d_north() ); 
-    s = D_d_to_u_row ( D_get_d_south() ); 
-    w = D_d_to_u_col ( D_get_d_west() );
-    e = D_d_to_u_col (  D_get_d_east() );
-    G_debug (2, "n = %f s = %f, w = %f e = %f", n, s, w, e );
-    
     Scale = (n - s) / ( D_get_d_south() - D_get_d_north() );
-    G_debug (2, "Scale = %f", Scale);
-    /*
-    Xscale = ( GRegion.east - GRegion.west ) / ( right - left );
-    Yscale = ( GRegion.north - GRegion.south ) / ( top - bot );
-
-    G_debug (2, "Xscale = %f Yscale = %f", Xscale, Yscale);
-    */
-    G_setup_plot (D_get_d_north(), D_get_d_south(), D_get_d_west(), D_get_d_east(),
-                  D_move_abs, D_cont_abs);
-    
-    D_set_clip_window_to_map_window ();
     
     return 1;
 }
 
 int driver_close (void)
 {
-    G_debug (5, "driver_close()");
-    R_close_driver();
-    G_debug (5, " -> closed");
     return 1;
 }
 
Index: main.c
===================================================================
RCS file: /grassrepository/grass6/vector/v.digit/main.c,v
retrieving revision 1.25
diff -u -r1.25 main.c
--- main.c	19 Aug 2006 12:52:24 -0000	1.25
+++ main.c	22 Feb 2007 04:19:35 -0000
@@ -71,6 +71,20 @@
     var_seti ( VAR_SNAP_MODE, SNAP_SCREEN );
     var_seti ( VAR_SNAP_SCREEN, 10 );
     var_setd ( VAR_SNAP_MAP, 10 );
+
+    /* Display the map */
+    symb_init ();
+    G_get_window(&window);
+    driver_open ();
+    display_erase ();
+    display_bg ();
+    display_map ();
+    driver_close ();
+
+    G_get_window(&window);
+
+    /* Set tool */
+    Tool_next = TOOL_NEW_POINT;
     
     G_debug (3, "Starting toolbox.tcl");
 
@@ -138,13 +152,6 @@
     G_debug (1, "Region: N = %f S = %f E = %f W = %f", GRegion.north,
 	GRegion.south, GRegion.east, GRegion.west);
     
-    /* Check driver */
-    if (R_open_driver() != 0)
-	G_fatal_error(_("No graphics device selected"));
-    R_close_driver();
-
-    G_debug (1, "Driver opened");
-    
     /* Open map */
     mapset = G_find_vector2 (map_opt->answer, G_mapset()); 
     if ( mapset == NULL ) {
@@ -174,20 +181,6 @@
     symb_lines_init (); 
     symb_nodes_init (); 
 
-    /* Display the map */
-    symb_init ();
-    G_get_window(&window);
-    driver_open ();
-    display_erase ();
-    display_bg ();
-    display_map ();
-    driver_close ();
-
-    G_get_window(&window);
-
-    /* Set tool */
-    Tool_next = TOOL_NEW_POINT;
-
     G_debug (3, "Starting Tk_Main.");
     
     /* Open toolbox */
@@ -211,10 +204,7 @@
 	G_message(_("Region restored to original extent."));
 
     /* clear the screen */
-    R_open_driver();
-    D_setup(TRUE);
-    D_clear_window();
-    R_close_driver();
+    Tcl_Eval(Toolbox, ".screen.canvas delete all");
 
     return 1;
 }
Index: proto.h
===================================================================
RCS file: /grassrepository/grass6/vector/v.digit/proto.h,v
retrieving revision 1.14
diff -u -r1.14 proto.h
--- proto.h	21 Feb 2007 22:15:41 -0000	1.14
+++ proto.h	22 Feb 2007 04:19:35 -0000
@@ -2,6 +2,9 @@
 int driver_open (void); 
 int driver_close (void); 
 int driver_refresh (void);
+void driver_rgb_color(int r, int g, int b);
+void driver_line_width(int w);
+void driver_plot_line(double x1, double y1, double x2, double y2);
 
 /* Miscellaneous */
 int update (int, int);
@@ -130,3 +133,4 @@
 	    tool_func_update *update,
 	    tool_func_end *end,
 	    void *closure);
+void cancel_tool(void);
Index: symb.c
===================================================================
RCS file: /grassrepository/grass6/vector/v.digit/symb.c,v
retrieving revision 1.6
diff -u -r1.6 symb.c
--- symb.c	11 Feb 2007 20:26:19 -0000	1.6
+++ symb.c	22 Feb 2007 04:19:35 -0000
@@ -110,7 +110,7 @@
 {
     G_debug ( 2, "set color to symb %d: %d %d %d", code, Symb[code].r, Symb[code].g, Symb[code].b );
     
-    R_RGB_color ( Symb[code].r, Symb[code].g, Symb[code].b);
+    driver_rgb_color ( Symb[code].r, Symb[code].g, Symb[code].b);
 }
 
 
Index: toolbox.tcl
===================================================================
RCS file: /grassrepository/grass6/vector/v.digit/toolbox.tcl,v
retrieving revision 1.25
diff -u -r1.25 toolbox.tcl
--- toolbox.tcl	9 Oct 2006 01:46:10 -0000	1.25
+++ toolbox.tcl	22 Feb 2007 04:19:35 -0000
@@ -25,6 +25,47 @@
 set prompt_right [G_msg "Right mouse button"]
 set coor ""
 
+proc get_w_point {} {
+    global get_done
+    set get_done {}
+    bind .screen.canvas <ButtonPress> { set get_done "%x %y %b" }
+    bind .screen.canvas <Motion> { set get_done "%x %y -1" }
+    tkwait variable get_done
+    return $get_done
+}
+
+proc get_update_line {ox oy x y} {
+    .screen.canvas delete active
+    .screen.canvas create line $ox $oy $x $y -tags active -dash {4 4}
+}
+
+proc get_w_line {ox oy} {
+    global get_done get_x get_y
+    set get_done {}
+    set get_x $ox
+    set get_y $oy
+    bind .screen.canvas <ButtonPress> { set get_done "%x %y %b" }
+    bind .screen.canvas <Motion> [subst { get_update_line $ox $oy %x %y ; set get_done "%x %y -1" }]
+    tkwait variable get_done
+    return $get_done
+}
+
+proc get_update_box {ox oy x y} {
+    .screen.canvas delete active
+    .screen.canvas create line $ox $oy $ox $y $x $y $x $oy $ox $oy -tags active -dash {4 4}
+}
+
+proc get_w_box {ox oy} {
+    global get_done get_x get_y
+    set get_done false
+    set get_x $ox
+    set get_y $oy
+    bind .screen.canvas <ButtonPress> { set get_done "%x %y %b" }
+    bind .screen.canvas <Motion> [subst { get_update_box $ox $oy %x %y ; set get_done "%x %y -1" }]
+    tkwait variable get_done
+    return $get_done
+}
+
 # GVariable stores variables by key, this variables are (should be) synchronized with
 # variables in Variable array in C (synchronization should be done somehow better). Key is
 # 'name' in VAR structure in C. Variables are initialized by var_init() on startup.
Index: util.c
===================================================================
RCS file: /grassrepository/grass6/vector/v.digit/util.c,v
retrieving revision 1.4
diff -u -r1.4 util.c
--- util.c	21 Feb 2007 22:15:41 -0000	1.4
+++ util.c	22 Feb 2007 04:19:35 -0000
@@ -47,22 +47,62 @@
     mode = m;
 }
 
+static int cancel;
+
+void cancel_tool(void)
+{
+    cancel = 1;
+}
+
 void get_location(int *sxn, int *syn, int *button)
 {
-    R_set_update_function (update);
+    char buf[1024];
+
+    cancel = 0;
+
+    Tcl_Eval(Toolbox, ".screen.canvas configure -cursor crosshair");
 
     switch (mode)
     {
     case MOUSE_POINT:
-	R_get_location_with_pointer (sxn, syn, button);
+	while (!cancel)
+	{
+	    Tcl_Eval(Toolbox, "get_w_point");
+	    sscanf(Toolbox->result, "%d %d %d", sxn, syn, button);
+	    if (*button >= 0)
+		break;
+	    update(*sxn, *syn);
+	}
 	break;
     case MOUSE_LINE:
-	R_get_location_with_line (sxo, syo, sxn, syn, button); 
+	while (!cancel)
+	{
+	    sprintf(buf, "get_w_line %d %d", sxo, syo);
+	    Tcl_Eval(Toolbox, buf);
+	    sscanf(Toolbox->result, "%d %d %d", sxn, syn, button);
+	    if (*button >= 0)
+		break;
+	    update(*sxn, *syn);
+	}
 	break;
     case MOUSE_BOX:
-	R_get_location_with_box (sxo, syo, sxn, syn, button); 
+	while (!cancel)
+	{
+	    sprintf(buf, "get_w_box %d %d", sxo, syo);
+	    Tcl_Eval(Toolbox, buf);
+	    sscanf(Toolbox->result, "%d %d %d", sxn, syn, button);
+	    if (*button >= 0)
+		break;
+	    update(*sxn, *syn);
+	}
 	break;
     }
+
+    Tcl_Eval(Toolbox, ".screen.canvas configure -cursor {}");
+    Tcl_Eval(Toolbox, ".screen.canvas delete active");
+
+    if (cancel)
+	*button = 0;
 }
 
 int do_tool(tool_func_begin *begin, tool_func_update *update, tool_func_end *end, void *closure)


More information about the grass-dev mailing list