Re: Extents under rotation
Uli Schlachter <[email protected]>
| Newsgroups | gmane.comp.lib.cairo |
|---|---|
| Message-ID | <[email protected]> |
Hi again, On 07.12.2013 08:31, Donn wrote: > On 06/12/2013 17:13, Bill Spitzak wrote: >> The matrices are multiplied before this is done, so this error does not >> accumulate. For instance if you rotate by 45 degrees and then back by 45 >> degrees, it will act like a rotation of 0 and produce your expected >> bounding box, rather than enlarging the bounding box twice. > > I'm sure I will face these things soon when I institute picking beyond a > basic bbox hit approach. > > > > Bill, > Do you have a way to draw a tight bbox in user-space around a path? [...] I was bored, so: See the attached test program (written in C since I don't know vala). It uses three different ways for getting the extents of a circle. 1) cairo_path_extents() 2) cairo_path_extents() after cairo_identity_matrix() 3) Some slow calculations with cairo_copy_path_flat(). See get_path_extents(). The first row is painted without any rotation (I needed this since I made a typo at first with x1/y1/x2/y2 that I took a while to find) with the calculations as mentioned above. The second row is rotated by 67° and the individual rectangles are again calculated as above. Hope this helps, Uli -- cairo mailing list [email protected] http://lists.cairographics.org/mailman/listinfo/cairo
img.png
(image/png, 8.8 KB) - not displayed
test.c
(text/x-csrc, 2.3 KB)
#include <cairo.h>
#include <math.h>
#include <assert.h>
static cairo_t *get_surface(int width, int height)
{
cairo_surface_t *surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
cairo_t *cr = cairo_create (surface);
cairo_surface_destroy (surface);
return cr;
}
static void get_path_extents(cairo_t *cr, double *x1, double *y1, double *x2, double *y2)
{
int i, had_point = 0;
cairo_path_t *path = cairo_copy_path_flat (cr);
*x1 = *y1 = *x2 = *y2 = 0;
for (i=0; i < path->num_data; i += path->data[i].header.length) {
cairo_path_data_t *data = &path->data[i];
switch (data->header.type) {
case CAIRO_PATH_MOVE_TO:
case CAIRO_PATH_LINE_TO:
if (!had_point) {
*x1 = *x2 = data[1].point.x;
*y1 = *y2 = data[1].point.y;
had_point = 1;
} else {
*x1 = fmin(*x1, data[1].point.x);
*y1 = fmin(*y1, data[1].point.y);
*x2 = fmax(*x2, data[1].point.x);
*y2 = fmax(*y2, data[1].point.y);
}
break;
case CAIRO_PATH_CLOSE_PATH:
/* Nothing to do here */
break;
case CAIRO_PATH_CURVE_TO:
default:
assert (0);
}
}
cairo_path_destroy (path);
}
static void do_row(cairo_t *cr)
{
double x1, y1, x2, y2;
double step_x, step_y;
cairo_save (cr);
step_x = 100;
step_y = 0;
cairo_device_to_user_distance (cr, &step_x, &step_y);
cairo_arc (cr, 50, 50, 30, 0, 2 * M_PI);
cairo_path_extents (cr, &x1, &y1, &x2, &y2);
cairo_rectangle (cr, x1, y1, x2-x1, y2-y1);
cairo_stroke (cr);
cairo_translate (cr, step_x, step_y);
cairo_arc (cr, 50, 50, 30, 0, 2 * M_PI);
cairo_save (cr);
cairo_identity_matrix (cr);
cairo_path_extents (cr, &x1, &y1, &x2, &y2);
cairo_rectangle (cr, x1, y1, x2-x1, y2-y1);
cairo_stroke (cr);
cairo_restore (cr);
cairo_translate (cr, step_x, step_y);
cairo_arc (cr, 50, 50, 30, 0, 2 * M_PI);
get_path_extents (cr, &x1, &y1, &x2, &y2);
cairo_rectangle (cr, x1, y1, x2-x1, y2-y1);
cairo_stroke (cr);
cairo_translate (cr, step_x, step_y);
cairo_restore (cr);
}
int main(void)
{
cairo_t *cr = get_surface(100 * 3, 100 * 2);
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_paint (cr);
cairo_set_source_rgb (cr, 1, 1, 1);
do_row (cr);
cairo_translate (cr, 80, 100);
cairo_rotate (cr, 67*M_PI/180);
do_row (cr);
cairo_surface_write_to_png (cairo_get_target (cr), "img.png");
cairo_destroy (cr);
return 0;
}