+ /* If nothing is visible, punt to full X data range. */
+ if (first) {
+ *x_min = acre->x_axis.data_min;
+ *x_max = acre->x_axis.data_max;
+ }
+}
+
+static void
+_find_y_range_given_x_range (acre_t *acre,
+ double *y_min, double *y_max,
+ double x_min, double x_max)
+{
+ acre_data_t *data;
+ unsigned d, i;
+ bool first;
+
+ first = true;
+
+ for (d = 0; d < acre->num_data; d++) {
+ data = acre->data[d];
+ for (i = 0; i < data->num_points; i++) {
+ if (data->points[i].x >= x_min &&
+ data->points[i].x <= x_max)
+ {
+ if (first) {
+ *y_min = data->points[i].y;
+ *y_max = data->points[i].y;
+ first = false;
+ } else {
+ if (data->points[i].y < *y_min)
+ *y_min = data->points[i].y;
+ if (data->points[i].y > *y_max)
+ *y_max = data->points[i].y;
+ }
+ }
+ }
+ }
+
+ /* If nothing is visible, punt to full Y data range. */
+ if (first) {
+ *y_min = acre->y_axis.data_min;
+ *y_max = acre->y_axis.data_max;
+ }
+}
+
+static void
+_compute_axis_ranges (acre_t *acre)
+{
+ double x_adjust, y_adjust;
+ cairo_t *cr = acre->cr;
+
+ /* If neither view range is set, set both to data ranges. */
+ if (! acre->x_axis.view_range_set && ! acre->y_axis.view_range_set)
+ {
+ acre->x_axis.view_min = acre->x_axis.data_min;
+ acre->x_axis.view_max = acre->x_axis.data_max;
+
+ acre->y_axis.view_min = acre->y_axis.data_min;
+ acre->y_axis.view_max = acre->y_axis.data_max;
+ } else {
+ /* Otherwise, auto-fit unset range based on data. */
+ if (acre->x_axis.view_range_set && ! acre->y_axis.view_range_set) {
+ _find_y_range_given_x_range (acre,
+ &acre->y_axis.view_min,
+ &acre->y_axis.view_max,
+ acre->x_axis.view_min,
+ acre->x_axis.view_max);
+ }
+ else if (acre->y_axis.view_range_set && ! acre->x_axis.view_range_set) {
+ _find_x_range_given_y_range (acre,
+ &acre->x_axis.view_min,
+ &acre->x_axis.view_max,
+ acre->y_axis.view_min,
+ acre->y_axis.view_max);
+ }
+ }
+
+ /* Next, we want to ensure that the data never collides with the
+ * ticks. So we expand each axis on its minimum side as needed. */
+ cairo_save (cr);
+ {
+ double x, y;
+
+ _set_transform_to_data_space (acre);
+
+ x = ACRE_TICK_MAJOR_SIZE + 2.0;
+ y = ACRE_TICK_MAJOR_SIZE + 2.0;
+ cairo_device_to_user_distance (cr, &x, &y);
+
+ acre->x_axis.view_min -= x;
+ acre->y_axis.view_min += y;
+ }
+ cairo_restore (cr);
+
+ /* Then, increase the axis ranges just enough so that the step