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