List<Polygon2d> Polygon2d::splittotris() { List<Polygon2d> ps; if (vs.len==3) { ps.add(*this); return ps; } for (int p=1;p<=vs.len;p++) for (int q=1;q<=vs.len;q++) { // Ensure we don't have the same or adjacent vertices if (p!=q && abs(p-q)>1 && abs(p-q)<vs.len) { Line2d l=Line2d(vs.num(p),vs.num(q)); // Check it doesn't cross the perimeter bool cross=false; for (int i=1;i<=vs.len && !cross;i++) { Line2d tl=Line2d(vs.num(i),vs.numwrap(i+1)); V2d *v=tl.findintersectionornull(l); if (v==NULL) cross=true; } if (!cross) { // We make two new polygons out of this one, and find their areas. ps.add(this->subpath(p,q).splittotris()); ps.add(this->subpath(q,p).splittotris()); return ps; } } } error("splittotris: Could not split polygon without crossing lines.\n"); // return NULL; }
float Polygon2d::area() { // printf("Finding area of polygon %i\n",vs.len); if (vs.len==3) { // Find area of triangle. // Split vertically into two // Get middle vertically vs.sort(&(V2d::gety)); V2d a=vs.num(1); V2d b=vs.num(2); V2d c=vs.num(3); // Find where vertical line crosses the horizontal of the middle point // i = A + k(C-A) // i = (l,B.y) // l = Ax+k(Cx-Ax) // By = Ay+k(Cy-Ay) float k=(b.y-a.y)/(c.y-a.y); V2d i=a+k*(c-a); float wid=floatabs(b.x-i.x); float ha=floatabs(a.y-b.y); float hc=floatabs(c.y-b.y); // a.print(); b.print(); c.print(); // printf("%f %f %f\n",wid,ha,hc); return 1.0/2.0*wid*(ha+hc); } // If larger than a triangle, need to split // Find a line between two vertices that does not cross the perimiter. for (int p=1;p<=vs.len;p++) for (int q=1;q<=vs.len;q++) { // Ensure we don't have the same or adjacent vertices if (p!=q && abs(p-q)>1 && abs(p-q)<vs.len) { // printf("Checking %i %i\n",p,q); Line2d l=Line2d(vs.num(p),vs.num(q)); // l.a.print(); l.b.print(); // Check it doesn't cross the perimeter bool cross=false; for (int i=1;i<=vs.len && !cross;i++) { // printf("%i\n",i); Line2d tl=Line2d(vs.num(i),vs.numwrap(i+1)); V2d *v=tl.findintersectionornull(l); if (v==NULL) cross=true; // printf("'\n"); //free(v); } if (!cross) { // printf("no crossing for %i %i\n",p,q); // We make two new polygons out of this one, and find their areas. Polygon2d tmpa=this->subpath(p,q); Polygon2d tmpb=this->subpath(q,p); return tmpa.area()+tmpb.area(); } // printf("Cross\n"); } } error("area: Could not split polygon without crossing lines.\n"); }
bool Polygon2d::contains(V2d v) { Line2d toinf=Line2d(v,V2d(10000,v.y)); int count=0; for (int i=1;i<=vs.len;i++) { Line2d t=Line2d(vs.num(i),vs.numwrap(i+1)); if (t.crosses(toinf)) count++; } return (intmod(count,2)==1); }
V3d *intersection(Line3d o) { //printf("\nTrying to find intersection %s-%s with %s-%s\n",a.toString(),b.toString(),o.a.toString(),o.b.toString()); Line2d la=Line2d(a.dropz(),b.dropz()); Line2d lb=Line2d(o.a.dropz(),o.b.dropz()); float f=la.findintersectionnum(lb); V3d lah=a+f*(b-a); float g=lb.findintersectionnum(la); V3d lbh=o.a+g*(o.b-o.a); //printf("Intersection (%f) %s == %s (%f) ?\n",f,lah.toString(),lbh.toString(),g); return new V3d(lah.x,lah.y,lah.z); if (lah==lbh) return new V3d(lah.x,lah.y,lah.z); //printf("Intersection failed.\n"); return NULL; }
Line2d Segment2d::getLine() const { float y = _end.getY() - _begin.getY(); float x = _end.getX() - _begin.getX(); Vector2d v(x, y); return Line2d(v, _begin); }
void Line2d :: GetNormal (Line2d & n) const { double ax = P2().X()-P1().X(), ay = P2().Y()-P1().Y(); Point2d mid(P1().X()+.5*ax, P1().Y()+.5*ay); n=Line2d(mid,Point2d(mid.X()+ay,mid.Y()-ax)) ; }
Line2d line() { // Region::list=NULL; Blob::remakelist(); float a=angle(); // printf("%f\n",a); V2d v=V2d(sin(a+pi/2.0),cos(a+pi/2.0))*(float)sqrt(Region::list->len); V2d c=centroid(); // printf("Made proper line length %f List %i\n",v.mod(),Region::list->len); return Line2d(c-v,c+v); }
Line2d intersection(Plane p) { Viewpoint v=orientor(); Plane pp=bring(v); // Where does pp meet this plane? // (X-PPP).PPN=0 // X=(x,y,0) // (x-pppx)*pppnx+(y-pppy)*pppny+pppz*pppnz=0 // y=(-pppz*pppnz+(pppx-x)*pppnx)/pppny+pppy #define yfrom(i) (-pp.pos.z*pp.nor.z+(pp.pos.x-(i))*pp.nor.x)/pp.nor.y+pp.pos.y Line2d l=Line2d(V2d(-100.0,yfrom(-100.0)),V2d(100.0,yfrom(100.0))); // Line3d t=Line3d(l); // t=t.orient(v); return l; }
void main(int argc,String *argv) { ArgParser a=ArgParser(argc,argv); int w=a.intafter("-w","width",275); int h=a.intafter("-h","height",116); int numpts=a.intafter("-n","number of points",100); a.done(); FILE *file=fopen("region.txt","wa"); fprintf(file,"[Normal]\n"); fprintf(file,"Numpoints=%i\n",numpts); V2d cen=V2d((float)w/2.0,(float)h/2.0); for (int i=0;i<numpts;i++) { V2d a=10.0*(w+h)*V2d::angle(-pi/4.0+2.0*pi*(float)i/(float)numpts); a=a+cen; if (a.x<0) a=Line2d(cen,a).intersect(Line2d(V2d(0,0),V2d(0,1))); if (a.y<0) a=Line2d(cen,a).intersect(Line2d(V2d(0,0),V2d(1,0))); if (a.x>w) a=Line2d(cen,a).intersect(Line2d(V2d(w,0),V2d(w,1))); if (a.y>h) a=Line2d(cen,a).intersect(Line2d(V2d(0,h),V2d(1,h))); a=a-cen; float rnd=myrnd(); a=a*rnd; a=a+cen; fprintf(file,"%i,%i",(int)a.x,(int)a.y); if (i<numpts-1) fprintf(file,", "); } fprintf(file,"\n"); fclose(file); }
void line(int x1, int y1, int x2, int y2,CT r) { Line2d l=Line2d(V2d(x1,y1),V2d(x2,y2)); String s=Sformat("Clipping %s...\n",l.toString()); // l.clipbyrectangle(0,0,width-1,height-1); // printf(" got %s...\n",l.toString()); x1=l.a.x; x2=l.b.x; y1=l.a.y; y2=l.b.y; // if (inbmp(x1,y1) && inbmp(x2,y2)) { List<Pixel> ps=Pixel::line(Pixel(x1,y1),Pixel(x2,y2)); for (int i=1;i<=ps.len;i++) { // printf("Setting pixel %s\n",ps.num(i).toString()); setpixel(ps.num(i),r); } ps.freedom(); // } else // printf("%sDidn't write line because got %s when clipped\n",s,l.toString()); free(s); }
int Polygon2d :: IsOn (const Point2d & p) const { int i; for (i = 1; i <= points.Size(); i++) { const Point2d & p1 = points.Get(i); const Point2d & p2 = points.Get(i%points.Size()+1); if (IsOnLine (Line2d(p1, p2), p)) return 1; } return 0; /* CURSOR c; Point2d * p1, * p2; p2 = points[points.Last()]; for (c = points.First(); c != points.Head(); c++) { p1 = p2; p2 = points[c]; if (IsOnLine (Line2d(*p1, *p2), p)) return 1; } return 0; */ }
Line2d Correlator::line() { V2d c=centroid(); V2d o=ori(); return Line2d(c,c+o); }
float affinity(Region *a,Region *b) { Line2d l=Line2d(a->centroid(),b->centroid()); return affinity(a,l)*affinity(b,l); }
Line2d Polygon2d::linefrom(int i) { return Line2d(vs.wrapnum(i),vs.wrapnum(i+1)); }
int TRIANGLE2D :: IsOn (const Point2d & p) const { return IsOnLine (Line2d (p1, p2), p) || IsOnLine (Line2d (p1, p3), p) || IsOnLine (Line2d (p2, p3), p); }
int PTRIANGLE2D :: IsOn (const Point2d & p) const { return IsOnLine (Line2d (*p1, *p2), p) || IsOnLine (Line2d (*p1, *p3), p) || IsOnLine (Line2d (*p2, *p3), p); }
void lookforparagraphs() { for (int i=1;i<=bs.len;i++) { Blob *b=bs.p2num(i); if (!b->blobbed && b->gettype()==Paragraph && b->sentcnt>=3) { printf("Inspecting a paragraph...\n"); // Is it expandable? (Are there any other blobs within 2*line spacing?) float ld=LineSpace*b->linedist(); bool found=false; for (int j=1;j<=bs.len && !found;j++) if (j!=i && !bs.p2num(j)->blobbed) if (closestdist(i,j)<ld) found=true; if (!found) { // Recover paragraph b->type=Block; RGBmp out=RGBmp(rm.width,rm.height); b->plot(&out); // An early bit of the VVP function // Find vertical line through centres of text lines Correlator c=Correlator(); for (int i=1;i<=b->lines.len;i++) c.add(bs.p2num(b->lines.num(i))->centroid); Line2d l=Line2d(c.centroid(),c.centroid()+c.ori().norm()); c.freedom(); out.line(l.a,l.a+(l.b-l.a)*200,myRGB::red); printf("Finding HVP...\n"); // Intersect all lines in paragraph with each other and cluster (by averaging!) V2d hvpl=V2d(0,0); V2d hvpr=V2d(0,0); int cnte=b->lines.len*(b->lines.len-1)/2; int cntl=0; int cntr=0; int cntt=0; for (int i=1;i<=b->lines.len;i++) { Line2d la=bs.p2num(b->lines.num(i))->line(); out.line(la,myRGB::yellow); for (int j=1;j<=b->lines.len;j++) { if (i!=j) { Line2d lb=bs.p2num(b->lines.num(j))->line(); V2d li=la.findintersection(lb); if ((li-b->centroid).mag()<10000000) { out.line(la.center(),li,myRGB::white*0.5); out.line(lb.center(),li,myRGB::white*0.5); if (l.whichsideis(li)<0) { cntl++; hvpl=hvpl+li/(float)cnte; } else { cntr++; hvpr=hvpr+li/(float)cnte; } } cntt++; printf("Intersect distance: %.2f\n",(li-b->centroid).mag()); } } } V2d hvp=( cntl>cntr ? hvpl : hvpr ); int cnt=( cntl>cntr ? cntl : cntr ); printf("Intersections on left %i right %i\n",cntl,cntr); if (cntl>cntr) printf("HPP found on left with %i intersections out of %i\n",cntl,cntt); else printf("HPP found on right with %i intersections out of %i\n",cntl,cntt); if (cnt!=cnte) { printf("Got count %i for HVP wrong, actually used %i intersections!\n",cnte,cnt); hvp=hvp*(float)cnte; hvp=hvp/(float)cnt; } printf("HVP=%s\n",hvp.toString()); float zh=(b->centroid-hvp).mag(); printf("Distance to HVP: %f\n",zh); if (!(zh<bigfloat*10.0)) { zh=bigfloat*10.0; hvp=b->centroid+(hvp-b->centroid).norm()*zh; zh=(b->centroid-hvp).mag(); if (!(zh<bigfloat*10.0)) { zh=bigfloat*10.0; hvp=b->centroid+V2d(-1,0)*zh; } printf(" too large: now %f %s\n",zh,hvp.toString()); } // printf("Plotting lines..."); for (int i=1;i<=b->lines.len;i+=b->lines.len-1) out.line(hvp,bs.p2num(b->lines.num(i))->centroid,myRGB::green); printf("Finding VVP...\n"); // Estimate distance of vanishing point Correlator c2=Correlator(); V2d lineori=b->lineori(); // *** Try average base size in a line // Doing linear correlation with line width float scale=1.0; for (int i=1;i<=b->lines.len;i++) { V2d cen=bs.p2num(b->lines.num(i))->centroid; float x=(cen-l.a).dot((l.b-l.a).norm()); float y=bs.p2num(b->lines.num(i))->width(); // Area of region! (used to be ->height()) // (used to be ->area()) printf("%f , %f\n",x,y); out.cross(l.a+(l.b-l.a).norm()*x+lineori*y*scale,5,myRGB::white); c2.add(x,y); } /* float scale=5.0; for (int i=1;i<=b->lines.len-1;i++) { // not -1 for height V2d cen=bs.p2num(b->lines.num(i))->centroid; float x=(cen-l.a).dot((l.b-l.a).norm()); // float y=bs.p2num(b->lines.num(i))->height(); // line (character) height float y=b->linedist(i); // line spacing if (y>0.5) { // Bodge to ensure two lines which should be the same are not used printf("%f , %f\n",x,y); out.cross(l.a+(l.b-l.a).norm()*x+lineori*y*scale,5,myRGB::white); c2.add(x,y); } }*/ // Doing linear correlation with base sizes. Too noisy! /* float scale=3.0; for (int i=1;i<=b->bases.len;i++) { V2d cen=bs.p2num(b->bases.num(i))->centroid; float x=(cen-l.a).dot((l.b-l.a).norm()); float y=bs.p2num(b->bases.num(i))->area; // Area of region! (used to be ->height()) printf("%f , %f\n",x,y); if (y>10) { out.cross(l.a+(l.b-l.a).norm()*x+lineori*y*scale,5,myRGB::white); c2.add(x,y); } else { out.cross(l.a+(l.b-l.a).norm()*x+lineori*y*scale,5,myRGB::green*0.5); } }*/ float z=c2.crossesyxoutliers(); // Check the line we get is worth anything by plotting it! float tx=(bs.p2num(b->lines.num(1))->centroid-l.a).dot((l.b-l.a).norm()); float ty=c2.yforx(tx); printf("First should be approx %f,%f\n",tx,ty); V2d lin1=l.a+(l.b-l.a).norm()*tx+lineori*ty*scale; tx=(bs.p2num(b->lines.num(b->lines.len))->centroid-l.a).dot((l.b-l.a).norm()); ty=c2.yforx(tx); printf("Last should be approx %f,%f\n",tx,ty); V2d lin2=l.a+(l.b-l.a).norm()*tx+lineori*ty*scale; out.line(lin1,lin2,myRGB::white); if (!(z>=-bigfloat && z<=bigfloat)) { printf("VP too far away (areas suggested %f)!\n",z); z=bigfloat; } printf("Distance to VVP: %f (originally %f)\n",z,z); c2.freedom(); V2d vvp=l.a+(l.b-l.a).norm()*z; printf("VVP=%s\n",vvp.toString()); Line2d enil=bs.p2num(b->lines.num(1))->line(); out.line(vvp,enil.a,myRGB::magenta); out.line(vvp,enil.b,myRGB::magenta); enil=bs.p2num(b->lines.num(b->lines.len))->line(); out.line(vvp,enil.a,myRGB::magenta); out.line(vvp,enil.b,myRGB::magenta); float hva=(b->centroid-hvp).angle(); float hvb=hva; float vva=(b->centroid-vvp).angle(); float vvb=vva; printf("Centre angles: H=%.2f V=%.2f\n",hva*rad2deg,vva*rad2deg); for (int i=1;i<=b->bpixs.len;i++) { V2d v=V2d(b->bpixs.num(i)); float ha=(v-hvp).angle(); float va=(v-vvp).angle(); if (angleless(ha,hva)) hva=ha; if (angleless(hvb,ha)) hvb=ha; if (angleless(va,vva)) vva=va; if (angleless(vvb,va)) vvb=va; // printf("Angles: H: %.2f< %.2f >%.2f V: %.2f< %.2f >%.2f\n",hva,ha,hvb,vva,va,vvb); } printf("Edge angles: H: %.2f-%.2f V: %.2f-%.2f\n",hva*rad2deg,hvb*rad2deg,vva*rad2deg,vvb*rad2deg); float vd=b->parawidth()*0.2/myabs(z); printf("Vertical margin angle %f degrees.\n",vd*360.0/2.0/pi); Line2d left=Line2d(vvp,vvp+V2d::angle(vvb+vd)*zh); Line2d right=Line2d(vvp,vvp+V2d::angle(vva-vd)*zh); float hd=b->paraheight()*0.2/zh; printf("Horizontal margin angle %f degrees.\n",hd*360.0/2.0/pi); Line2d top=Line2d(hvp,hvp+V2d::angle(hva-hd)*z); Line2d bottom=Line2d(hvp,hvp+V2d::angle(hvb+hd)*z); printf("Outer lines are\nleft=%s\nright=%s\ntop=%s\nbottom=%s\n",left.toString(),right.toString(),top.toString(),bottom.toString()); V2d tl=top.intersect(left); V2d tr=top.intersect(right); V2d bl=bottom.intersect(left); V2d br=bottom.intersect(right); printf("Outer corners are\ntl=%s\ntr=%s\nbr=%s\nbl=%s\n",tl.toString(),tr.toString(),br.toString(),bl.toString()); out.line(tl,tr,myRGB::yellow); out.line(tr,br,myRGB::yellow); out.line(br,bl,myRGB::yellow); out.line(bl,tl,myRGB::yellow); blockswritten++; out.writefile(Sformat("block%i.bmp",blockswritten)); // rm.applyfn(&finddad)->hueify().writefile(Sformat("block%ilines.bmp",blockswritten)); out.freedom(); /* printf("Recovering quad...\n"); List<V2d> qs; qs.add(tl); qs.add(tr); qs.add(br); qs.add(bl); RGBmp *n=image->recoverquad(&qs,1,600); n->writefile(Sformat("recover%i.bmp",blockswritten)); printf(" done\n"); */ printf("Recovering quad...\n"); List<V2d> qs; qs.add(tl*origimage->width/image->width); qs.add(tr*origimage->width/image->width); qs.add(br*origimage->width/image->width); qs.add(bl*origimage->width/image->width); RGBmp *n=origimage->recoverquad(&qs,1,600); n->writefile(Sformat("recover%i.bmp",blockswritten)); printf(" done\n"); // Write quadrilateral point to text file (0,0)-(1,1) List<String> qd; qd.add("Quad points {topleft,topright,bottomright,bottomleft}"); qd.add(Sformat("%f %f",tl.x/image->width,tl.y/image->height)); qd.add(Sformat("%f %f",tr.x/image->width,tr.y/image->height)); qd.add(Sformat("%f %f",br.x/image->width,br.y/image->height)); qd.add(Sformat("%f %f",bl.x/image->width,bl.y/image->height)); writelinestofile(qd,Sformat("quad%i.dat",blockswritten)); // Remove paragraph from blobs b->blobbed=true; } } } }
Line2d line() { V2d o=ori()*width(); return Line2d(centroid-o,centroid+o); }
Line2d Line2d::getPerpendicular(const Vector2d &point) const { Vector2d v(1, _b / _a); return Line2d(v, point); }
Line2d Viewpoint::lookAtLine3D(const Line3d& l3d){ return Line2d(lookAtPoint3D(l3d.p1), lookAtPoint3D(l3d.p2)); }