Check collision via cairo_clip_extents

"Yang Hong" <[email protected]> Fri, 23 Nov 2018 17:16:54 +0800
Newsgroups gmane.comp.lib.cairo
Message-ID <[email protected]>
Dear Cairo developers

 

I'm writing a 2D game which need to check collision between
triangle/trapezoid/rectangle/hexagon blocks on the canvas.

 

I tried to use cairo_clip_extents() to find intersect of triangle and
rectangle, but it doesn't work, because the returned bounding is bigger than
the accurate intersect. Please refer to the attached collision checking
model, I want get the bounding of the area C to check if the triangle is
intersected with the rectangle. This model only works between rectangles,
the cairo_region_t also not help on this.

 

I also tried cairo_fill_extents, it returns the whole bounding of the
current path, which is not what I want.

 

While the C area is correctly filled with clip, I want to know is there any
API to get the bound of this area, so I can use it to check if collision
exists. Or is it possible to add API to do so, I have looked into the source
code of cairo, please give me some comment, I'd like to add this API by
myself.

 

The attached cairo-sandbox.c is the code I used to test the checking model.

 

    gcc -o sandbox cairo-sandbox.c -lcairo -g

    ./sandbox

    eog image.png

 

Best regards

 

Hong Yang - TS

-- 
cairo mailing list
[email protected]
https://lists.cairographics.org/mailman/listinfo/cairo
collision-checking-model.txt (text/plain, 289 B)

          ^
         / \  +--------+
        /   \ |        |
       /     \|        |
      /       \   B    |
     /   A    |\       |
    /         | \      |
   /          |C \     |
  /___________|___\    |
              |        |
              |        |
              +--------+
cairo-sandbox.c (application/octet-stream, 6.8 KB)
#include <stdio.h>
#include <cairo/cairo.h>

typedef struct _point point_t;

struct _point {
	double x;
	double y;
};

double scale = 20.0;

void create_triangle (cairo_t *cr, const point_t *points, int len, int close)
{
	const point_t *point = points;
	int i = 0;

	cairo_move_to (cr, scale * points[i].x, scale * points[i].y);
	i++;

	while (i < len) {
		cairo_line_to (cr, scale * points[i].x, scale * points[i].y);
		i++;
	}

	if (close) {
		cairo_close_path(cr);
	}
}

static point_t tri4[] = {
	{ 3.0, 0.0 },
	{ 6.0, 3.0 },
	{ 0.0, 3.0 },
};

static point_t rec36[] = {
	{ 0.0, 0.0 },
	{ 3.0, 0.0 },
	{ 3.0, 6.0 },
	{ 0.0, 6.0 },
};

static point_t rec915[] = {
	{ 0.0, 0.0 },
	{ 9.0, 0.0 },
	{ 9.0, 1.5 },
	{ 0.0, 1.5 },
};

#define ARRAY_SIZE(a) (sizeof(a)/sizeof(point_t))

