On Wed, Jun 3, 2009 at 3:40 PM, Hezekiah M. Carty<hca...@atmos.umd.edu> wrote:
> While writing the Cairo backend for plarc, I am having some trouble
> getting the transformation from world coordinates to Cairo coordinates
> correct.

I have attached a patch which implements the plarc function, adds
Cairo-specific support for arc outlines and fills, and updates example
3 to use plarc for the polar plot circles.  It is my hope that someone
with more experience with the PLplot internals can point out what I am
doing wrong with the scaling of the coordinates.  The implementation
is still incomplete as plot-device-accelerated plarc calls are not
added to the plot buffer yet.  It is complete enough to compare the
"proper" results (ex. using the xwin device) with the incorrectly
scaled results (ex. using the xcairo device).

>From what I understand, the problem is in src/plarc.c in the c_plarc
function, somewhere between lines 128 and 144 where arc-capable
devices are handled.  The Cairo rendering function is in
drivers/cairo.c and is called arc().

Thank you for any insight you can provide on this.

Hez

-- 
Hezekiah M. Carty
Graduate Research Assistant
University of Maryland
Department of Atmospheric and Oceanic Science
diff --git a/drivers/cairo.c b/drivers/cairo.c
index 7a8443c..9f98149 100644
--- a/drivers/cairo.c
+++ b/drivers/cairo.c
@@ -215,6 +217,7 @@ static void close_span_tag(char *, int);
 static void set_current_context(PLStream *);
 static void poly_line(PLStream *, short *, short *, PLINT);
 static void filled_polygon(PLStream *pls, short *xa, short *ya, PLINT npts);
+static void arc(PLStream *, arc_struct *);
 static void rotate_cairo_surface(PLStream *, float, float, float, float, float, float);
 /* Rasterization of plotted material */
 static void start_raster(PLStream*);
@@ -486,6 +489,9 @@ void plD_esc_cairo(PLStream *pls, PLINT op, void *ptr)
     case PLESC_END_RASTERIZE: /* End offscreen/rasterized rendering */
       end_raster(pls);
       break;
+    case PLESC_ARC: /* Draw an arc, either filled or outline */
+      arc(pls, (arc_struct *) ptr);
+      break;
     }
 }
 
@@ -992,6 +998,7 @@ PLCairo *stream_and_font_setup(PLStream *pls, int interactive)
   pls->alt_unicode = 1;      /* Wants to handle unicode character by character */
   pls->page = 0;
   pls->dev_fill0 = 1;        /* Supports hardware solid fills */
+  pls->dev_arc = 1;          /* Supports driver-level arcs */
   pls->plbuf_write = 1;      /* Activate plot buffer */
   
   
@@ -1149,6 +1156,60 @@ void filled_polygon(PLStream *pls, short *xa, short *ya, PLINT npts)
 }
 
 /*---------------------------------------------------------------------
+  arc()
+
+  Draws an arc, possibly filled.
+  ---------------------------------------------------------------------*/
+
+void arc(PLStream *pls, arc_struct *arc_info)
+{
+  /*
+     TODO:
+     - Decide on a direction for increasing angles and make sure this Cairo
+       implementation matches the software/fallback implementation.
+     - Add clipping to viewport boundaries
+  */
+  PLCairo *aStream;
+  double x, y, a, b;
+  double angle1, angle2;
+  double rotation;
+
+  set_current_context(pls);
+
+  aStream = (PLCairo *)pls->dev;
+
+  /* Scale to the proper Cairo coordinates */
+  x = aStream->downscale * arc_info->x;
+  y = aStream->downscale * arc_info->y;
+  a = aStream->downscale * arc_info->a;
+  b = aStream->downscale * arc_info->b;
+
+  /* Degrees to radians */
+  angle1 = arc_info->angle1 * M_PI / 180.0;
+  angle2 = arc_info->angle2 * M_PI / 180.0;
+  rotation = - arc_info->rotation * M_PI / 180.0;
+
+  /* Make sure the arc is properly shaped */
+  cairo_save(aStream->cairoContext);
+  cairo_translate(aStream->cairoContext, x, y);
+  cairo_rotate(aStream->cairoContext, rotation);
+  cairo_scale(aStream->cairoContext, a, b);
+  cairo_arc(aStream->cairoContext, 0.0, 0.0, 1.0, angle1, angle2);
+  cairo_restore(aStream->cairoContext);
+  cairo_set_source_rgba(aStream->cairoContext,
+      (double)pls->curcolor.r/255.0,
+      (double)pls->curcolor.g/255.0,
+      (double)pls->curcolor.b/255.0,
+      (double)pls->curcolor.a);
+  if (arc_info->fill) {
+    cairo_fill(aStream->cairoContext);
+  }
+  else {
+    cairo_stroke(aStream->cairoContext);
+  }
+}
+
+/*---------------------------------------------------------------------
   rotate_cairo_surface()
   
   Rotates the cairo surface to the appropriate orientation.
diff --git a/examples/c/x03c.c b/examples/c/x03c.c
index 8a07637..ffb9a41 100644
--- a/examples/c/x03c.c
+++ b/examples/c/x03c.c
@@ -41,15 +41,9 @@ main(int argc, const char *argv[])
 /* Set up viewport and window, but do not draw box */
 
     plenv(-1.3, 1.3, -1.3, 1.3, 1, -2);
