#include "vec.h" struct crosspoint { int flag; double t; }; int clipcheck(Vector *v, double w, double h) { int flag=0; if (v->x < -w) flag |= 0x2; else if (v->x > w) flag |= 0x1; if (v->y < -h) flag |= 0x20; else if (v->y > h) flag |= 0x10; return(flag); } int clip(Vector *p, Vector *q, int w, int h, Vector *ans1, Vector *ans2) { Vector a,b,c; int aflag, bflag, cflag, i, j; struct crosspoint cross[4]; double t; a = *p; b = *q; aflag=clipcheck(&a,w,h); bflag=clipcheck(&b,w,h); if ((aflag&0xf) && (aflag&0xf)==(bflag&0xf)) return(0); /* 端点がともにx軸方向にはずれている */ if ((aflag&0xf0) && (aflag&0xf0)==(bflag&0xf0)) return(0); /* 端点がともにy軸方向にはずれている */ if (!aflag && !bflag) { /* 両端点が視野内にある */ *ans1 = a; *ans2 = b; return(1); } if (!bflag) { /* 端点の一方だけが視野内にあればそれを a とする */ c = a; a = b; b = c; cflag = aflag; aflag = bflag; bflag=cflag; } t = b.y - a.y; if (abs(t) > 1e-10 && (t = (h-a.y)/t) >= 0.0 && t <= 1.0) { /* y=h */ cross[3].flag=1; cross[3].t = t; } else cross[3].flag=0; t = b.y - a.y; if (abs(t) > 1e-10 && (t = (-h-a.y)/t) >= 0.0 && t <= 1.0) { /* y=-h */ cross[2].flag=1; cross[2].t = t; } else cross[2].flag=0; t = b.x - a.x; if (abs(t) > 1e-10 && (t = (w-a.x)/t) >= 0.0 && t <= 1.0) { /* x=w */ cross[1].flag=1; cross[1].t = t; } else cross[1].flag=0; t = b.x - a.x; if (abs(t) > 1e-10 && (t = (-w-a.x)/t) >= 0.0 && t <= 1.0) { /* x=-w */ cross[0].flag=1; cross[0].t = t; } else cross[0].flag=0; if (!aflag) { /* 端点の一方が視野内にあれば */ t = 100000; /* large value (dummy) */ for (i=0; i<4; ++i) { if (cross[i].flag == 0) continue; if (cross[i].t >= 0.0 && cross[i].t < t) { t = cross[i].t; } } if (t > 1.0) { char *p=(char *)0; fprintf(stderr,"something bad %f",t); *p = 0; return(0); } vsub(&b,&a,&c); /* c = a + t(b-c)*/ smul(t,&c,&c); vadd(&a,&c,&c); *ans1 = a; *ans2 = c; return(1); } /* 両端点が視野外にある */ j = 0; for (i=0; i<4; ++i) { if (cross[i].flag) { vsub(&b,&a,&c); /* c = a + t(b-c)*/ smul(t,&c,&c); vadd(&a,&c,&c); if (c.x <= w+1e-5 && c.x >= -(w+1e-5) && c.y <= h+1e-5 && c.y >= -(h+1e-5)) { if (j==0) { *ans1=c; } else if (j==1) { *ans2=c; return(1); } } } } return(0); }