void sandbox(void)
{
	double x1, y1, x2, y2;
	const int img_size = 700;
	cairo_surface_t * const pix = cairo_image_surface_create
		(
		 /*format =*/ CAIRO_FORMAT_RGB24,
		 /*width =*/  img_size,
		 /*height =*/ img_size/2
		);
	cairo_t * const cr = cairo_create(pix);
	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
	/* use overwriting operator to make clear that overwriting is blocked by clipping */
	cairo_set_source_rgb(cr, 1, 1, 1); /* background */
	cairo_paint(cr);

	//cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
	cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING);
	cairo_translate(cr, 20, 20);
	////////////

	cairo_reset_clip(cr);
	cairo_new_path(cr);
	create_triangle(cr, tri4, ARRAY_SIZE(tri4), 1);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.5, 0.5);
	//cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);
	//cairo_clip(cr);

	cairo_translate(cr, 100, 0);
	cairo_new_path(cr);
	create_triangle(cr, rec36, ARRAY_SIZE(rec36), 1);
	cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.5);
	//cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 0.0, 1.0, 0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);

	x1 = y1 = x2 = y2 = 0.0;
	cairo_clip(cr);
	cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
	//cairo_fill_extents(cr, &x1, &y1, &x2, &y2);

	printf("Clip extents: %f, %f, %f, %f\n", x1, y1, x2, y2);

	cairo_reset_clip(cr);
	cairo_new_path(cr);
	cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
	cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5);
	cairo_stroke_preserve (cr);
	////////////

	cairo_translate(cr, 120, 0);
	cairo_reset_clip(cr);
	cairo_new_path(cr);
	create_triangle(cr, tri4, ARRAY_SIZE(tri4), 1);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.5, 0.5);
	//cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);
	cairo_clip(cr);

	cairo_translate(cr, 100, 0);
	cairo_new_path(cr);
	create_triangle(cr, rec36, ARRAY_SIZE(rec36), 1);
	cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.5);
	cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 0.0, 1.0, 0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);

	x1 = y1 = x2 = y2 = 0.0;
	cairo_clip(cr);
	cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
	//cairo_fill_extents(cr, &x1, &y1, &x2, &y2);

	printf("Clip extents: %f, %f, %f, %f\n", x1, y1, x2, y2);

	cairo_reset_clip(cr);
	cairo_new_path(cr);
	cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
	cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5);
	cairo_stroke_preserve (cr);
	////////////

	cairo_translate(cr, 80, 0);
	cairo_reset_clip(cr);
	cairo_new_path(cr);
	create_triangle(cr, tri4, ARRAY_SIZE(tri4), 1);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.5, 0.5);
	//cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);
	cairo_clip_preserve(cr);

	cairo_translate(cr, 100, 0);
	cairo_new_path(cr);
	create_triangle(cr, rec36, ARRAY_SIZE(rec36), 1);
	cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.5);
	cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 0.0, 1.0, 0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);

	x1 = y1 = x2 = y2 = 0.0;
	cairo_clip_preserve(cr);
	//cairo_clip_extents(cr, &x1, &y1, &x2, &y2);
	cairo_fill_extents(cr, &x1, &y1, &x2, &y2);

	printf("Clip extents: %f, %f, %f, %f\n", x1, y1, x2, y2);

	cairo_reset_clip(cr);
	cairo_new_path(cr);
	cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
	cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5);
	cairo_stroke_preserve (cr);
	////////////

	cairo_translate(cr, -480, 180);
	cairo_reset_clip(cr);
	cairo_new_path(cr);
	create_triangle(cr, rec36, ARRAY_SIZE(rec36), 1);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.5, 0.5);
	//cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);
	//cairo_clip(cr);

	cairo_new_path(cr);
	create_triangle(cr, rec915, ARRAY_SIZE(rec915), 1);
	cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.5);
	//cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 0.0, 1.0, 0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);
	////////////

	cairo_translate(cr, 220, 00);
	cairo_reset_clip(cr);
	cairo_new_path(cr);
	create_triangle(cr, rec36, ARRAY_SIZE(rec36), 1);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.5, 0.5);
	//cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);
	cairo_clip(cr);

	cairo_new_path(cr);
	create_triangle(cr, rec915, ARRAY_SIZE(rec915), 1);
	cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.5);
	cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 0.0, 1.0, 0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);

	x1 = y1 = x2 = y2 = 0.0;
	cairo_clip(cr);
	cairo_clip_extents(cr, &x1, &y1, &x2, &y2);

	printf("Clip extents: %f, %f, %f, %f\n", x1, y1, x2, y2);

	cairo_reset_clip(cr);
	cairo_new_path(cr);
	cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
	cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5);
	cairo_stroke_preserve (cr);

	////////////
	cairo_translate(cr, 100, 00);
	cairo_reset_clip(cr);
	cairo_new_path(cr);
	create_triangle(cr, rec36, ARRAY_SIZE(rec36), 1);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.5, 0.5);
	//cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 1.0, 0.0, 0.0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);
	cairo_clip(cr);

	cairo_translate(cr, 0, 30);
	cairo_new_path(cr);
	create_triangle(cr, rec915, ARRAY_SIZE(rec915), 1);
	cairo_set_source_rgba (cr, 0.8, 0.8, 0.8, 0.5);
	cairo_fill_preserve(cr);
	cairo_set_source_rgba (cr, 0.0, 1.0, 0, 0.5);
	cairo_set_line_width (cr, 2.0);
	cairo_stroke_preserve (cr);

	x1 = y1 = x2 = y2 = 0.0;
	cairo_clip(cr);
	cairo_clip_extents(cr, &x1, &y1, &x2, &y2);

	printf("Clip extents: %f, %f, %f, %f\n", x1, y1, x2, y2);

	cairo_reset_clip(cr);
	cairo_new_path(cr);
	cairo_rectangle(cr, x1, y1, x2 - x1, y2 - y1);
	cairo_set_source_rgba (cr, 0.0, 0.0, 1.0, 0.5);
	cairo_stroke_preserve (cr);

	cairo_surface_write_to_png(pix, "image.png");
}

int main(int argc, char *argv[])
{
	sandbox();

	return 0;
}