Ilya Zakharevich on Wed, 7 Mar 2001 19:18:39 -0500


[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[PATCH] gnuplot plotting


This patch:

  a) removes warnings for a compile with -DDYNAMIC_PLOTTING;

  b) adds support for two new types of DYNAMIC_PLOTTING which may be
     usable in the "plain" GP (the old type was easy to use from a capable
     runtime only, such as Perl in Math::Pari);

  c) You could have get "stuck" if you mistyped the name of the terminal
     in plotterm(): after this plotterm() would like to reset() the "previous"
     terminal which is not in working order ==> plotterm() would fail;

When I teach Perl building the DLLs needed for the new types in (b),
I will support these variants of the build in Configure.  Right now,
given a Gnuplot-engine DLL which exports get_term_ftable() entry point,
one can either

 1) define DYNAMIC_PLOTTING_STATIC_LINK, and link with -lname-of-dll,

 2) or define DYNAMIC_PLOTTING_RUNTIME_LINK=\"name-of-dll\", and
    gp will transparently link at runtime when plotting is requested.

Note that (2) does not require any additional software present when
gp is compiled (except dlopen()); thus it may safely replace "none"
type of graphic.

Ilya

--- ./src/graph/Gnuplot.h-pre	Fri Nov  3 16:00:24 2000
+++ ./src/graph/Gnuplot.h	Tue Mar  6 22:47:02 2001
@@ -161,10 +161,9 @@ char term_options[200] = "";
 #define AXIS_ARRAY_SIZE 10
 #define DATATYPE_ARRAY_SIZE 10
 
-extern double min_array[], max_array[], base_array[], log_base_array[];
+extern double base_array[], log_base_array[];
 extern TBOOLEAN log_array[];
 /* graphics.c */
-extern int xleft, xright, ybot, ytop;
 extern TBOOLEAN is_3d_plot;
 
 double min_array[AXIS_ARRAY_SIZE], max_array[AXIS_ARRAY_SIZE], base_array[AXIS_ARRAY_SIZE], log_base_array[AXIS_ARRAY_SIZE];
@@ -362,6 +361,10 @@ typedef void (*TSET_FP)(char *s);
 typedef void (*TST_END_FP)(void);
 typedef void (*SET_SIZES_t)(double x, double y);
 typedef double (*GET_SIZES_t)(int flag);
+typedef void (*SET_MOUSE_FEEDBACK_RECTAGLE_t)(int term_xmin, int term_xmax, 
+			     int term_ymin, int term_ymax,
+			     double plot_xmin, double plot_xmax,
+			     double plot_ymin, double plot_ymax);
 
 struct t_ftable {
   int loaded;
@@ -370,13 +373,16 @@ struct t_ftable {
   SET_SIZES_t set_sizesp;
   GET_SIZES_t get_sizesp;
   TST_END_FP term_funcs[TTABLE_COUNT];
+  SET_MOUSE_FEEDBACK_RECTAGLE_t mouse_feedback_func;
 };
 
 #ifdef DYNAMIC_PLOTTING			/* Can load plotting DLL later */
 
+int
 UNKNOWN_null()
 {
     croak("gnuplot-like plotting environment not loaded yet");
+    return 0;
 }
 
 static void myterm_table_not_loaded_v(void);
@@ -384,7 +390,10 @@ static void myterm_table_not_loaded(char
 static int myterm_table_not_loaded_u();
 static void myterm_table_not_loaded_vdd(double x, double y);
 static double myterm_table_not_loaded_di(int flag);
-
+static void myterm_table_not_loaded_v4i4d(int term_xmin, int term_xmax, 
+			     int term_ymin, int term_ymax,
+			     double plot_xmin, double plot_xmax,
+			     double plot_ymin, double plot_ymax);
 #if 0
 static int ftable_warned;
 static void
@@ -403,7 +412,8 @@ static struct t_ftable my_term_ftable = 
 	&myterm_table_not_loaded_di,
 	{&myterm_table_not_loaded_v, &myterm_table_not_loaded_v, 
 	 &myterm_table_not_loaded_v, &myterm_table_not_loaded_v,
-	 &myterm_table_not_loaded_v, &myterm_table_not_loaded_v}
+	 &myterm_table_not_loaded_v, &myterm_table_not_loaded_v},
+	myterm_table_not_loaded_v4i4d
 };
 
 static struct t_ftable *my_term_ftablep = &my_term_ftable;