-    for (i = 1; i <= 10; i++) {
-	for (j = 0; j <= 360; j++) {
-	    x[j] = 0.1 * i * x0[j];
-	    y[j] = 0.1 * i * y0[j];
-	}
-
     /* Draw circles for polar grid */
-
-	plline(361, x, y);
+    for (i = 1; i <= 10; i++) {
+        plarc(0.0, 0.0, 0.1 * i, 0.1 * i, 0.0, 360.0, 0.0, 0);
     }
 
     plcol0(2);
diff --git a/include/plplot.h b/include/plplot.h
index a002e02..c280a83 100644
--- a/include/plplot.h
+++ b/include/plplot.h
@@ -271,6 +271,7 @@ typedef void* PLPointer;
 #define PLESC_END_TEXT          31      /* finish a drawing a line of text */
 #define PLESC_START_RASTERIZE   32      /* start rasterized rendering */
 #define PLESC_END_RASTERIZE     33      /* end rasterized rendering */
+#define PLESC_ARC               34      /* render an arc */
 
 /* Alternative unicode text handling control characters */
 #define PLTEXT_FONTCHANGE       0       /* font change in the text stream */
@@ -554,6 +555,7 @@ typedef struct {
 #define    plbox	c_plbox
 #define    plbox3	c_plbox3
 #define    plcalc_world	c_plcalc_world
+#define    plarc	c_plarc
 #define    plclear	c_plclear
 #define    plcol0	c_plcol0
 #define    plcol1	c_plcol1
@@ -805,6 +807,12 @@ c_plbox3(const char *xopt, const char *xlabel, PLFLT xtick, PLINT nsubx,
 PLDLLIMPEXP void
 c_plcalc_world(PLFLT rx, PLFLT ry, PLFLT *wx, PLFLT *wy, PLINT *window);
 
+/**/
+
+PLDLLIMPEXP void
+c_plarc(PLFLT x, PLFLT y, PLFLT a, PLFLT b, PLFLT angle1, PLFLT angle2,
+        PLFLT rotation, PLBOOL fill);
+
 /* Clear current subpage. */
 
 PLDLLIMPEXP void
diff --git a/include/plplotP.h b/include/plplotP.h
index 5db1104..928dff4 100644
--- a/include/plplotP.h
+++ b/include/plplotP.h
@@ -891,6 +891,18 @@ void
 plP_image(PLFLT *z, PLINT nx, PLINT ny, PLFLT xmin, PLFLT ymin, PLFLT dx, PLFLT dy,
         void (*pltr) (PLFLT, PLFLT, PLFLT *, PLFLT *, PLPointer), PLPointer pltr_data);
 
+/* Structure for holding arc data */
+typedef struct {
+    PLFLT x;
+    PLFLT y;
+    PLFLT a;
+    PLFLT b;
+    PLFLT angle1;
+    PLFLT angle2;
+    PLFLT rotation;
+    PLBOOL fill;
+} arc_struct;
+
 /* End of page */
 
 PLDLLIMPEXP void
diff --git a/include/plstrm.h b/include/plstrm.h
index 7d30b56..91cdbef 100644
--- a/include/plstrm.h
+++ b/include/plstrm.h
@@ -531,7 +531,7 @@ typedef struct {
     PLINT color, colorset;
     PLINT family, member, finc, fflen, bytemax, famadv;
     PLINT dev_fill0, dev_fill1, dev_dash, dev_di, dev_flush, dev_swin;
-    PLINT dev_text, dev_xor, dev_clear, dev_fastimg;
+    PLINT dev_text, dev_xor, dev_clear, dev_fastimg, dev_arc;
 
     char DevName[80];
     FILE *OutFile;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 085c615..83dd8a9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -21,6 +21,7 @@
 
 set(plplot${LIB_TAG}_LIB_SRCS
 pdfutils.c
+plarc.c
 plargs.c
 plbox.c
 plcont.c
diff --git a/src/plarc.c b/src/plarc.c
new file mode 100644
index 0000000..b2f15b8
--- /dev/null
+++ b/src/plarc.c
@@ -0,0 +1,150 @@
+/* plarc()
+ *
+ * Copyright (C) 2009  Hezekiah M. Carty
+ *
+ * This file is part of PLplot.
+ *
+ * PLplot is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Library Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * PLplot is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with PLplot; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "plplotP.h"
+
+#define CIRCLE_SEGMENTS (PL_MAXPOLY - 2)
+#define DEG_TO_RAD(x) ((x) * M_PI / 180.0)
+
+/*-------------------------------------------------------------------------
+ * plarc_approx : Plot an approximated arc with a series of lines
+ *
+ * Takes the following arguments:
+ *
+ *   x, y:
+ *      x and y coordinates for the center of the arc
+ *
+ *   a, b:
+ *      Radius of the arc's major and minor axes
+ *
+ *   angle1:
+ *      Start angle (degrees)
+ *
+ *   angle2:
+ *      End angle (degrees)
+ *
+ *   fill:
+ *      Should the arc be filled?
+ *
+ *-------------------------------------------------------------------------*/
+void
+plarc_approx(PLFLT x, PLFLT y, PLFLT a, PLFLT b, PLFLT angle1, PLFLT angle2, PLFLT rotation, PLBOOL fill)
+{
+    PLINT i;
+    PLFLT theta0, theta_step, theta, d_angle;
+    PLFLT rot;
+    PLINT segments;
+    PLFLT xs[CIRCLE_SEGMENTS + 2], ys[CIRCLE_SEGMENTS + 2];
+
+    /* The difference between the start and end angles */
+    d_angle = DEG_TO_RAD(angle2 - angle1);
+    if (fabs(d_angle) > M_PI * 2.0)
+        d_angle = M_PI * 2.0;
+
+    /* The number of line segments used to approximate the arc */
+    segments = d_angle / (2.0 * M_PI) * CIRCLE_SEGMENTS;
+    /* The start angle in radians */
+    theta0 = DEG_TO_RAD(angle1);
+
+    theta_step = d_angle / segments;
+
+    /* Rotation angle in radians */
+    rot = DEG_TO_RAD(rotation);
+
+    /* The coordinates for the circle outline */
+    for (i = 0; i <= segments; i++) {
+        theta = theta0 + theta_step * (PLFLT) i;
+        xs[i] = x + a * cos(theta) * cos(rot) + b * sin(theta) * sin(rot);
+        ys[i] = y - a * cos(theta) * sin(rot) + b * sin(theta) * cos(rot);
+    }
+
+    /* If the arc is a full circle/ellipse, then close it. */
+    if (d_angle == M_PI * 2.0) {
+        segments++;
+        xs[segments] = x + a * cos(theta0) * cos(rot) + b * sin(theta0) * sin(rot);
+        ys[segments] = y + a * cos(theta0) * sin(rot) + b * sin(theta0) * cos(rot);
+    }
+
+    if (fill) {
+        /* Add the center point if we aren't drawing a circle */
+        if (fabs(d_angle) < M_PI * 2.0) {
+            segments++;
+            xs[segments] = x;
+            ys[segments] = y;
+        }
+        /* Draw a filled arc */
+        plfill(segments, xs, ys);
+    }
+    else {
+        /* Draw the arc outline */
+        plline(segments, xs, ys);
+    }
+}
+
+/*-------------------------------------------------------------------------
+ * plarc : Plot an arc
+ *
+ * Takes the following arguments:
+ *
+ *   x, y:
+ *      x and y coordinates for the center of the arc
+ *
+ *   a, b:
+ *      Radius of the arc's major and minor axes
+ *
+ *   angle1:
+ *      Start angle (degrees)
+ *
+ *   angle2:
+ *      End angle (degrees)
+ *
+ *   fill:
+ *      Should the arc be filled?
+ *
+ *-------------------------------------------------------------------------*/
+void
+c_plarc(PLFLT x, PLFLT y, PLFLT a, PLFLT b, PLFLT angle1, PLFLT angle2, PLFLT rotation, PLBOOL fill)
+{
+    arc_struct *arc_info;
+
+    if (plsc->dev_arc) {
+        /* If the driver can handle arcs, let it */
+        arc_info = (arc_struct *) malloc((size_t) sizeof(arc_struct));
+
+        arc_info->x = plP_wcpcx(x);
+        arc_info->y = plP_wcpcy(y);
+        arc_info->a = plP_wcpcx(x + a) - arc_info->x;
+        arc_info->b = plP_wcpcy(y + b) - arc_info->y;
+        arc_info->angle1 = angle1;
+        arc_info->angle2 = angle2;
+        arc_info->rotation = rotation;
+        arc_info->fill = fill;
+
+        plP_esc(PLESC_ARC, arc_info);
+
+        free(arc_info);
+    }
+    else {
+        /* If the driver can't do arcs, approximate it */
+        plarc_approx(x, y, a, b, angle1, angle2, rotation, fill);
+    }
+}
+
------------------------------------------------------------------------------
OpenSolaris 2009.06 is a cutting edge operating system for enterprises 
looking to deploy the next generation of Solaris that includes the latest 
innovations from Sun and the OpenSource community. Download a copy and 
enjoy capabilities such as Networking, Storage and Virtualization. 
Go to: http://p.sf.net/sfu/opensolaris-get
_______________________________________________
Plplot-devel mailing list
Plplot-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/plplot-devel

Reply via email to