Photolog
Back to list of problems
Polygons
137.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define EPS 1E-10
#define ZERO(a) (fabs(a) < EPS)
#define SIGN(a) (ZERO(a) ? 0 : (a>0) ? 1 : -1)
typedef struct {
double x;
double y;
} punto;
int
minang(int o, int nl, punto *li) {
int i,m=!o;
for (i=0; i<nl; i++) {
if (i==o) continue;
if ((li[i].x-li[o].x)*(li[m].y-li[o].y)
> (li[i].y-li[o].y)*(li[m].x-li[o].x)) {
m=i;
}
}
return m;
}
int
convex_hull(int N, punto *li) {
int i,m=0;
punto p;
if (!N) return 0;
for (i=1; i<N; i++) {
double c = li[i].y - li[m].y;
if (c<0) m=i;
if (!c && (li[i].x < li[m].x)) m=i;
}
p=li[0]; li[0]=li[m]; li[m]=p;
i=0; m=1;
while (1) {
i = minang(m-1, N, li);
if (i==0) return m;
p=li[m]; li[m]=li[i]; li[i]=p;
m++;
}
}
typedef struct {
int np;
punto *p;
} poly;
double
cross(punto p1, punto p2) {
return p1.x*p2.y - p1.y*p2.x;
}
double
modulo(punto p) {
return sqrt(p.x*p.x + p.y*p.y);
}
punto
psub(punto p1, punto p2) {
punto p;
p.x = p2.x - p1.x;
p.y = p2.y - p1.y;
return p;
}
#define dist(p1,p2) modulo(psub(p1,p2))
int
inside(punto pu, poly po) {
int i;
int sign=0;
for (i=0; i<po.np; i++) {
double d = cross(psub(po.p[i], po.p[(i+1)%po.np]), psub(po.p[i], pu));
if (ZERO(d)) {
continue;
}
if (!sign) {
sign = (int)(d / fabs(d));
} else if (sign != (int)(d / fabs(d))) {
return 0;
}
}
return 1;
}
double
area(poly po) {
int i;
double ar=0.0;
for (i=1; i<po.np-1; i++) {
double a,b,c,s;
a = dist(po.p[0], po.p[i]);
b = dist(po.p[i], po.p[i+1]);
c = dist(po.p[0], po.p[i+1]);
s = (a+b+c)/2.0;
ar += sqrt(s*(s-a)*(s-b)*(s-c));
}
return ar;
}
double
coordy(punto p1, punto p2, double x) {
return p1.y + (x-p1.x)*(p2.y-p1.y) / (p2.x-p1.x);
}
punto
corte(punto p11, punto p12, punto p21, punto p22) {
punto p;
double A,B;
if (p11.x == p12.x) {
p.x = p11.x;
p.y = coordy(p21, p22, p.x);
return p;
}
if (p21.x == p22.x) {
p.x = p21.x;
p.y = coordy(p11, p12, p.x);
return p;
}
A = (p12.y - p11.y) / (p12.x - p11.x);
B = (p22.y - p21.y) / (p22.x - p21.x);
p.x = (p21.y - p11.y + A*p11.x - B*p21.x) / (A-B);
p.y = p11.y + A*(p.x-p11.x);
return p;
}
int
se_cortan(punto p11, punto p12, punto p21, punto p22) {
if (SIGN(cross(psub(p11,p12), psub(p11,p21))) * SIGN(cross(psub(p11,p12), psub(p11,p22))) == -1 &&
SIGN(cross(psub(p21,p22), psub(p21,p11))) * SIGN(cross(psub(p21,p22), psub(p21,p12))) == -1) {
return 1;
}
return 0;
}
poly
calc(poly po1, poly po2, int s) {
int i,j,k;
poly inter;
inter.np = 0;
inter.p = NULL;
for (i=0; i<po1.np; i++) {
if (inside(po1.p[i], po2)) {
int done=0;
#if DEBUG
printf("point (%d,%d) is inside poly 2\n", (int)po1.p[i].x, (int)po1.p[i].y);
#endif
for (k=0; k<inter.np; k++) {
if (ZERO(po1.p[i].x-inter.p[k].x) && ZERO(po1.p[i].y-inter.p[k].y)) {
done=1;
break;
}
}
if (!done) {
inter.p = realloc(inter.p, (inter.np+1)*sizeof(punto));
if (inter.np>500) abort();
if (!inter.p) abort();
inter.p[inter.np] = po1.p[i];
inter.np++;
}
}
}
for (i=0; i<po2.np; i++) {
if (inside(po2.p[i], po1)) {
int done=0;
#if DEBUG
printf("point (%d,%d) is inside poly 1\n", (int)po2.p[i].x, (int)po2.p[i].y);
#endif
for (k=0; k<inter.np; k++) {
if (ZERO(po2.p[i].x-inter.p[k].x) && ZERO(po2.p[i].y-inter.p[k].y)) {
done=1;
break;
}
}
if (!done) {
inter.p = realloc(inter.p, (inter.np+1)*sizeof(punto));
if (inter.np>500) abort();
if (!inter.p) abort();
inter.p[inter.np] = po2.p[i];
inter.np++;
}
}
}
for (i=0; i<po1.np; i++) {
int i1 = (i+1)%po1.np;
for (j=0; j<po2.np; j++) {
int j1 = (j+1)%po2.np;
if (se_cortan(po1.p[i], po1.p[i1], po2.p[j], po2.p[j1])) {
int done=0;
punto p = corte(po1.p[i], po1.p[i1], po2.p[j], po2.p[j1]);
#if DEBUG
printf("segmentos (%f,%f)-(%f,%f) y (%f,%f)-(%f,%f) se cortan en (%f,%f)\n",
po1.p[i].x, po1.p[i].y, po1.p[i1].x, po1.p[i1].y,
po2.p[j].x, po2.p[j].y, po2.p[j1].x, po2.p[j1].y,
p.x, p.y);
#endif
for (k=0; k<inter.np; k++) {
if (ZERO(p.x-inter.p[k].x) && ZERO(p.y-inter.p[k].y)) {
done=1;
break;
}
}
if (!done) {
inter.p = realloc(inter.p, (inter.np+1)*sizeof(punto));
if (inter.np>500) abort();
if (!inter.p) abort();
inter.p[inter.np] = p;
inter.np++;
}
}
}
}
#if DEBUG
printf("=> intersection has %d points:", inter.np);
for (i=0; i<inter.np; i++) {
printf(" (%f,%f)", inter.p[i].x, inter.p[i].y);
}
printf("\n");
#endif
convex_hull(inter.np, &inter.p[0]);
#if DEBUG
printf("=> Convex Hull of intersection:");
for (i=0; i<inter.np; i++) {
printf(" (%f,%f)", inter.p[i].x, inter.p[i].y);
}
printf("\n");
printf("area intersection = %f\n", area(inter));
#endif
return inter;
}
int
main(void) {
int i;
int n;
poly po1, po2, inter;
double a1, a2, a3;
int s=0;
while (1) {
scanf("%d", &n);
if (n==0) {
break;
}
po1.np = n;
po1.p = malloc(n*sizeof(punto));
if (po1.np>500) abort();
if (!po1.p) abort();
for (i=0; i<n; i++) {
scanf("%lf %lf", &po1.p[i].x, &po1.p[i].y);
}
scanf("%d", &n);
po2.np = n;
po2.p = malloc(n*sizeof(punto));
if (po2.np>500) abort();
if (!po2.p) abort();
for (i=0; i<n; i++) {
scanf("%lf %lf", &po2.p[i].x, &po2.p[i].y);
}
inter = calc(po1, po2, s);
/* for (i=0; i<10000000; i++) {n=i;} */
a1 = area(po1);
a2 = area(po2);
a3 = area(inter);
#if DEBUG
printf("area po1 = %8.2f\n", a1);
printf("area po2 = %8.2f\n", a2);
printf("area int = %8.2f\n", a3);
printf("=> = %8.2f\n", a1+a2-2.0*a3);
#endif
printf("%8.2f", a1+a2-2.0*a3);
free(po1.p);
free(po2.p);
free(inter.p);
s++;
}
printf("\n");
return 0;
}