@@ -434,6 +444,7 @@ static double
 myterm_table_not_loaded_di(int flag)
 {
   myterm_table_not_loaded_v();
+  return 0;			/* NOT REACHED */
 }
 
 static int
@@ -443,6 +454,14 @@ myterm_table_not_loaded_u()
   return 0;
 }
 
+void myterm_table_not_loaded_v4i4d(int term_xmin, int term_xmax, 
+			     int term_ymin, int term_ymax,
+			     double plot_xmin, double plot_xmax,
+			     double plot_ymin, double plot_ymax)
+{
+  myterm_table_not_loaded_v();
+}
+
 #  define change_term		(*my_term_ftablep->change_term_p)
 #  define term_set_output	(*my_term_ftablep->term_set_outputp)
 #  define term_start_plot	(*my_term_ftablep->term_funcs[TTABLE_STARTPLOT])
@@ -453,6 +472,7 @@ myterm_table_not_loaded_u()
 #  define list_terms		(*my_term_ftablep->term_funcs[TTABLE_LIST])
 #  define plotsizes_scale	(*my_term_ftablep->set_sizesp)
 #  define plotsizes_scale_get	(*my_term_ftablep->get_sizesp)
+#  define set_mouse_feedback_rectangle	(*my_term_ftablep->mouse_feedback_func)
 
 #  define scaled_xmax()	((int)termprop(xmax)*plotsizes_scale_get(0))
 #  define scaled_ymax()	((int)termprop(ymax)*plotsizes_scale_get(1))
@@ -468,6 +488,7 @@ my_change_term(char*s,int l)
     return term = (struct termentry *)(*my_term_ftablep->change_term_p)(s,l);
 }
 
+#if 0
 static struct termentry dummy_term_tbl[] = {
     {"unknown", "Unknown terminal type - not a plotting device",
 	  100, 100, 1, 1,
@@ -477,6 +498,7 @@ static struct termentry dummy_term_tbl[]
      UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, 0,
 	  UNKNOWN_null, UNKNOWN_null, UNKNOWN_null, UNKNOWN_null},
 };
+#endif
 
 #define set_term_funcp(change_p, term_p) set_term_funcp2((change_p), 0)
 /* #define set_term_funcp3(change_p, term_p, tchange) \
@@ -508,9 +530,27 @@ set_term_ftable(struct t_ftable *p)
   my_term_ftablep = p;
 }
 
+extern struct t_ftable *get_term_ftable();
+
 #else /* !DYNAMIC_PLOTTING */
 
 extern struct termentry term_tbl[];
+extern double min_array[], max_array[];
+extern int xleft, xright, ybot, ytop;
+
+void
+mys_mouse_feedback_rectangle(int term_xmin, int term_xmax, 
+			     int term_ymin, int term_ymax,
+			     double plot_xmin, double plot_xmax,
+			     double plot_ymin, double plot_ymax)
+{
+  xleft = term_xmin, xright = term_xmax;
+  ybot = term_ymin, ytop = term_ymax;
+  min_array[FIRST_X_AXIS] = min_array[SECOND_X_AXIS] = plot_xmin;
+  max_array[FIRST_X_AXIS] = max_array[SECOND_X_AXIS] = plot_xmax;
+  min_array[FIRST_Y_AXIS] = min_array[SECOND_Y_AXIS] = plot_ymin;
+  max_array[FIRST_Y_AXIS] = max_array[SECOND_Y_AXIS] = plot_ymax;
+}
 
 #  define my_change_term	change_term
 #  define my_term_tbl		term_tbl
