]> git.cworth.org Git - acre/commitdiff
Finish adjustment of tick positions for pixel-snapping.
authorCarl Worth <cworth@cworth.org>
Tue, 27 Jan 2009 07:17:42 +0000 (23:17 -0800)
committerCarl Worth <cworth@cworth.org>
Thu, 16 Apr 2009 19:04:20 +0000 (12:04 -0700)
This is the final step of adjusting the axis ranges so that
the ticks aligne nicely with integer pixel boundaries. Notably
we don't round the ticks at all while drawing them---instead
we only adjust the axis ranges so that when we draw the ticks
at their numerical positions they will look good.

acre.c

diff --git a/acre.c b/acre.c
index 6a4728ba99313b8798fdd793000e4c03e601ccc4..6d1262abe0af95f72864255d0781c688d3bf65fd 100644 (file)
--- a/acre.c
+++ b/acre.c
@@ -17,6 +17,9 @@
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#define _ISOC99_SOURCE /* for round() */
+#define _XOPEN_SOURCE 500
+
 #include "acre.h"
 #include "xmalloc.h"
 
@@ -304,13 +307,31 @@ _expand_range (double data_range, int pixel_size)
     return data_range * pixel_step / floor (pixel_step);
 }
 
+/* Setup a transformation in acre->cr such that data values plotted
+ * will appear where they should within the chart.
+ */
+static void
+_set_transform_to_data_space (acre_t *acre)
+{
+    cairo_t *cr = acre->cr;
+
+    cairo_translate (cr,
+                    acre->chart.x,
+                    acre->chart.y + acre->chart.height);
+    cairo_scale (cr,
+                acre->chart.width / (acre->x_axis.max - acre->x_axis.min),
+                - acre->chart.height /(acre->y_axis.max - acre->y_axis.min));
+    cairo_translate (cr, -acre->x_axis.min, -acre->y_axis.min);
+}
+
 static void
 _compute_axis_ranges (acre_t *acre)
 {
     unsigned int d, i;
     acre_data_t *data;
-    double x_range, new_x_range;
-    double y_range, new_y_range;
+    double x_range, new_x_range, x_adjust;
+    double y_range, new_y_range, y_adjust;
+    cairo_t *cr = acre->cr;
 
     /* First, simply find the extrema of the data. */
     for (d = 0; d < acre->num_data; d++) {
@@ -343,23 +364,28 @@ _compute_axis_ranges (acre_t *acre)
 
     acre->y_axis.min -= (new_y_range - y_range) / 2.0;
     acre->y_axis.max += (new_y_range - y_range) / 2.0;
-}
 
-/* Setup a transformation in acre->cr such that data values plotted
- * will appear where they should within the chart.
- */
-static void
-_set_transform_to_data_space (acre_t *acre)
-{
-    cairo_t *cr = acre->cr;
+    /* Finally, we also translate the axis ranges slightly so that the
+     * ticks land on half-integer device-pixel positions.
+     */
+    cairo_save (cr);
+    {
+       _set_transform_to_data_space (acre);
 
-    cairo_translate (cr,
-                    acre->chart.x,
-                    acre->chart.y + acre->chart.height);
-    cairo_scale (cr,
-                acre->chart.width / (acre->x_axis.max - acre->x_axis.min),
-                - acre->chart.height /(acre->y_axis.max - acre->y_axis.min));
-    cairo_translate (cr, -acre->x_axis.min, -acre->y_axis.min);
+       x_adjust = 0.0;
+       y_adjust = 0.0;
+       cairo_user_to_device (cr, &x_adjust, &y_adjust);
+       x_adjust = (round (x_adjust + 0.5) - 0.5) - x_adjust;
+       y_adjust = (round (y_adjust + 0.5) - 0.5) - y_adjust;
+       cairo_device_to_user_distance (cr, &x_adjust, &y_adjust);
+
+       acre->x_axis.min -= x_adjust;
+       acre->x_axis.max -= x_adjust;
+
+       acre->y_axis.min -= y_adjust;
+       acre->y_axis.max -= y_adjust;
+    }
+    cairo_restore (cr);
 }
 
 static void
@@ -418,7 +444,7 @@ _draw_frame_and_ticks (acre_t *acre)
            {
                cairo_identity_matrix (cr);
                cairo_rel_line_to (cr, 0, 0.5);
-               cairo_rel_line_to (cr, 0, -ACRE_TICK_SIZE);
+               cairo_rel_line_to (cr, 0, -ACRE_TICK_SIZE-0.5);
                cairo_set_line_width (cr, 1.0);
                cairo_stroke (cr);
            }
@@ -434,7 +460,7 @@ _draw_frame_and_ticks (acre_t *acre)
            {
                cairo_identity_matrix (cr);
                cairo_rel_line_to (cr, -0.5, 0);
-               cairo_rel_line_to (cr, ACRE_TICK_SIZE, 0);
+               cairo_rel_line_to (cr, ACRE_TICK_SIZE+0.5, 0);
                cairo_set_line_width (cr, 1.0);
                cairo_stroke (cr);
            }