In the spirit of "commit early, commit often," I would like to request
comments on a patch I have put together which provides the start of
global coordinate transform support for PLplot.
What does this mean? Rather than providing one transform function to
each PLplot function call, as can be done currently with, e.g.,
plimagefr and plmap, a user can instead (or in addition) provide a
single callback function which then allows _all_ PLplot output to go
through the same coordinate transform without having to specify a
function for each function call. This avoids changing the existing
PLplot C API beyond the addition of one new function, plstransform.
The attached patch implements this a somewhat naive but hopefully
effective manner for most of the PLplot primitives on which the rest
of PLplot's plotting functions are built (pljoin + plline and their
underlying support functions, plfill, plptex). plmtex is notable in
its absence in this list, as it means that axis labels are not
properly affected by this patch. That is next on my TODO list for
this feature.
An example x19-v2c.c is included as an illustration of the new
function plstransform and its current effect. This is a copy of the
standard C example 19 but with a duplicate of the last page in the
example which shows a polar view of the earth's continental outlines.
This duplicate page performs the same transform as the existing
plmap-based method polar view method, but uses plstransform to apply
the transform. The result is that the last two pages of x19-v2c.c
should be identical to one another.
The patch should apply cleanly against the latest PLplot trunk. It
updates the CMake logic for examples/c/ to add x19-v2c.c to the list
of examples to build when building the examples is enabled.
Please test, review and comment! I think that this would be a very
nice feature to have in a future version of PLplot.
Hez
--
Hezekiah M. Carty
Graduate Research Assistant
University of Maryland
Department of Atmospheric and Oceanic Science
commit c4686224b71d61d5a60ebf840e5ff3601f16bfbd
Author: Hezekiah M. Carty <hca...@atmos.umd.edu>
Date: Thu Oct 1 16:45:44 2009 -0500
Add the start of global/universal coordinate transform support
This commit adds the plstransform function which allows a user to define
a global coordinate transform which will be used by all PLplot plotting
functions.
An example, x19-v2c.c, is provided which is a replica of the standard
example 19 but with the last page duplicated. The last page of x19-v2c.c
uses plstransform to apply the coordinate transformation to the plotted
data rather than passing a transformation function to plmap. A dummy
transform function is passed to plmeridians as a workaround due to some
assumptions in the plmerdians code.
Note that this is INCOMPLETE! Most importantly, plmtex has not been
appropriately updated. Changes to assumptions in other PLplot functions
will likely be required in order to have everything "just work" as it
should.
diff --git a/examples/c/CMakeLists.txt b/examples/c/CMakeLists.txt
index fb2e46c..90928e2 100644
--- a/examples/c/CMakeLists.txt
+++ b/examples/c/CMakeLists.txt
@@ -44,6 +44,7 @@ set(c_STRING_INDICES
"17"
"18"
"19"
+ "19-v2"
"20"
"21"
"22"
diff --git a/examples/c/x19-v2c.c b/examples/c/x19-v2c.c
new file mode 100644
index 0000000..9e30a60
--- /dev/null
+++ b/examples/c/x19-v2c.c
@@ -0,0 +1,179 @@
+/* $Id$
+
+ Illustrates backdrop plotting of world, US maps.
+ Contributed by Wesley Ebisuzaki.
+*/
+
+#include "plcdemos.h"
+
+void
+map_transform(PLFLT x, PLFLT y, PLFLT *xt, PLFLT *yt)
+{
+ double radius;
+
+ radius = 90.0 - y;
+ *xt = radius * cos(x * M_PI / 180.0);
+ *yt = radius * sin(x * M_PI / 180.0);
+}
+
+void
+id_mapform(PLINT n, PLFLT *x, PLFLT *y)
+{
+ /* Do nothing. This is a workaround for using plmeridians with a user-
+ * defined global PLplot transform function. */
+ return;
+}
+
+/*--------------------------------------------------------------------------*\
+ * mapform19
+ *
+ * Defines specific coordinate transformation for example 19.
+ * Not to be confused with mapform in src/plmap.c.
+ * x[], y[] are the coordinates to be plotted.
+\*--------------------------------------------------------------------------*/
+
+void
+mapform19(PLINT n, PLFLT *x, PLFLT *y)
+{
+ int i;
+ double xp, yp;
+ for (i = 0; i < n; i++) {
+ map_transform(x[i], y[i], &xp, &yp);
+ x[i] = xp;
+ y[i] = yp;
+ }
+}
+
+/* "Normalize" longitude values so that they always fall between -180.0 and
+ 180.0 */
+PLFLT normalize_longitude(PLFLT lon) {
+ PLFLT times;
+ if (lon >= -180.0 && lon <= 180.0) {
+ return(lon);
+ }
+ else {
+ times = floor ((fabs(lon) + 180.0) / 360.0);
+ if (lon < 0.0) {
+ return(lon + 360.0 * times);
+ }
+ else {
+ return(lon - 360.0 * times);
+ }
+ }
+}
+
+/* A custom axis labeling function for longitudes and latitudes. */
+void
+geolocation_labeler(PLINT axis, PLFLT value, char *label, PLINT length, PLPointer data) {
+ const char *direction_label;
+ PLFLT label_val;
+
+ if (axis == PL_Y_AXIS) {
+ label_val = value;
+ if (label_val > 0.0) {
+ direction_label = " N";
+ }
+ else if (label_val < 0.0) {
+ direction_label = " S";
+ }
+ else {
+ direction_label = "Eq";
+ }
+ }
+ else if (axis == PL_X_AXIS) {
+ label_val = normalize_longitude(value);
+ if (label_val > 0.0) {
+ direction_label = " E";
+ }
+ else if (label_val < 0.0) {
+ direction_label = " W";
+ }
+ else {
+ direction_label = "";
+ }
+ }
+ if (axis == PL_Y_AXIS && value == 0.0) {
+ /* A special case for the equator */
+ snprintf(label, length, "%s", direction_label);
+ }
+ else {
+ snprintf(label, length, "%.0f%s", fabs(label_val), direction_label);
+ }
+}
+
+/*--------------------------------------------------------------------------*\
+ * main
+ *
+ * Shows two views of the world map.
+\*--------------------------------------------------------------------------*/
+
+int
+main(int argc, const char **argv)
+{
+ PLFLT minx, maxx, miny, maxy;
+
+/* Parse and process command line arguments */
+
+ (void) plparseopts(&argc, argv, PL_PARSE_FULL);
+
+/* Longitude (x) and latitude (y) */
+
+ miny = -70;
+ maxy = 80;
+
+ plinit();
+
+/* Cartesian plots */
+/* Most of world */
+
+ minx = 190;
+ maxx = 190+360;
+
+ /* Setup a custom latitude and longitude-based scaling function. */
+ plslabelfunc(geolocation_labeler, NULL);
+
+ plcol0(1);
+ plenv(minx, maxx, miny, maxy, 1, 70);
+ plmap(NULL, "usaglobe", minx, maxx, miny, maxy);
+
+/* The Americas */
+
+ minx = 190;
+ maxx = 340;
+
+ plcol0(1);
+ plenv(minx, maxx, miny, maxy, 1, 70);
+ plmap(NULL, "usaglobe", minx, maxx, miny, maxy);
+
+ /* Clear the labeling function */
+ plslabelfunc(NULL, NULL);
+
+/* Polar, Northern hemisphere */
+
+ minx = 0;
+ maxx = 360;
+
+ plenv(-75., 75., -75., 75., 1, -1);
+ plmap(mapform19,"globe", minx, maxx, miny, maxy);
+
+ pllsty(2);
+ plmeridians(mapform19,10.0, 10.0, 0.0, 360.0, -10.0, 80.0);
+
+/* Polar, Northern hemisphere, this time with a PLplot-wide transform */
+
+ minx = 0;
+ maxx = 360;
+
+ plstransform(map_transform, NULL);
+
+ pllsty(1);
+ plenv(-75., 75., -75., 75., 1, -1);
+ plmap(NULL, "globe", minx, maxx, miny, maxy);
+
+ pllsty(2);
+ /* Use a no-op map transform so to make plmeridians draw the lines piece
+ * by piece. */
+ plmeridians(id_mapform, 10.0, 10.0, 0.0, 360.0, -10.0, 80.0);
+ plend();
+ exit(0);
+}
diff --git a/include/plplot.h b/include/plplot.h
index dc99a7c..ff3484d 100644
--- a/include/plplot.h
+++ b/include/plplot.h
@@ -556,6 +556,7 @@ typedef struct {
#define plgcolbg c_plgcolbg
#define plgcolbga c_plgcolbga
#define plgcompression c_plgcompression
+#define plstransform c_plstransform
#define plgdev c_plgdev
#define plgdidev c_plgdidev
#define plgdiori c_plgdiori
@@ -943,6 +944,10 @@ c_plgcolbga(PLINT *r, PLINT *g, PLINT *b, PLFLT *a);
PLDLLIMPEXP void
c_plgcompression(PLINT *compression);
+/* Set the coordinate transform */
+PLDLLIMPEXP void
+c_plstransform(void (*coordinate_transform)(PLFLT, PLFLT, PLFLT*, PLFLT*, PLPointer), PLPointer coordinate_transform_data);
+
/* Get the current device (keyword) name */
PLDLLIMPEXP void
diff --git a/include/plplotP.h b/include/plplotP.h
index 6dcf9b2..b0e016e 100644
--- a/include/plplotP.h
+++ b/include/plplotP.h
@@ -219,6 +219,9 @@ extern PLDLLIMPEXP_DATA(PLStream *)plsc;
#ifndef SIGN
#define SIGN(a) ((a)<0 ? -1 : 1)
#endif
+#ifndef TRANSFORM
+#define TRANSFORM(x,y,xnew,ynew) if (plsc->coordinate_transform) { plsc->coordinate_transform((x), (y), (xnew), (ynew), plsc->coordinate_transform_data); } else { *xnew = x; *ynew = y; }
+#endif
/* A coordinate value that should never occur */
diff --git a/include/plstrm.h b/include/plstrm.h
index 1e5833d..3003d53 100644
--- a/include/plstrm.h
+++ b/include/plstrm.h
@@ -499,6 +499,11 @@ typedef struct {
PLINT ipls, level, verbose, debug, initialized, dev_initialized;
const char *program;
+/* Plot-wide coordinate transform */
+
+ void (*coordinate_transform)(PLFLT, PLFLT, PLFLT*, PLFLT*, PLPointer);
+ PLPointer coordinate_transform_data;
+
/* Colormaps */
PLINT icol0, ncol0, icol1, ncol1, ncp1, curcmap;
diff --git a/src/plcore.c b/src/plcore.c
index f7378f0..778352f 100644
--- a/src/plcore.c
+++ b/src/plcore.c
@@ -3936,3 +3936,16 @@ plP_image( PLFLT *z, PLINT nx, PLINT ny, PLFLT xmin, PLFLT ymin, PLFLT dx, PLFLT
plsc->plbuf_write = plbuf_write;
#endif /* END dev_fastimg COMMENT */
}
+
+/*--------------------------------------------------------------------------*\
+ * plstransform
+ *
+ * Set a universal coordinate transform function which will be applied to all
+ * plotted items.
+\*--------------------------------------------------------------------------*/
+void
+c_plstransform(void (*coordinate_transform)(PLFLT, PLFLT, PLFLT*, PLFLT*, PLPointer), PLPointer coordinate_transform_data)
+{
+ plsc->coordinate_transform = coordinate_transform;
+ plsc->coordinate_transform_data = coordinate_transform_data;
+}
diff --git a/src/plfill.c b/src/plfill.c
index 8001edd..88d5763 100644
--- a/src/plfill.c
+++ b/src/plfill.c
@@ -57,6 +57,7 @@ c_plfill( PLINT n, PLFLT *x, PLFLT *y )
{
PLINT xpoly[PL_MAXPOLY], ypoly[PL_MAXPOLY];
PLINT i;
+ PLFLT xt, yt;
if ( plsc->level < 3 )
{
@@ -75,15 +76,17 @@ c_plfill( PLINT n, PLFLT *x, PLFLT *y )
}
for ( i = 0; i < n; i++ )
{
- xpoly[i] = plP_wcpcx( x[i] );
- ypoly[i] = plP_wcpcy( y[i] );
+ TRANSFORM( x[i], y[i], &xt, &yt );
+ xpoly[i] = plP_wcpcx( xt );
+ ypoly[i] = plP_wcpcy( yt );
}
if ( x[0] != x[n - 1] || y[0] != y[n - 1] )
{
if ( n < PL_MAXPOLY ) n++;
- xpoly[n - 1] = plP_wcpcx( x[0] );
- ypoly[n - 1] = plP_wcpcy( y[0] );
+ TRANSFORM( x[0], y[0], &xt, &yt );
+ xpoly[n - 1] = plP_wcpcx( xt );
+ ypoly[n - 1] = plP_wcpcy( yt );
}
plP_plfclp( xpoly, ypoly, n, plsc->clpxmi, plsc->clpxma,
diff --git a/src/plline.c b/src/plline.c
index 8660735..d01de82 100644
--- a/src/plline.c
+++ b/src/plline.c
@@ -459,8 +459,11 @@ plP_draphy( PLINT x, PLINT y )
void
plP_movwor( PLFLT x, PLFLT y )
{
- plsc->currx = plP_wcpcx( x );
- plsc->curry = plP_wcpcy( y );
+ PLFLT xt, yt;
+ TRANSFORM( x, y, &xt, &yt );
+
+ plsc->currx = plP_wcpcx( xt );
+ plsc->curry = plP_wcpcy( yt );
}
/*----------------------------------------------------------------------*\
@@ -472,10 +475,13 @@ plP_movwor( PLFLT x, PLFLT y )
void
plP_drawor( PLFLT x, PLFLT y )
{
+ PLFLT xt, yt;
+ TRANSFORM( x, y, &xt, &yt );
+
xline[0] = plsc->currx;
- xline[1] = plP_wcpcx( x );
+ xline[1] = plP_wcpcx( xt );
yline[0] = plsc->curry;
- yline[1] = plP_wcpcy( y );
+ yline[1] = plP_wcpcy( yt );
pllclp( xline, yline, 2 );
}
@@ -519,6 +525,7 @@ void
plP_drawor_poly( PLFLT *x, PLFLT *y, PLINT n )
{
PLINT i, j, ib, ilim;
+ PLFLT xt, yt;
for ( ib = 0; ib < n; ib += PL_MAXPOLY - 1 )
{
@@ -527,8 +534,9 @@ plP_drawor_poly( PLFLT *x, PLFLT *y, PLINT n )
for ( i = 0; i < ilim; i++ )
{
j = ib + i;
- xline[i] = plP_wcpcx( x[j] );
- yline[i] = plP_wcpcy( y[j] );
+ TRANSFORM( x[j], y[j], &xt, &yt );
+ xline[i] = plP_wcpcx( xt );
+ yline[i] = plP_wcpcy( yt );
}
pllclp( xline, yline, ilim );
}
diff --git a/src/plsym.c b/src/plsym.c
index cb61a2b..726066f 100644
--- a/src/plsym.c
+++ b/src/plsym.c
@@ -87,6 +87,7 @@ void
c_plsym( PLINT n, PLFLT *x, PLFLT *y, PLINT code )
{
PLINT i;
+ PLFLT xt, yt;
if ( plsc->level < 3 )
{
@@ -101,7 +102,8 @@ c_plsym( PLINT n, PLFLT *x, PLFLT *y, PLINT code )
for ( i = 0; i < n; i++ )
{
- plhrsh( code, plP_wcpcx( x[i] ), plP_wcpcy( y[i] ));
+ TRANSFORM( x[i], y[i], &xt, &yt );
+ plhrsh( code, plP_wcpcx( xt ), plP_wcpcy( yt ));
}
}
@@ -122,6 +124,7 @@ void
c_plpoin( PLINT n, PLFLT *x, PLFLT *y, PLINT code )
{
PLINT i, sym, ifont = plsc->cfont;
+ PLFLT xt, yt;
if ( plsc->level < 3 )
{
@@ -136,8 +139,10 @@ c_plpoin( PLINT n, PLFLT *x, PLFLT *y, PLINT code )
if ( code == -1 )
{
- for ( i = 0; i < n; i++ )
- pljoin( x[i], y[i], x[i], y[i] );
+ for ( i = 0; i < n; i++ ) {
+ TRANSFORM(x[i], y[i], &xt, &yt);
+ pljoin( xt, yt, xt, yt );
+ }
}
else
{
@@ -145,8 +150,10 @@ c_plpoin( PLINT n, PLFLT *x, PLFLT *y, PLINT code )
ifont = 1;
sym = *( fntlkup + ( ifont - 1 ) * numberchars + code );
- for ( i = 0; i < n; i++ )
- plhrsh( sym, plP_wcpcx( x[i] ), plP_wcpcy( y[i] ));
+ for ( i = 0; i < n; i++ ) {
+ TRANSFORM(x[i], y[i], &xt, &yt);
+ plhrsh( sym, plP_wcpcx( xt ), plP_wcpcy( yt ));
+ }
}
}
@@ -596,6 +603,7 @@ c_plptex( PLFLT wx, PLFLT wy, PLFLT dx, PLFLT dy, PLFLT just, const char *text )
PLFLT xform[4], diag;
PLFLT chrdef, chrht;
PLFLT dispx, dispy;
+ PLFLT wxt, wyt, dxt, dyt;
if ( plsc->level < 3 )
{
@@ -603,13 +611,19 @@ c_plptex( PLFLT wx, PLFLT wy, PLFLT dx, PLFLT dy, PLFLT just, const char *text )
return;
}
- if ( dx == 0.0 && dy == 0.0 )
+ /* Transform both the origin and offset values */
+ TRANSFORM(wx, wy, &wxt, &wyt);
+ TRANSFORM(wx + dx, wy + dy, &dxt, &dyt);
+ dxt = dxt - wxt;
+ dyt = dyt - wyt;
+ if ( dxt == 0.0 && dyt == 0.0 )
{
- dx = 1.0;
- dy = 0.0;
+ dxt = 1.0;
+ dyt = 0.0;
}
- cc = plsc->wmxscl * dx;
- ss = plsc->wmyscl * dy;
+
+ cc = plsc->wmxscl * dxt;
+ ss = plsc->wmyscl * dyt;
diag = sqrt( cc * cc + ss * ss );
cc /= diag;
ss /= diag;
@@ -619,8 +633,8 @@ c_plptex( PLFLT wx, PLFLT wy, PLFLT dx, PLFLT dy, PLFLT just, const char *text )
xform[2] = ss;
xform[3] = cc;
- xdv = plP_wcdcx( wx );
- ydv = plP_wcdcy( wy );
+ xdv = plP_wcdcx( wxt );
+ ydv = plP_wcdcy( wyt );
dispx = 0.;
dispy = 0.;
------------------------------------------------------------------------------
Come build with us! The BlackBerry® Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay
ahead of the curve. Join us from November 9-12, 2009. Register now!
http://p.sf.net/sfu/devconf
_______________________________________________
Plplot-devel mailing list
Plplot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/plplot-devel