// CPP program to disect a polyhedra in vrml format // and output it in jvx format #include #include #include #include #include #include #include #include #include /* #define PRINT_INT #define PRINT_MERGE #define PRINT_HIDE */ /** * couple of templates to treat vectors cyclically */ template void rotate_to_set(vector&,const T,const T); template vector merge_at(vector,vector,const T,const T); template void clean_spikes(vector &); template void rotate_to_set(vector& vec,const T a,const T b) { vector::iterator i; vector::iterator j; /* need to find i,j which are consecutive */ i = vec.begin(); while(i!=vec.end()) { i = find(i,vec.end(),a); if(i == vec.end() ) break; if(i == vec.begin() ) { j = i+1; if( *j == b) break; j = vec.end()-1; if( *j == b ) break; } else if(i == vec.end()-1) { j = i-1; if( *j == b) break; j = vec.begin(); if( *j == b ) break; } else { j = i+1; if( *j == b) break; j = i-1; if( *j == b) break; } ++i; } if(i==vec.end() || j == vec.end()) { cerr << "Rotate_to_set failed 198\n!"; return; } if(i == vec.begin()) { if(j == i + 1) { // the state we want do nothing } else if(j == vec.end()-1 ) { rotate(vec.begin(),i+1,vec.end()); reverse(vec.begin(),vec.end()); } else { cerr << "Wierdness in cycle\n"; } } else if(j == vec.begin()) { if(i==j+1) { rotate(vec.begin(),i+1,vec.end()); reverse(vec.begin(),vec.end()); } else if(i==vec.end()-1) { rotate(vec.begin(),i,vec.end()); } else { cerr << "Wierdness in cycle\n"; } } else if(i vector merge_at(vector vec1,vector vec2,const T a,const T b) { rotate_to_set(vec1,a,b); rotate_to_set(vec2,b,a); //cout << "c1 (" << c1 << ")\n"; //cout << "c2 (" << c2 << ")\n"; vector c(0); vector::iterator i; for(i=vec1.begin()+1;i!=vec1.end();++i) c.push_back(*i); for(i=vec2.begin()+1;i!=vec2.end();++i) c.push_back(*i); return c; } template void clean_spikes(vector &vec) { int size = vec.size(); vector::iterator i; bool more_to_do = true; while(more_to_do) { more_to_do = false; if(vec.size() <= 2) { vec.clear(); return; } for(i=vec.begin();i!=vec.end();++i) { vector::iterator previ; vector::iterator nexti; previ = ( i==vec.begin() ? vec.end()-1 : i-1); nexti = (i==vec.end()-1 ? vec.begin() : i+1); if(*previ == *nexti) { //cerr << "\nClean spikes (" << vec << ") -> ("; if(i==vec.begin()) { vec.erase(vec.end()-1); vec.erase(i); } else if(i==vec.end()-1) { vec.erase(vec.end()-1); vec.erase(vec.begin()); } else { vec.erase(previ,nexti); } //cerr << vec << ")\n"; more_to_do = true; break; } else if(*i == *nexti) { vec.erase(i); more_to_do = true; break; } } } /* if(vec.size() == 4) { if((vec[0] == vec[1] && vec[2] == vec[3]) ||(vec[0] == vec[2] && vec[1] == vec[3]) ||(vec[0] == vec[3] && vec[1] == vec[2])) vec.clear(); } */ } class Point { double coords[3]; public: const static double limit=0.000001; Point(double xx=0.0,double yy=0.0,double zz=0.0) { coords[0]=xx; coords[1]=yy; coords[2]=zz; }; // Point(const Point &p) friend ostream& operator<<(ostream&,const Point&); friend Point operator+ (const Point&,const Point&); friend Point operator- (const Point&,const Point&); friend Point operator* (double,const Point&); friend Point operator^ (const Point&,const Point&); // vector product friend double dot(const Point&,const Point&); // dot product friend bool parallel(const Point&,const Point&); // whether two vectors are parallel friend double lensq(const Point&); // square of the length bool unit(); void flip(); }; inline ostream& operator<<(ostream& os,const Point& p) { os << p.coords[0] << " " << p.coords[1] << " " << p.coords[2]; } inline Point operator+ (const Point& a,const Point& b) { Point p(a.coords[0]+b.coords[0],a.coords[1]+b.coords[1],a.coords[2]+b.coords[2]); return p; } inline Point operator- (const Point& a,const Point& b) { Point p(a.coords[0]-b.coords[0],a.coords[1]-b.coords[1],a.coords[2]-b.coords[2]); return p; } inline Point operator* (double d,const Point& a) { Point p(d* a.coords[0],d*a.coords[1],d*a.coords[2]); return p; } inline double dot(const Point& a,const Point& b) { return a.coords[0]*b.coords[0]+a.coords[1]*b.coords[1]+a.coords[2]*b.coords[2]; } inline double lensq(const Point& a) { return a.coords[0]*a.coords[0]+a.coords[1]*a.coords[1]+a.coords[2]*a.coords[2]; } inline Point operator^ (const Point& a,const Point& b) { Point p(a.coords[1]*b.coords[2]-a.coords[2]*b.coords[1], a.coords[2]*b.coords[0]-a.coords[0]*b.coords[2], a.coords[0]*b.coords[1]-a.coords[1]*b.coords[0]); return p; } inline bool Point::unit() { double len = sqrt(coords[0]*coords[0] + coords[1] * coords[1] + coords[2] * coords[2]); if(len!=len || len < limit) { coords[0] = coords[1] = coords[2] = 0.0; return false; } coords[0] /= len; coords[1] /= len; coords[2] /= len; return true; } inline void Point::flip() { coords[0] = -coords[0]; coords[1] = -coords[1]; coords[2] = -coords[2]; } inline bool parallel(const Point& a,const Point& b) { return lensq(a^b) < Point::limit; } /** * A functional class * returns true if lensq(p) < dist - Point::limit */ class DistPred { double dist; public: DistPred(double d) {dist = d;}; bool operator() (const Point &p) { bool flag = lensq(p) < dist - Point::limit; // cerr << "DIstPred " << flag << endl; return flag;} }; /** * Face: a ordered list of indicies to the points array */ class Face { public: vector indices; Face(vector in) {indices = in;} friend ostream& operator<<(ostream&,const Face&); friend void printFacePoints(ostream &,const Face&); }; ostream& operator<<(ostream& os,const Face& f) { for(int j=0;j < f.indices.size();++j) os << f.indices[j] << " "; return os; } /** * A colour value */ class ColourInfo { int r,g,b; // rgb colours 0..255 public: ColourInfo(int rr=-1,int gg=-1,int bb=-1) { r = rr; g=gg; b=bb; } ColourInfo(const ColourInfo &c) { r = c.r; g=c.g; b=c.b; } void setColour(int rr,int gg,int bb) { r = rr; g = gg; b = bb; } friend ostream& operator<<(ostream& os,const ColourInfo& c); }; ostream& operator<<(ostream& os,const ColourInfo& c) { os << c.r << " " << c.g << " " << c.b; } /** * A plane */ class Plane { public: Point normal; // outward pointing normal double d; // minimum distance from origin Plane() : normal() { d = 0.0; } // uses default constructor for normal Plane(const Point &n,double dd) : normal(n) { if( dd < 0 ) { d = -dd; normal.flip(); } else d = dd; } double dist(const Point &p) const { return (dot(p,normal) - d); } // the distance from the plane along normal }; /** * A face with info on facial plane */ class NFace : public Face, public Plane { void calcPlane(); public: NFace(vector in) : Plane() , Face(in) { calcPlane(); }; NFace(vector in,const Plane &p) : Plane(p) , Face(in) {}; NFace(vector in,const Point &p,double dd) : Plane(p,dd) , Face(in) {}; NFace(vector in,const NFace &f2) : Face(in), Plane(f2) {}; }; /** * A face with colour info and plane info */ class NCFace : public NFace, public ColourInfo { public: NCFace(vector in) : NFace(in) , ColourInfo() {}; NCFace(vector in,const Plane &p) : NFace(in,p) , ColourInfo() {}; NCFace(vector in,const Point &p,double dd) : NFace(in,p,dd) , ColourInfo() {}; NCFace(vector in,const ColourInfo &c) : NFace(in) , ColourInfo(c) {}; NCFace(vector in,const Plane &p,const ColourInfo &c) : NFace(in,p) , ColourInfo(c) {}; NCFace(vector in,const Point &p, double dd,const ColourInfo &c) : NFace(in,p,dd) , ColourInfo(c) {}; NCFace(vector in,const NCFace &f2) : NFace(in,f2) , ColourInfo(f2) {}; }; /** * The end class in the Face hieraracy * good determins whether we print the face at the end * TODO: add list of faces which have been done */ class MyFace : public NCFace { public: bool good; // whether we want to print in final ouput friend bool no_good(const MyFace &f); int originalIndex,Findex; vector linkingFaces; void setFindex(int i) { Findex = i; }; MyFace(vector in) : NCFace(in) { good = true; }; MyFace(vector in,const Plane &p) : NCFace(in,p) { good = true; }; MyFace(vector in,const Point &p,double dd) : NCFace(in,p,dd) { good = true; }; MyFace(vector in,const ColourInfo &c) : NCFace(in,c) {good = true; }; MyFace(vector in,const Plane &p,const ColourInfo &c) : NCFace(in,p,c) {good = true; }; MyFace(vector in,const Point &p, double dd,const ColourInfo &c) : NCFace(in,p,dd,c) {good = true; }; MyFace(vector in,const MyFace &f2) : NCFace(in,f2) {good = true; originalIndex = f2.originalIndex; }; }; bool no_good(const MyFace &f) { return !f.good; }; /** * EdgeKey used for constructing a hash table for edges */ class EdgeKey { public: int a,b; EdgeKey(int aa,int bb) { if(aa faces; Edge() {}; void addFace(MyFace *f) { faces.push_back(f); } }; /******************* Global variable *******************/ vector points; // the list of points needs to be up here as used by NFace list faces; // the list of faces list newfaces; // new faces added vector originalfaces; // the list of faces map edges; string polyname; // contains the name of the polyhedron void NFace::calcPlane() { if(indices.size()<3) { cerr << "Face with only two points found\n"; d = 0.0; } Point &f1a = points[indices[0]]; Point &f1b = points[indices[1]]; Point &f1c = points[indices[2]]; Point a1 = f1a-f1b; Point b1 = f1c-f1b; normal = a1^b1; // normal for face1 if( !normal.unit() ) { cerr << "Normal for face is zero\n"; d = 0.0; return; } d = dot(normal,f1b); // distance from origin for face1 if(d<0) { d = -d; normal.flip(); } } /******************* input routines *******************/ void readPoints() { Point buf; string str; char ch; getline(cin,str); getline(cin,str); getline(cin,str); // read until ) is reached while(cin>>ch && ch!=')'); cin.get(ch); getline(cin,polyname); // now gobble until point[ while(1) { getline(cin,str); if(str.find("point[") != string::npos) break; } while(1) { double x,y,z; if( (cin >> x ) ) { cin >> y >> z >> ch; // cout << "read " << x << " " << y << " " << z << " " << ch << endl; points.push_back(Point(x,y,z)); } else { cin.clear(); cin>>ch; if(ch == '#' ) { getline(cin,str); } else { break; } } } } /** * readFaces(bool joinFlag) * if join flag is true then each face is like * 0,1,12,-1,1,6,12,-1,6,9,12,-1,9,2,12,-1,2,0,12,-1, */ void readFaces(int joinFlag) { string str; vector indices; char ch; int a; // first gobble until point[ while(1) { getline(cin,str); if(str.find("coordIndex[") != string::npos) break; } if(joinFlag == 1) { while(1) { // 0,1,12,-1,1,6,12,-1,6,9,12,-1,9,2,12,-1,2,0,12,-1, getline(cin,str); istream *inptr; inptr = new istrstream(str.c_str()); istream &input = *inptr; if( !(input >> a >> ch) ) break; // catch the end of the faces indices.push_back(a); while( input >> a >> ch) { if(a != -1) indices.push_back(a); } // delete input; vector goodind; for(int i=0;i> a >> ch) ) break; // catch the end of the faces indices.push_back(a); while( input >> a >> ch) { if(a != -1) indices.push_back(a); } // delete input; vector goodind; for(int i=0;i intersectPoints; int size = goodind.size(); for(int i=0;i -Point::limit) continue; double lambda = (matD*(ax-cx)-matB*(ay-cy))/det; double mu = (-matC*(ax-cx)+matA*(ay-cy))/det; if(lambda < 0.0+Point::limit || lambda > 1.0-Point::limit) continue; Point p = origin + (1-lambda)*a + lambda*b; intersectPoints.push_back(p); } } if(intersectPoints.size() == 0) { faces.push_back(MyFace(goodind)); originalfaces.push_back(MyFace(goodind)); MyFace &createdface = faces.back(); createdface.originalIndex = originalfaces.size()-1; } else { vector::iterator k,l; vector intersectInd(intersectPoints.size()); vector junk; int kk,ll; double dist1 = lensq(intersectPoints[0]); double dist2 = lensq(intersectPoints[1]); double maxdist = (dist1>dist2 ? dist1 : dist2); double mindist = (dist1>dist2 ? dist2 : dist1); if( maxdist - mindist > Point::limit) { DistPred mydp(maxdist); remove_copy_if(intersectPoints.begin(),intersectPoints.end(),back_inserter(junk),mydp); intersectPoints.clear(); copy(junk.begin(),junk.end(),back_inserter(intersectPoints)); } // add the intersectPoints to points //cerr << "Interior pts " << endl; for(k=intersectPoints.begin(),kk=0;k!=intersectPoints.end();++k,++kk) { for(l=points.begin(),ll=0;l!=points.end();++l,++ll) { if(lensq(*k-*l) < Point::limit ) { intersectInd[kk] = ll; break; } } if(l==points.end()) { intersectInd[kk] = ll; points.push_back(intersectPoints[kk]); } //cerr << intersectInd[kk] << ' '; } //cerr << "\nFinal "; int lastvert = -1; int curextvert = 0; int curintvert = -1; vector finalind; do { //cerr << goodind[curextvert] << ' '; finalind.push_back(goodind[curextvert]); // find the closest interior vert to ext vert Point &a = points[goodind[curextvert]]; double mindist = 10.0; int minind = -1; //cerr << "curintvert " << curintvert << endl; for(int i =0;i interiorverts; for(int i=1;i starverts; starverts.push_back(finalind[0]); starverts.push_back(finalind[1]); starverts.push_back(finalind[finalsize-1]); faces.push_back(MyFace(starverts,createdface)); for(int i=1;i> a >> ch) { if(a != -1) indices.push_back(a); else { faces.push_back(MyFace(indices)); originalfaces.push_back(MyFace(indices)); indices.clear(); } } } cin.clear(); } /*********************** output routines ****************/ void print_head() { cout << "\n"; cout << "\n"; cout << " \n"; cout << " \n"; cout << " 0.02\n"; cout << " " << polyname << "\n"; cout << " \n"; cout << " \n"; cout << " Richard\n"; cout << " Morris\n"; cout << " \n"; cout << " Dept Statistics, University of Leeds\n"; cout << "
\n"; cout << " Leeds\n"; cout << " LS2 9JT\n"; cout << "
\n"; cout << "
\n"; cout << " webmaster@pfaf.org, rjm@amsta.leeds.ac.uk\n"; cout << " www.pfaf.org\n"; cout << "
\n"; cout << "
\n"; cout << " \n"; cout << " A uniform polyhedra.\n"; cout << " \n"; cout << " This surface was evolved while working on the\n"; cout << " \n"; cout << " \n"; cout << " uniform polyhedra\n"; cout << " " << polyname << "\n"; cout << " \n"; cout << " \n"; cout << " 52B10\n"; cout << " 52B99\n"; cout << " 51M20\n"; cout << " \n"; cout << " Kalidio data for polyhedra triangulation by rjm - optional -\n"; cout << " \n"; cout << " \n"; cout << " \n"; cout << " \n"; } void print_mid() { cout << " \n"; cout << " \n"; } void print_tail() { cout << " \n"; cout << " \n"; cout << " \n"; cout << "
\n"; } void print_points() { typedef vector::const_iterator VI; cout << " \n"; for(VI i=points.begin();i!=points.end();++i) { Point p = *i; cout << "