@@ -534,13 +574,13 @@ struct t_ftable my_term_ftable =
 	1, (FUNC_PTR)&change_term, &term_set_output,
 	&plotsizes_scale, &plotsizes_get,
 	{&term_start_plot, &term_end_plot, 
-	 &term_start_multiplot, &term_end_multiplot, &term_init, &list_terms}
+	 &term_start_multiplot, &term_end_multiplot, &term_init, &list_terms},
+	&mys_mouse_feedback_rectangle
 };
 
 struct t_ftable *get_term_ftable()	{ SET_OUTFILE; return &my_term_ftable; }
 void set_term_ftable()	{ SET_OUTFILE; }
 
-
 void
 set_term_funcp3(FUNC_PTR change_p, void *term_p, TSET_FP tchange)
 {
@@ -564,8 +604,35 @@ set_term_funcp3(FUNC_PTR change_p, void 
 void
 v_set_term_ftable(void *a) { set_term_ftable((struct t_ftable*)a); }
 
+typedef void (*set_term_ftable_t)(struct t_ftable *p);
+typedef struct t_ftable *(get_term_ftable_t)(void);
+
+extern get_term_ftable_t *get_term_ftable_get(void);
+
+static int shim_set;
+
 void
-setup_gpshim(void) { SET_OUTFILE; }
+setup_gpshim(void) {
+#if 0
+  if (shim_set++)
+    return;
+#endif
+
+  if (!shim_set++) {
+#ifdef DYNAMIC_PLOTTING_RUNTIME_LINK
+    get_term_ftable_t *f = get_term_ftable_get(); /* Resolve the getter */
+
+    if (f)
+	v_set_term_ftable(f());			/* Get the external table */
+#endif
+
+#ifdef DYNAMIC_PLOTTING_STATIC_LINK
+    void *a = get_term_ftable();		/* Get the external one */
+    v_set_term_ftable(get_term_ftable());
+#endif
+  }
+  SET_OUTFILE;
+}
 
 #ifdef SET_OPTIONS_FROM_STRING
 /* This sets the tokens for the options */
@@ -653,10 +720,10 @@ set_options_from(char *s)
 
 #ifdef GNUPLOT_OUTLINE_STDOUT
 int
-StartOutput() {}
+StartOutput() { return 0; }
 
 int
-EndOutput() {}
+EndOutput() { return 0; }
 
 int
 OutLine(char *s)
--- ./src/graph/plotgnuplot.c-pre	Fri Nov  3 16:00:24 2000
+++ ./src/graph/plotgnuplot.c	Tue Mar  6 22:59:08 2001
@@ -56,31 +56,22 @@ rectdraw0(long *w, long *x, long *y, lon
   for(i=0;i<lw;i++) {
       e=rectgraph[w[i]];
       if (RHasGraph(e)) {
-	  double t;
-
-	  xleft = x[i]; xright = xleft + RXsize(e) - 1;
-	  ytop = w_height - 1 - y[i]; ybot = ytop - (RYsize(e) - 1);
-	  t = (0 - RXshift(e))/RXscale(e);
-	  min_array[FIRST_X_AXIS] = min_array[SECOND_X_AXIS] = t;
-	  t = (RXsize(e) - 1 - RXshift(e))/RXscale(e);
-	  max_array[FIRST_X_AXIS] = max_array[SECOND_X_AXIS] = t;
-	  t = (RYsize(e) - 1 - RYshift(e))/RYscale(e);
-	  min_array[FIRST_Y_AXIS] = min_array[SECOND_Y_AXIS] = t;
-	  t = (0 - RYshift(e))/RYscale(e);
-	  max_array[FIRST_Y_AXIS] = max_array[SECOND_Y_AXIS] = t;
+	  set_mouse_feedback_rectangle(
+		x[i], x[i] + RXsize(e) - 1,
+		w_height - 1 - y[i] - (RYsize(e) - 1), w_height - 1 - y[i],
+		(0 - RXshift(e))/RXscale(e),
+		(RXsize(e) - 1 - RXshift(e))/RXscale(e),
+		(RYsize(e) - 1 - RYshift(e))/RYscale(e),
+		(0 - RYshift(e))/RYscale(e)
+	  );
 	  seen_graph = 1;
 	  break;
       }
   }
-  if (!seen_graph) {			/* Put some reasonable values */
-      xleft = 0; xright = w_width - 1;
-      ybot  = 0; ytop   = w_height - 1;
-      min_array[FIRST_X_AXIS] = min_array[SECOND_X_AXIS] = 0;
-      max_array[FIRST_X_AXIS] = max_array[SECOND_X_AXIS] = 0;
-      min_array[FIRST_Y_AXIS] = min_array[SECOND_Y_AXIS] = 0;
-      max_array[FIRST_Y_AXIS] = max_array[SECOND_Y_AXIS] = 0;
-  }
-  
+  if (!seen_graph)			/* Put some reasonable values */
+	  set_mouse_feedback_rectangle(	0, w_width - 1,	0, w_height - 1,
+					0, 0, 0, 0);
+
 #if 0
   graphics();				/* Switch on terminal. */
 #else
@@ -209,7 +200,6 @@ PARI_get_plot(long fatal)
   if (pari_plot.init) {
     return;
   }
-  setup_gpshim();
   term_set( DEF_TERM );
 }
 
@@ -219,6 +209,7 @@ term_set(char *s)
 {
   char *t, *size = NULL;
   double x, y;
+  static int had_error;
 
   setup_gpshim();
   if (*s == 0)
@@ -231,16 +222,18 @@ term_set(char *s)
   while (*t && !(*t == ' ' || *t == '\t' || *t == '\n' || *t == '='))
 	t++;
   if ((t-s) > PLOT_NAME_LEN)
-      err(talker,"too long name \"%s\"for terminal", s);
-  if (*pari_plot.name
-      && (strlen(pari_plot.name) != t - s	/* Why this? */
+      err(talker,"name \"%s\" for terminal too long", s);
+  if (*pari_plot.name && !had_error
+      && (strlen(pari_plot.name) != t - s /* As strcmp() without \0 at end */
 	  || (strncmp(pari_plot.name, s, t-s) != 0)) )
 	reset();
   strncpy(pari_plot.name,s,t-s);
   pari_plot.name[t-s] = '\0';
 
+  had_error = 1;
   if (!termset( pari_plot.name ))
       err(talker,"error setting terminal \"%s\"", pari_plot.name);
+  had_error = 0;
 
   if (*t == '=') {
     size = ++t;
@@ -306,3 +299,34 @@ set_pointsize(double d) 
     if (pari_plot.init)
 	setpointsize(d);
 }
+
+#ifdef DYNAMIC_PLOTTING_RUNTIME_LINK
+#include <dlfcn.h>
+
+get_term_ftable_t *
+get_term_ftable_get(void) /* Establish runtime link with gnuplot engine */
+{
+    char *s = getenv("GNUPLOT_DRAW_DLL"), buf[4096];
+    void *h, *f;
+    int mode = RTLD_LAZY;
+
+#ifdef RTLD_GLOBAL
+	mode |= RTLD_GLOBAL;
+#endif
+
+    if (!s)
+	s = DYNAMIC_PLOTTING_RUNTIME_LINK;
+    h = dlopen(s, mode);
+    if (!h) {
+	sprintf(buf,"Can't load Gnuplot drawing engine from '%s': %s", s, dlerror());
+	croak(buf);
+	return 0;
+    }
+    f = dlsym(h, "get_term_ftable");
+    if (f)
+	return (get_term_ftable_t *)f;
+    sprintf(buf, "Can't resolve 'get_term_ftable' function from Gnuplot drawing engine '%s': %s", s, dlerror());
+    croak(buf);
+    return 0;
+}
+#endif