" << p << "

\n"; } cout << "
\n"; } void print_faces() { int ii,count=0; list::const_iterator i; cout << " \n"; for(i=faces.begin(),ii=0;i!=faces.end();++i,++ii) { MyFace f = *i; if( f.good && f.indices.size() > 0 ) { Face &ff = f; cout << "" << ff << "\n"; ++count; } } cout << " \n"; cerr << "Printed " << count << " faces\n"; } void print_face_colours() { int ii; list::const_iterator i; cout << " \n"; for(i=faces.begin(),ii=0;i!=faces.end();++i,++ii) { MyFace f = *i; if( f.good ) { ColourInfo &c = f; cout << "" << c << "\n"; } } cout << " \n"; } void printFacePoints(ostream & os,const MyFace& f) { os << "Face:\n"; for(int j=0;j < f.indices.size();++j) { os << points[f.indices[j]] << endl; } } void print(const bool colourFlag) { print_head(); print_points(); print_mid(); print_faces(); if(colourFlag) print_face_colours(); print_tail(); } /********************** intersection routines *******************/ /** * bool intersectPlane(const Point &v,const double d,Face &f) * returns true if the face iteresects the plane * sideeffects: will add and delete faces from the list of faces if an intersection is found * will also add points */ bool intersectPlane(MyFace &f,const MyFace &f2) { // find first point not on line int j; // primary loop variable int size = f.indices.size(); int signs[size]; double dists[size]; bool plusFlag=false,minusFlag=false; for(j=0;j < size;++j) { double dist0; dist0 = f2.dist(points[f.indices[j]]); dists[j] = dist0; if( dist0 > Point::limit ) { signs[j] = 1; plusFlag = true; } else if( dist0 < - Point::limit ) { signs[j] = -1; minusFlag = true; } else signs[j] = 0; } if(!plusFlag || !minusFlag) return false; // check second face actuall crosses first face /* plusFlag=false,minusFlag=false; for(j=0;j < f2.indices.size();++j) { double dist0; dist0 = f.dist(points[f2.indices[j]]); if( dist0 > Point::limit ) { plusFlag = true; if(minusFlag) break; } else if( dist0 < - Point::limit ) { minusFlag = true; if(plusFlag) break; } } if(!plusFlag || !minusFlag) return false; */ // We know there is some intersection f.good = false; #ifdef PRINT_INT cerr << "Intersection with plane face " << f.indices << " points "; for(j=0;j < size;++j) cerr << dists[j] << " " ; cerr << endl; cerr << "Plane (" << f.normal << ") = " << f.d << " (" << f2.normal << ") = " << f2.d << endl; // printFacePoints(cerr,f); //cerr << "Initial "; //for(j=0;j::const_iterator pi; int k; for(pi=points.begin(),k=0;pi!=points.end();++pi,++k) { Point q = p - *pi; if( lensq(q) < Point::limit) break; } if(pi!=points.end()) { indicies2[i] = k; #ifdef PRINT_INT cerr << "existing point " << *pi << ' ' << f.dist(points[indicies2[i]]) << ' ' << f2.dist(points[indicies2[i]]) << ' ' << indicies2[i] << endl; #endif } else { indicies2[i] = points.size(); points.push_back(p); #ifdef PRINT_INT cerr << "new point " << p << ' ' << f.dist(points[indicies2[i]]) << ' ' << f2.dist(points[indicies2[i]]) << ' ' << indicies2[i] << endl; #endif } signs2[i] = 0; ++i; } } //cerr << "Before cycle "; //for(j=0;j va; for(j=0;j plusind,minusind; for(j=0;j 2) { newfaces.push_back(MyFace(plusind,f)); //cerr << "creating new plus face: " << plusind << endl; } if(minusind.size() > 2) { newfaces.push_back(MyFace(minusind,f)); //cerr << "creating new minus face: " << minusind << endl; } } void intersectAllFaces() { int ii,jj; list::iterator i; vector::const_iterator j; cerr << "Number of original faces " << originalfaces.size() << endl; for(j=originalfaces.begin(),jj=0;j!=originalfaces.end();++j,++jj) { int size = faces.size(); cerr << "Intersecting with face " << jj << " current number of faces " << size << endl; for(i=faces.begin(),ii=0;iioriginalIndex) continue; // if(i->good ) { // cerr << "Intersecting " << ii << " " << jj << endl; intersectPlane(*i,*j); } } //cerr << "Size before splice " << faces.size() << endl; faces.splice(faces.end(),newfaces); //cerr << "Size after splice " << faces.size() << endl; faces.remove_if(no_good); //cerr << "Size after remove " << faces.size() << endl; } cerr << "Final Number of faces " << faces.size() << endl; } /********************************* hiding algorithms **************************/ /** * hideInteriorFaces * hides those faces which do not have 'num' verticies on the sphere * very rudementary routine */ void hideInteriorFaces(const int num) { list::iterator i; for(i=faces.begin();i!=faces.end();++i) { MyFace &f = *i; int j,count=0; // primary loop variable int size = f.indices.size(); for(j=0;j < size;++j) { Point &p = points[f.indices[j]]; if( lensq(p) > 1 - Point::limit ) ++count; } if(count::iterator i; for(i=faces.begin();i!=faces.end();++i) { MyFace &f = *i; const MyFace &of = originalfaces[f.originalIndex]; int j,count=0; // primary loop variable int size = f.indices.size(); for(j=0;j < size;++j) { const Point &p = points[f.indices[j]]; int osize = of.indices.size(); for(int k=0; k < osize; ++k) { int nextk = k +1; if(nextk == osize) nextk = 0; const Point &a = points[of.indices[k]]; const Point &b = points[of.indices[nextk]]; if( parallel(b-a,p-a) ) ++count; } } if(count<2) f.good = false; } } /** * This version checks that at one point lies at a vertex * and one lies on one of the original edges * if num is 5 or 6 then break on first face found */ void hideInteriorFaces3(const int num) { list::iterator i; for(i=faces.begin();i!=faces.end();++i) { MyFace &f = *i; const MyFace &of = originalfaces[f.originalIndex]; int j,count1=0,count2=0; // primary loop variable int size = f.indices.size(); for(j=0;j < size;++j) // for each point { int pc1=0,pc2=0; const Point &p = points[f.indices[j]]; int osize = of.indices.size(); for(int k=0; k < osize; ++k) { int nextk = k +1; if(nextk == osize) nextk = 0; const Point &a = points[of.indices[k]]; const Point &b = points[of.indices[nextk]]; if( lensq(p-a) < Point::limit && lensq(p) > 1 - Point::limit ) ++pc1; if( parallel(b-a,p-a) ) { ++pc2; //Point ba = b-a; Point pa = p-a; ba.unit(); pa.unit(); Point n = ba^pa; //cerr << "Parallel " << a << " b " << b << " p " << p < angles(e.faces.size()); vector::const_iterator i; Point firstpoint; const Point &a = points[ek.a]; const Point &b = points[ek.b]; const Point &n = f.normal; Point v = b-a; // vector along edge v.unit(); Point u = n^v; // vector in face pirpendicular to edge u.unit(); for(i=f.indices.begin();i!=f.indices.end();++i) { #ifdef PRINT_HIDE //cerr << "Index " << *i << ' ' << points[*i] << endl; #endif if(*i != ek.a && *i != ek.b) { firstpoint = points[*i]; break; } } if(i==f.indices.end()) { cerr << "Whoopse: apparently only two verticies\n"; cerr << f.indices << endl; exit(1); } Point v2 = firstpoint-a; if(dot(u,v2) < 0) u.flip(); // make sure u points in right direction //cerr << "v " << v << "\nn " << n << "\nu " << u << "\nv2 " << v2 << endl; //Point goodnorm = (points[0]-points[20])^(points[26]-points[20]); //goodnorm.unit(); //cerr << "good norm " << goodnorm << endl; /* now have coorinate frame n,u find the face with the smalest angle */ int ll,min_l,original_index; float min_angle = 4*M_PI; Point thispoint; #ifdef PRINT_HIDE cerr << "faces on edges " << &e << ' ' << e.faces.size() << endl; #endif vector::const_iterator l; for(l=e.faces.begin(),ll=0;l!=e.faces.end();++l,++ll) { MyFace *fp = *l; if(fp == &f) { angles[ll] = 4*M_PI; original_index = ll; continue; } #ifdef PRINT_HIDE cerr << "Adjacent face no " << ll << ' ' << fp << endl; cerr << fp->indices << endl; #endif for(i=fp->indices.begin();i!=fp->indices.end();++i) { //cerr << "Index " << *i << ' ' << points[*i] << endl; if(*i != ek.a && *i != ek.b) { thispoint = points[*i]; break; } } if(i==fp->indices.end()) { cerr << "Whoopse2: apparently only two verticies\n"; cerr << fp->indices << endl; exit(1); } Point v3 = thispoint-a; angles[ll] = atan2(dot(v3,n),dot(v3,u)); if(angles[ll] < 0.0 + Point::limit ) angles[ll] += 2*M_PI; //cerr << "v3 " << v3 << " dot " << dot(v3,n) << ' ' << dot(v3,u) << " Angle " << angles[ll] << endl; if(angles[ll] < min_angle) { min_angle = angles[ll]; min_l = ll; } } MyFace *fp = e.faces[min_l]; if(fp->good) return false; fp->good = true; NFace &nf = *fp; #ifdef PRINT_HIDE cerr << "Added face " << nf << endl; #endif // maintain outward pointing normals if(num == 5 || num == 6 || num == 7 || num == 8) { if(min_angle > M_PI_2 - Point::limit && min_angle < M_PI_2 + Point::limit ) { if(dot(u,fp->normal) < 0 ) fp->normal.flip(); } else if(min_angle > M_PI + M_PI_2 - Point::limit && min_angle < M_PI + M_PI_2 + Point::limit ) { if(dot(u,fp->normal) > 0 ) fp->normal.flip(); } else if(min_angle < M_PI_2 || min_angle > M_PI + M_PI_2 ) { if(dot(n,fp->normal) > 0 ) fp->normal.flip(); } else { if(dot(n,fp->normal) < 0 ) fp->normal.flip(); } } //cerr << "Normal " << fp->normal << endl; return true; } /** * Loop through list of edges * if only one of the faces is good then find the other adjacent face * which makes the smallest angle an mark that face as good * repeat until this does not occur (just do it once to check) */ void hideInteriorFaces4(const int num) { map::const_iterator k; bool more_to_do = true; while(more_to_do) { int num_faces_added = 0; more_to_do = false; for(k=edges.begin();k!=edges.end();++k) { int count=0; // how many good faces are adjacent MyFace *firstface; vector fvec = k->second.faces; vector::const_iterator l; for(l=fvec.begin();l!=fvec.end();++l) { MyFace *fp = *l; if(fp->good) { firstface = fp; ++count; } } if(count == 1) { more_to_do = true; ++num_faces_added; valarray angles(fvec.size()); vector::const_iterator i; Point firstpoint; const Point &a = points[k->first.a]; const Point &b = points[k->first.b]; const Point &n = firstface->normal; Point v = b-a; v.unit(); Point u = n^v; u.unit(); #ifdef PRINT_HIDE cerr << "Doing edge: " << k->first.a << ' ' << k->first.b << ' ' << a << ',' << b << endl; // find a point on firstface which is not on edge Face ff = *firstface; cerr << "First face: " << ff << endl; #endif for(i=firstface->indices.begin();i!=firstface->indices.end();++i) { #ifdef PRINT_HIDE //cerr << "Index " << *i << ' ' << points[*i] << endl; #endif if(*i != k->first.a && *i != k->first.b) { firstpoint = points[*i]; break; } } if(i==firstface->indices.end()) { cerr << "Whoopse: apparently only two verticies\n"; cerr << firstface->indices << endl; exit(1); } Point v2 = firstpoint-a; if(dot(u,v2) < 0) u.flip(); //cerr << "v " << v << "\nn " << n << "\nu " << u << "\nv2 " << v2 << endl; //Point goodnorm = (points[0]-points[20])^(points[26]-points[20]); //goodnorm.unit(); //cerr << "good norm " << goodnorm << endl; /* now have coorinate frame n,u */ int ll,min_l; float min_angle = 4*M_PI; Point thispoint; for(l=fvec.begin(),ll=0;l!=fvec.end();++l,++ll) { MyFace *fp = *l; #ifdef PRINT_HIDE cerr << "Adjacent face no " << ll; cerr << fp->indices << endl; #endif for(i=fp->indices.begin();i!=fp->indices.end();++i) { cerr << "Index " << *i << ' ' << points[*i] << endl; if(*i != k->first.a && *i != k->first.b) { thispoint = points[*i]; break; } } if(i==fp->indices.end()) { cerr << "Whoopse2: apparently only two verticies\n"; cerr << firstface->indices << endl; exit(1); } Point v3 = thispoint-a; angles[ll] = atan2(dot(v3,n),dot(v3,u)); if(angles[ll] < 0.0 + Point::limit ) angles[ll] += 2*M_PI; //cerr << "v3 " << v3 << " dot " << dot(v3,n) << ' ' << dot(v3,u) << " Angle " << angles[ll] << endl; if(angles[ll] < min_angle) { min_angle = angles[ll]; min_l = ll; } } MyFace *fp = fvec[min_l]; fp->good = true; NFace &nf = *fp; #ifdef PRINT_HIDE cerr << "Added face " << nf << endl; #endif // maintain outward pointing normals if(num == 5 || num == 6) { if(min_angle > M_PI_2 - Point::limit && min_angle < M_PI_2 + Point::limit ) { if(dot(u,fp->normal) < 0 ) fp->normal.flip(); } else if(min_angle > M_PI + M_PI_2 - Point::limit && min_angle < M_PI + M_PI_2 + Point::limit ) { if(dot(u,fp->normal) > 0 ) fp->normal.flip(); } else if(min_angle < M_PI_2 || min_angle > M_PI + M_PI_2 ) { if(dot(n,fp->normal) > 0 ) fp->normal.flip(); } else { if(dot(n,fp->normal) < 0 ) fp->normal.flip(); } } //cerr << "Normal " << fp->normal << endl; } // end if statement } // end loop through edges cerr << "Added " << num_faces_added << " faces adjacent to edges\n"; // break; } // end while } /** * loop through faces * adding adjacents where necessary */ void hideInteriorFaces7(const int num) { list::iterator k; bool more_to_do = true; // clear the linking faces for(k=faces.begin();k!=faces.end();++k) { MyFace &fp = *k; int i; int size = fp.indices.size(); for(i=0;i= 0) continue; int nexti = i+1; if(nexti==size) nexti = 0; EdgeKey ek(fp.indices[i],fp.indices[nexti]); Edge e = edges[ek]; if(showAdjacentFace(fp,e,ek,num)) { more_to_do = true; ++num_faces_added; } } } } cerr << "Added " << num_faces_added << " faces adjacent to edges\n"; // break; } // end while } /**************************** merging routines *****************************/ void mergeFaces(MyFace &f1,MyFace &f2,const int a,const int b) { #ifdef PRINT_MERGE cerr << "Merge faces on " << a << ' ' << b << ' '; cerr << "(" << f1.indices << ") "; cerr << " (" << f2.indices << ")\n"; #endif vector newind = merge_at(f1.indices,f2.indices,a,b); #ifdef PRINT_MERGE cerr << "before spike -> (" << newind << ")\n"; #endif clean_spikes(newind); if(newind.size() <= 2 ) return; faces.push_back(MyFace(newind,f1)); MyFace &newface = faces.back(); f1.good = false; f2.good = false; newface.good = true; #ifdef PRINT_MERGE cerr << "Mergeinds -> (" << newface.indices << ")\n"; #endif /* now need to adjust each of the edges to point to this new face */ int i,size=newind.size(); for(i=0;i::iterator j; int jj; for(j=e.faces.begin(),jj=0;j!=e.faces.end();++j,++jj) { MyFace *fp1 = &f1; MyFace *fp2 = &f2; MyFace *fp3 = &newface; if(*j == fp1 || *j == fp2) { //cerr << "Swapping face on " << newind[i] << ' ' << newind[nexti] << " (" << (*j)->indices << ") with (" << newface.indices << ")\n"; // e.faces[jj] = fp3; *j = fp3; } } } } /** * Link faces * links together adjacent faces which share a common edge */ void linkFaces() { map::iterator k; bool more_to_do = true; /* work out the good edges */ for(k=edges.begin();k!=edges.end();++k) { vector fvec = k->second.faces; vector::const_iterator l,m; int count = 0; for(l=fvec.begin();l!=fvec.end();++l) { MyFace *fp1 = *l; if(fp1->good) ++count; } if(count==2) k->second.good = true; else k->second.good = false; } while(more_to_do) { int num_faces_merged = 0; more_to_do = false; for(k=edges.begin();k!=edges.end();++k) { if( ! k->second.good ) continue; int count=0; // how many good faces are adjacent vector fvec = k->second.faces; vector::const_iterator l,m; for(l=fvec.begin();l!=fvec.end();++l) { MyFace *fp1 = *l; if(fp1->good) for(m=l+1;m!=fvec.end();++m) { MyFace *fp2 = *m; if(fp1 == fp2) { k->second.good = false; continue; } if(fp2->good && fp1->originalIndex == fp2->originalIndex) { mergeFaces(*fp1,*fp2,k->first.a,k->first.b); more_to_do = true; k->second.good = false; ++num_faces_merged; } } } } cerr << "Merged " << num_faces_merged << endl; } } void buildEdges() { list::iterator i; int ii; for(i=faces.begin(),ii=0;i!=faces.end();++i,++ii) { MyFace &f = *i; f.setFindex(ii); int j,nextj; // primary loop variable int size = f.indices.size(); for(j=0;j < size;++j) { nextj = j+1; if(nextj == size) nextj = 0; EdgeKey ek(f.indices[j],f.indices[nextj]); edges[ek].addFace(&f); } } map::const_iterator k; for(k=edges.begin();k!=edges.end();++k) { // cerr << k->first.a << ',' << k->first.b << ':'; vector fvec = k->second.faces; vector::const_iterator l; for(l=fvec.begin();l!=fvec.end();++l) { MyFace *fp = *l; // cerr << ' ' << fp->Findex; } // cerr << endl; } } void colourFaces() { list::iterator i; Point v1(1,1,1); Point vx(1,0,0); Point vy(0,1,0); Point vz(0,0,1); for(i=faces.begin();i!=faces.end();++i) { MyFace &f = *i; Point n = f.normal; if(dot(n,v1) < 0 ) n.flip(); int r = int( 128 + dot(n,vx) * 127 ); int g = int( 128 + dot(n,vy) * 127 ); int b = int( 128 + dot(n,vz) * 127 ); //cerr << "Colour " << r << " " << g << " " << b << " normal " << n << endl; f.setColour(r,g,b); } } /* * colour the first num faces one colour, etc */ void colourFaces2(int num) { list::iterator i; int ii,r,g,b; Point v1(1,1,1); Point vx(1,0,0); Point vy(0,1,0); Point vz(0,0,1); for(i=faces.begin(),ii=0;i!=faces.end();++i,++ii) { MyFace &f = *i; Point n = f.normal; if(dot(n,v1) < 0 ) n.flip(); if(ii==num) ii = 0; if(ii==0) { r = int( 128 + dot(n,vx) * 127 ); g = int( 128 + dot(n,vy) * 127 ); b = int( 128 + dot(n,vz) * 127 ); cerr << "Colour " << r << " " << g << " " << b << " normal " << n << endl; } f.setColour(r,g,b); } } /** * colour the faces by the type of polyhedra * tri = red * square = green * pent = blue * hex = yellow * oct = purple * dec = cyan * other = white */ void colourFaces3(int num) { list::iterator i; int ii,r,g,b; Point v1(1,1,1); Point vx(1,0,0); Point vy(0,1,0); Point vz(0,0,1); for(i=faces.begin(),ii=0;i!=faces.end();++i,++ii) { MyFace &f = *i; switch(f.indices.size()) { case 3: r = 255; g = 0; b = 0; break; case 4: r = 0; g = 255; b = 0; break; case 5: r = 0; g = 0; b = 255; break; case 6: r = 0; g = 255; b = 255; break; case 8: r = 255; g = 0; b = 255; break; case 10: r = 255; g = 255; b = 0; break; default: r = 255; g = 255; b = 255; break; } f.setColour(r,g,b); } } void setOriginalIndicies() { list::iterator i; int ii; for(i=faces.begin(),ii=0;i!=faces.end();++i,++ii) { i->originalIndex = ii; } } void print_help() { cout << "convert opts < stdin > stdout\n"; cout << "Where the input is that produced by kaleido's -w option\n"; cout << "and the output is in JVX format\n"; cout << "\t-i\tIntersect all the faces with each other\n"; cout << "\t-j\tJoin star faces together\n"; cout << "\t-c\tColour the faces (uses direction of normal)\n"; cout << "\t-h num\tRemove interior facets\n"; cout << "\t-h 1\tRemoves those not adjacent to a vertex\n"; cout << "\t-h 2\tRemoves those not adjacent to two verticies\n"; cout << "\t-h 3\tRemoves those where two of verticies do not line on an edge of the polyhedron\n"; cout << "\t-m file.WRL\tMatches the vertices to those in file\n"; cout << "\t\tUseful for making coumpounds\n"; cout << "\t-?\tPrints this screen\n"; cout << "\t--help\tPrints this screen\n"; exit(0); } main(int argc,char **argv) { bool intersectFlag = false,colourFlag=false,linkFlag=false; int hideFlag = -1,colourNum = 0,joinFlag = 0; for(int i=1;i 0) colourFaces2(colourNum); if(colourNum == -1) colourFaces3(colourNum); if(intersectFlag) intersectAllFaces(); switch(hideFlag) { case 1: case 2: hideInteriorFaces(hideFlag); break; case 3: hideInteriorFaces2(hideFlag); break; case 4: buildEdges(); hideInteriorFaces3(hideFlag); hideInteriorFaces4(hideFlag); break; case 5: case 6: buildEdges(); hideInteriorFaces3(hideFlag); hideInteriorFaces4(hideFlag); break; case 7: case 8: buildEdges(); hideInteriorFaces3(hideFlag); hideInteriorFaces7(hideFlag); break; } if(linkFlag) { if(hideFlag < 4 || hideFlag > 8 ) buildEdges(); linkFaces(); } print(colourFlag || (colourNum)); }