void Output<Integer>::write_files() const { const Sublattice_Representation<Integer>& BasisChange = Result->getSublattice(); size_t i, nr; const Matrix<Integer>& Generators = Result->getGeneratorsMatrix(); const Matrix<Integer>& Support_Hyperplanes = Result->getSupportHyperplanesMatrix(); vector<libnormaliz::key_t> rees_ideal_key; if (esp && Result->isComputed(ConeProperty::SupportHyperplanes)) { //write the suport hyperplanes of the full dimensional cone Matrix<Integer> Support_Hyperplanes_Full_Cone = BasisChange.to_sublattice_dual(Support_Hyperplanes); // Support_Hyperplanes_Full_Cone.print(name,"esp"); string esp_string = name+".esp"; const char* esp_file = esp_string.c_str(); ofstream esp_out(esp_file); Support_Hyperplanes_Full_Cone.print(esp_out); esp_out << "inequalities" << endl; if (Result->isComputed(ConeProperty::Grading)) { esp_out << 1 << endl << rank << endl; esp_out << BasisChange.to_sublattice_dual(Result->getGrading()); esp_out << "grading" << endl; } if (Result->isComputed(ConeProperty::Dehomogenization)) { esp_out << 1 << endl << rank << endl; esp_out << BasisChange.to_sublattice_dual(Result->getDehomogenization()); esp_out << "dehomogenization" << endl; } esp_out.close(); } if (tgn) Generators.print(name,"tgn"); if (tri && Result->isComputed(ConeProperty::Triangulation)) { //write triangulation write_tri(); } if (out==true) { //printing .out file string name_open=name+".out"; //preparing output files const char* file=name_open.c_str(); ofstream out(file); // write "header" of the .out file size_t nr_orig_gens = 0; if (lattice_ideal_input) { nr_orig_gens = Result->getNrOriginalMonoidGenerators(); out << nr_orig_gens <<" original generators of the toric ring"<<endl; } if (Result->isComputed(ConeProperty::ModuleGenerators)) { out << Result->getNrModuleGenerators() <<" module generators" << endl; } if (Result->isComputed(ConeProperty::HilbertBasis)) { out << Result->getNrHilbertBasis() <<" Hilbert basis elements" << of_monoid << endl; } if (homogeneous && Result->isComputed(ConeProperty::Deg1Elements)) { out << Result->getNrDeg1Elements() <<" Hilbert basis elements of degree 1"<<endl; } if (Result->isComputed(ConeProperty::IsReesPrimary) && Result->isComputed(ConeProperty::HilbertBasis)) { const Matrix<Integer>& Hilbert_Basis = Result->getHilbertBasisMatrix(); nr = Hilbert_Basis.nr_of_rows(); for (i = 0; i < nr; i++) { if (Hilbert_Basis.read(i,dim-1)==1) { rees_ideal_key.push_back(i); } } out << rees_ideal_key.size() <<" generators of integral closure of the ideal"<<endl; } if (Result->isComputed(ConeProperty::VerticesOfPolyhedron)) { out << Result->getNrVerticesOfPolyhedron() <<" vertices of polyhedron" << endl; } if (Result->isComputed(ConeProperty::ExtremeRays)) { out << Result->getNrExtremeRays() <<" extreme rays" << of_cone << endl; } if(Result->isComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid)) { out << Result->getNrModuleGeneratorsOverOriginalMonoid() <<" module generators over original monoid" << endl; } if (Result->isComputed(ConeProperty::SupportHyperplanes)) { out << Result->getNrSupportHyperplanes() <<" support hyperplanes" << of_polyhedron << endl; } out<<endl; if (Result->isComputed(ConeProperty::ExcludedFaces)) { out << Result->getNrExcludedFaces() <<" excluded faces"<<endl; out << endl; } out << "embedding dimension = " << dim << endl; if (homogeneous) { out << "rank = "<< rank << is_maximal(rank,dim) << endl; //out << "index E:G = "<< BasisChange.get_index() << endl; out << "external index = "<< BasisChange.getExternalIndex() << endl; } else { // now inhomogeneous case if (Result->isComputed(ConeProperty::AffineDim)) out << "affine dimension of the polyhedron = " << Result->getAffineDim() << is_maximal(Result->getAffineDim(),dim-1) << endl; if (Result->isComputed(ConeProperty::RecessionRank)) out << "rank of recession monoid = " << Result->getRecessionRank() << endl; } if(Result->isComputed(ConeProperty::OriginalMonoidGenerators)){ out << "internal index = " << Result->getIndex() << endl; } if (homogeneous && Result->isComputed(ConeProperty::IsIntegrallyClosed)) { if (Result->isIntegrallyClosed()) { out << "original monoid is integrally closed"<<endl; } else { out << "original monoid is not integrally closed"<<endl; } } out << endl; if (Result->isComputed(ConeProperty::TriangulationSize)) { out << "size of "; if (Result->isTriangulationNested()) out << "nested "; if (Result->isTriangulationPartial()) out << "partial "; out << "triangulation = " << Result->getTriangulationSize() << endl; } if (Result->isComputed(ConeProperty::TriangulationDetSum)) { out << "resulting sum of |det|s = " << Result->getTriangulationDetSum() << endl; } if (Result->isComputed(ConeProperty::TriangulationSize)) { out << endl; } if ( Result->isComputed(ConeProperty::Dehomogenization) ) { out << "dehomogenization:" << endl << Result->getDehomogenization() << endl; } if ( Result->isComputed(ConeProperty::Grading) ) { out << "grading:" << endl << Result->getGrading(); Integer denom = Result->getGradingDenom(); if (denom != 1) { out << "with denominator = " << denom << endl; } out << endl; if (homogeneous && Result->isComputed(ConeProperty::ExtremeRays)) { out << "degrees of extreme rays:"<<endl; map<Integer,long> deg_count; vector<Integer> degs = Result->getExtremeRaysMatrix().MxV(Result->getGrading()); for (i=0; i<degs.size(); ++i) { deg_count[degs[i]/denom]++; } out << deg_count; } } else if (Result->isComputed(ConeProperty::IsDeg1ExtremeRays)) { if ( !Result->isDeg1ExtremeRays() ) { out << "No implicit grading found" << endl; } } out<<endl; if (homogeneous && Result->isComputed(ConeProperty::IsDeg1HilbertBasis) && Result->isDeg1ExtremeRays() ) { if (Result->isDeg1HilbertBasis()) { out << "Hilbert basis elements are of degree 1"; } else { out << "Hilbert basis elements are not of degree 1"; } out<<endl<<endl; } if ( Result->isComputed(ConeProperty::ModuleRank) ) { out << "module rank = "<< Result->getModuleRank() << endl; } if ( Result->isComputed(ConeProperty::Multiplicity) ) { out << "multiplicity = "<< Result->getMultiplicity() << endl; } if ( Result->isComputed(ConeProperty::ModuleRank) || Result->isComputed(ConeProperty::Multiplicity)) { out << endl; } if ( Result->isComputed(ConeProperty::HilbertSeries) ) { const HilbertSeries& HS = Result->getHilbertSeries(); out << "Hilbert series:" << endl << HS.getNum(); map<long, long> HS_Denom = HS.getDenom(); long nr_factors = 0; for (map<long, long>::iterator it = HS_Denom.begin(); it!=HS_Denom.end(); ++it) { nr_factors += it->second; } out << "denominator with " << nr_factors << " factors:" << endl; out << HS.getDenom(); out << endl; if (HS.getShift() != 0) { out << "shift = " << HS.getShift() << endl << endl; } out << "degree of Hilbert Series as rational function = " << HS.getDegreeAsRationalFunction() << endl << endl; long period = HS.getPeriod(); if (period == 1) { out << "Hilbert polynomial:" << endl; out << HS.getHilbertQuasiPolynomial()[0]; out << "with common denominator = "; out << HS.getHilbertQuasiPolynomialDenom(); out << endl<< endl; } else { // output cyclonomic representation out << "Hilbert series with cyclotomic denominator:" << endl; out << HS.getCyclotomicNum(); out << "cyclotomic denominator:" << endl; out << HS.getCyclotomicDenom(); out << endl; // Hilbert quasi-polynomial HS.computeHilbertQuasiPolynomial(); if (HS.isHilbertQuasiPolynomialComputed()) { out<<"Hilbert quasi-polynomial of period " << period << ":" << endl; Matrix<mpz_class> HQP(HS.getHilbertQuasiPolynomial()); HQP.pretty_print(out,true); out<<"with common denominator = "<<HS.getHilbertQuasiPolynomialDenom(); } out << endl << endl; } } if (Result->isComputed(ConeProperty::IsReesPrimary)) { if (Result->isReesPrimary()) { out<<"ideal is primary to the ideal generated by the indeterminates"<<endl; } else { out<<"ideal is not primary to the ideal generated by the indeterminates"<<endl; } if (Result->isComputed(ConeProperty::ReesPrimaryMultiplicity)) { out<<"multiplicity of the ideal = "<<Result->getReesPrimaryMultiplicity()<<endl; } out << endl; } if(Result->isComputed(ConeProperty::ClassGroup)) { vector<Integer> ClassGroup=Result->getClassGroup(); out << "rank of class group = " << ClassGroup[0] << endl; if(ClassGroup.size()==1) out << "class group is free" << endl << endl; else{ ClassGroup.erase(ClassGroup.begin()); out << "finite cyclic summands:" << endl; out << count_in_map<Integer,size_t>(ClassGroup); out << endl; } } out << "***********************************************************************" << endl << endl; if (lattice_ideal_input) { out << nr_orig_gens <<" original generators:"<<endl; Result->getOriginalMonoidGeneratorsMatrix().pretty_print(out); out << endl; } if (Result->isComputed(ConeProperty::ModuleGenerators)) { out << Result->getNrModuleGenerators() <<" module generators:" << endl; Result->getModuleGeneratorsMatrix().pretty_print(out); out << endl; } if ( Result->isComputed(ConeProperty::Deg1Elements) ) { const Matrix<Integer>& Hom = Result->getDeg1ElementsMatrix(); write_matrix_ht1(Hom); nr=Hom.nr_of_rows(); out<<nr<<" Hilbert basis elements of degree 1:"<<endl; Hom.pretty_print(out); out << endl; } if (Result->isComputed(ConeProperty::HilbertBasis)) { const Matrix<Integer>& Hilbert_Basis = Result->getHilbertBasisMatrix(); if(!Result->isComputed(ConeProperty::Deg1Elements)){ nr=Hilbert_Basis.nr_of_rows(); out << nr << " Hilbert basis elements" << of_monoid << ":" << endl; Hilbert_Basis.pretty_print(out); out << endl; } else { nr=Hilbert_Basis.nr_of_rows()-Result->getNrDeg1Elements(); out << nr << " further Hilbert basis elements" << of_monoid << " of higher degree:" << endl; Matrix<Integer> HighDeg(nr,dim); for(size_t i=0;i<nr;++i) HighDeg[i]=Hilbert_Basis[i+Result->getNrDeg1Elements()]; HighDeg.pretty_print(out); out << endl; } Matrix<Integer> complete_Hilbert_Basis(0,dim); if (gen || egn || typ) { // for these files we append the module generators if there are any if (Result->isComputed(ConeProperty::ModuleGenerators)) { complete_Hilbert_Basis.append(Hilbert_Basis); complete_Hilbert_Basis.append(Result->getModuleGeneratorsMatrix()); write_matrix_gen(complete_Hilbert_Basis); } else { write_matrix_gen(Hilbert_Basis); } } if (egn || typ) { Matrix<Integer> Hilbert_Basis_Full_Cone = BasisChange.to_sublattice(Hilbert_Basis); if (Result->isComputed(ConeProperty::ModuleGenerators)) { Hilbert_Basis_Full_Cone.append(BasisChange.to_sublattice(Result->getModuleGeneratorsMatrix())); } if (egn) { string egn_string = name+".egn"; const char* egn_file = egn_string.c_str(); ofstream egn_out(egn_file); Hilbert_Basis_Full_Cone.print(egn_out); // egn_out<<"cone"<<endl; egn_out.close(); } if (typ && homogeneous) { write_matrix_typ(Hilbert_Basis_Full_Cone.multiplication(BasisChange.to_sublattice_dual(Support_Hyperplanes).transpose())); } } if (Result->isComputed(ConeProperty::IsReesPrimary)) { out << rees_ideal_key.size() <<" generators of integral closure of the ideal:"<<endl; Matrix<Integer> Ideal_Gens = Hilbert_Basis.submatrix(rees_ideal_key); Ideal_Gens.resize_columns(dim-1); Ideal_Gens.pretty_print(out); out << endl; } } if (Result->isComputed(ConeProperty::VerticesOfPolyhedron)) { out << Result->getNrVerticesOfPolyhedron() <<" vertices of polyhedron:" << endl; Result->getVerticesOfPolyhedronMatrix().pretty_print(out); out << endl; } if (Result->isComputed(ConeProperty::ExtremeRays)) { out << Result->getNrExtremeRays() << " extreme rays" << of_cone << ":" << endl; Result->getExtremeRaysMatrix().pretty_print(out); out << endl; if (ext) { // for the .gen file we append the vertices of polyhedron if there are any if (Result->isComputed(ConeProperty::VerticesOfPolyhedron)) { Matrix<Integer> Extreme_Rays(Result->getExtremeRaysMatrix()); Extreme_Rays.append(Result->getVerticesOfPolyhedronMatrix()); write_matrix_ext(Extreme_Rays); } else { write_matrix_ext(Result->getExtremeRaysMatrix()); } } } if(Result->isComputed(ConeProperty::ModuleGeneratorsOverOriginalMonoid)) { out << Result->getNrModuleGeneratorsOverOriginalMonoid() <<" module generators over original monoid:" << endl; Result->getModuleGeneratorsOverOriginalMonoidMatrix().pretty_print(out); out << endl; if(mod) write_matrix_mod(Result->getModuleGeneratorsOverOriginalMonoidMatrix()); } //write constrains (support hyperplanes, congruences, equations) if (Result->isComputed(ConeProperty::SupportHyperplanes)) { out << Support_Hyperplanes.nr_of_rows() <<" support hyperplanes" << of_polyhedron << ":" << endl; Support_Hyperplanes.pretty_print(out); out << endl; } if (Result->isComputed(ConeProperty::ExtremeRays)) { //equations const Matrix<Integer>& Equations = BasisChange.getEquationsMatrix(); size_t nr_of_equ = Equations.nr_of_rows(); if (nr_of_equ > 0) { out << nr_of_equ <<" equations:" <<endl; Equations.pretty_print(out); out << endl; } //congruences const Matrix<Integer>& Congruences = BasisChange.getCongruencesMatrix(); size_t nr_of_cong = Congruences.nr_of_rows(); if (nr_of_cong > 0) { out << nr_of_cong <<" congruences:" <<endl; Congruences.pretty_print(out); out << endl; } //lattice const Matrix<Integer>& LatticeBasis = BasisChange.getEmbeddingMatrix(); size_t nr_of_latt = LatticeBasis.nr_of_rows(); if (nr_of_latt < dim || BasisChange.getExternalIndex()!=1) { out << nr_of_latt <<" basis elements of lattice:" <<endl; LatticeBasis.pretty_print(out); out << endl; } if(lat) write_matrix_lat(LatticeBasis); //excluded faces if (Result->isComputed(ConeProperty::ExcludedFaces)) { const Matrix<Integer>& ExFaces = Result->getExcludedFacesMatrix(); out << ExFaces.nr_of_rows() <<" excluded faces:" <<endl; ExFaces.pretty_print(out); out << endl; } if(cst) { string cst_string = name+".cst"; const char* cst_file = cst_string.c_str(); ofstream cst_out(cst_file); Support_Hyperplanes.print(cst_out); cst_out<<"inequalities"<<endl; Equations.print(cst_out); cst_out<<"equations"<<endl; Congruences.print(cst_out); cst_out<<"congruences"<<endl; if (Result->isComputed(ConeProperty::ExcludedFaces)) { Result->getExcludedFacesMatrix().print(cst_out); cst_out<<"excluded_faces"<<endl; } if (Result->isComputed(ConeProperty::Grading)) { cst_out << 1 << endl << dim << endl; cst_out << Result->getGrading(); cst_out << "grading" << endl; } if (Result->isComputed(ConeProperty::Dehomogenization)) { cst_out << 1 << endl << dim << endl; cst_out << Result->getDehomogenization(); cst_out << "dehomogenization" << endl; } cst_out.close(); } } out.close(); } write_inv_file(); write_Stanley_dec(); }
int main(int argc, char** argv) { if(argc >= 2) { if(strcmp(argv[1], "--help") == 0) { print_usage(); exit(2); } } int c; int errflg = 0; int male = 1; float D = 9.0; // default value, can be changed as a command line argument float P = 2; // default value, can be changed as a command line argument float theta = M_PI/3; // 60 degrees, the standard, can be changed as a command line argument float screwHeight = 20; // height of entire screw (without a head) // TODO maybe add ability to add a head float outerDiameter = -1; int segments = 72; // number of segments to approximate a circle, // higher the number, higher the resolution // (and file size) of the stl file while((c = getopt(argc, argv, "fP:D:a:h:s:o:")) != -1) { switch(c) { case 'f': male = 0; break; case 'P': P = atof(optarg); break; case 'D': D = atof(optarg); break; case 'a': theta = atof(optarg)*M_PI/180; break; case 'h': screwHeight = atof(optarg); break; case 's': segments = atoi(optarg); break; case 'o': outerDiameter = atof(optarg); break; case '?': fprintf(stderr, "Unrecognized option: '-%c'\n", optopt); errflg++; break; } } if(outerDiameter <= D) { outerDiameter = D+1; } if(errflg || optind >= argc) { print_usage(); exit(2); } char *file = argv[optind]; FILE *outf; outf = fopen(file, "wb"); if(!outf) { fprintf(stderr, "Can't write to file: %s\n", file); exit(2); } char header[81] = {0}; // TODO add some settings summary to header string snprintf(header, 81, "Created with stl_threads."); fwrite(header, 80, 1, outf); // writing 0 to num_tris for now, will update it at the end. uint32_t num_tris = 0; fwrite(&num_tris, 4, 1, outf); // ISO metric screw thread standard designates screw threads // as M followed by diameter D, a multiplication sign, and then // the pitch P (e.g. M8x1.25). Other standards designate standard // pitches for a given diameter (e.g. M8 means the same as M8x1.25). // // See http://en.wikipedia.org/wiki/ISO_metric_screw_thread // // The standard assumes a theta of 60 degrees, but we allow // theta to change, for ease of manufacturing. Certain 3D printers // may not be able to print without drooping at 60 degrees. int female = !male; // equations vary from wikipedia because we're not assuming a 60 degree theta // and we're allowing cutting off different amounts than H/8 // and H/4 from the tip and troughs float tantheta_2 = tan(theta/2); float H = P/(2*tantheta_2); float Htip = H/8; float Htrough = H/4; float Hdiff = H-Htip-Htrough; float Pdiff = Hdiff*tantheta_2; float Ptip = 2*Htip*tantheta_2; float Ptrough = 2*Htrough*tantheta_2; float Dmin = D-2*Hdiff; float Dmin_2 = Dmin/2; float D_2 = D/2; float fD = outerDiameter/2; /* // my ascii representation of image at // (http://en.wikipedia.org/wiki/ISO_metric_screw_thread) // with my own added variables |<--H->| | | | | | |-------------. pt5| ------ // pt5 is the same as pt1 one cycle later | ^ |/| | ^ | | . | | Ptrough | | \| | v | | . pt4| ------ | | \ | | | ( \ | | ( . pt3 ------ | P ( |\ ^ | theta | . Ptip | | ( |/ v | | ( . pt2 ------ | | ( / ^ | v / | Pdiff |-------------. pt1 ------ | /| | | . | | |<---Dmin/2-->| | | | | | |<-----D/2------>| */ vec pt1,pt2,pt3,pt4,pt5; pt1.x = Dmin_2; pt1.y = 0; pt1.z = 0; pt1.w = 1; pt2.x = D_2; pt2.y = 0; pt2.z = Pdiff; pt2.w = 1; pt3.x = D_2; pt3.y = 0; pt3.z = Pdiff+Ptip; pt3.w = 1; pt4.x = Dmin_2; pt4.y = 0; pt4.z = 2*Pdiff+Ptip; pt4.w = 1; pt5.x = Dmin_2; // not used, instead pt1 one full cycle later is used pt5.y = 0; // to avoid floating point errors pt5.z = P; pt5.w = 1; int total_segments = (screwHeight/P-1)*segments; vec origin = {0}; vec top = {0}; top.z = screwHeight; vec up = {0}; up.z = 1; vec down = {0}; down.z = -1; float anginc = (float)360/segments; vec sliced8Int; int needsExtraTris = 0; for(int i = -segments; i < total_segments+segments; i++) { vec p1,p2,p3,p4,p5; vec p1n,p2n,p3n,p4n,p5n; vec ob1,ob1n; vec ot1,ot1n; float ango = (float)360*((i+segments)%segments)/segments; float angno = (float)360*((i+segments)%segments+1)/segments; float cosao = cos(ango*M_PI/180); float sinao = sin(ango*M_PI/180); float cosano = cos(angno*M_PI/180); float sinano = sin(angno*M_PI/180); ob1.x = fD*cosao; ob1.y = fD*sinao; ob1.z = 0; ob1n.x = fD*cosano; ob1n.y = fD*sinano; ob1n.z = 0; ot1.x = fD*cosao; ot1.y = fD*sinao; ot1.z = screwHeight; ot1n.x = fD*cosano; ot1n.y = fD*sinano; ot1n.z = screwHeight; float ang = (float)360*i/segments; float angn = (float)360*(i+1)/segments; float angc = (float)360*(i+segments)/segments; float angnc = (float)360*(i+1+segments)/segments; float cosa = cos(ang*M_PI/180); float sina = sin(ang*M_PI/180); float cosan = cos(angn*M_PI/180); float sinan = sin(angn*M_PI/180); float cosanc = cos(angnc*M_PI/180); float sinanc = sin(angnc*M_PI/180); float cosac = cos(angc*M_PI/180); float sinac = sin(angc*M_PI/180); float z = P*ang/360; float zn = P*angn/360; float zc = P*angc/360; float znc = P*angnc/360; mat t; mat tn; mat tc; mat tnc; t.xx = cosa; t.xy = sina; t.xz = 0; t.xw = 0; t.yx = -sina; t.yy = cosa; t.yz = 0; t.yw = 0; t.zx = 0; t.zy = 0; t.zz = 1; t.zw = 0; t.tx = 0; t.ty = 0; t.tz = z; t.tw = 1; tn.xx = cosan; tn.xy = sinan; tn.xz = 0; tn.xw = 0; tn.yx = -sinan; tn.yy = cosan; tn.yz = 0; tn.yw = 0; tn.zx = 0; tn.zy = 0; tn.zz = 1; tn.zw = 0; tn.tx = 0; tn.ty = 0; tn.tz = zn; tn.tw = 1; tnc.xx = cosanc; tnc.xy = sinanc; tnc.xz = 0; tnc.xw = 0; tnc.yx = -sinanc; tnc.yy = cosanc; tnc.yz = 0; tnc.yw = 0; tnc.zx = 0; tnc.zy = 0; tnc.zz = 1; tnc.zw = 0; tnc.tx = 0; tnc.ty = 0; tnc.tz = znc; tnc.tw = 1; tc.xx = cosac; tc.xy = sinac; tc.xz = 0; tc.xw = 0; tc.yx = -sinac; tc.yy = cosac; tc.yz = 0; tc.yw = 0; tc.zx = 0; tc.zy = 0; tc.zz = 1; tc.zw = 0; tc.tx = 0; tc.ty = 0; tc.tz = zc; tc.tw = 1; vec_mat_mult(&pt1, &t, &p1); vec_mat_mult(&pt2, &t, &p2); vec_mat_mult(&pt3, &t, &p3); vec_mat_mult(&pt4, &t, &p4); vec_mat_mult(&pt1, &tc, &p5); // using pt1 with a transform of 1 // full cycle around to avoid // floating point roundoff errors vec_mat_mult(&pt1, &tn, &p1n); vec_mat_mult(&pt2, &tn, &p2n); vec_mat_mult(&pt3, &tn, &p3n); vec_mat_mult(&pt4, &tn, &p4n); vec_mat_mult(&pt1, &tnc, &p5n); // using pt1 with a transform of 1 // full cycle around to avoid // floating point roundoff errors if(i < 0) { int wrote_outer_tri = 0; vec int1,int2; int tris_written; if(write_sliced_tri(outf, &p1,&p1n,&p2n,female,&origin,&up,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int2,&origin,&int1,0); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ob1,0); num_tris += 1; } else { write_tri(outf,&int1,&ob1n,&ob1,0); write_tri(outf,&int2,&int1,&ob1,0); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p1,&p2n,&p2,female,&origin,&up,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int2,&origin,&int1,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ob1,0); num_tris += 1; } else { write_tri(outf,&int1,&ob1n,&ob1,0); write_tri(outf,&int2,&int1,&ob1,0); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p2,&p2n,&p3n,female,&origin,&up,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int2,&origin,&int1,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ob1,0); num_tris += 1; } else { write_tri(outf,&int1,&ob1n,&ob1,0); write_tri(outf,&int2,&int1,&ob1,0); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p2,&p3n,&p3,female,&origin,&up,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int2,&origin,&int1,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ob1,0); num_tris += 1; } else { write_tri(outf,&int1,&ob1n,&ob1,0); write_tri(outf,&int2,&int1,&ob1,0); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p3,&p3n,&p4n,female,&origin,&up,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int2,&origin,&int1,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ob1,0); num_tris += 1; } else { write_tri(outf,&int1,&ob1n,&ob1,0); write_tri(outf,&int2,&int1,&ob1,0); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p3,&p4n,&p4,female,&origin,&up,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int2,&origin,&int1,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ob1,0); num_tris += 1; } else { write_tri(outf,&int1,&ob1n,&ob1,0); write_tri(outf,&int2,&int1,&ob1,0); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p4,&p4n,&p5n,female,&origin,&up,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int2,&origin,&int1,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ob1,0); num_tris += 1; } else { write_tri(outf,&int1,&ob1n,&ob1,0); write_tri(outf,&int2,&int1,&ob1,0); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p4,&p5n,&p5,female,&origin,&up,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int2,&origin,&int1,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ob1,0); num_tris += 1; } else { write_tri(outf,&int1,&ob1n,&ob1,0); write_tri(outf,&int2,&int1,&ob1,0); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; } else if(i >= total_segments) { int wrote_outer_tri = 0; vec int1,int2; int tris_written; if(write_sliced_tri(outf, &p1,&p1n,&p2n,female,&top,&down,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int1,&top,&int2,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ot1,1); num_tris += 1; } else { write_tri(outf,&int1,&ot1n,&ot1,1); write_tri(outf,&int2,&int1,&ot1,1); wrote_outer_tri = 1; num_tris += 2; } } if(i == total_segments+segments-1 && needsExtraTris) { write_tri(outf, &int1,&p1n,&sliced8Int,female); num_tris += 1; if(male) { write_tri(outf, &int1,&sliced8Int,&top,female); num_tris += 1; } else { write_tri(outf, &int1,&sliced8Int,&ot1n,female); num_tris += 1; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p1,&p2n,&p2,female,&top,&down,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int1,&top,&int2,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ot1,1); num_tris += 1; } else { write_tri(outf,&int1,&ot1n,&ot1,1); write_tri(outf,&int2,&int1,&ot1,1); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p2,&p2n,&p3n,female,&top,&down,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int1,&top,&int2,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ot1,1); num_tris += 1; } else { write_tri(outf,&int1,&ot1n,&ot1,1); write_tri(outf,&int2,&int1,&ot1,1); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p2,&p3n,&p3,female,&top,&down,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int1,&top,&int2,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ot1,1); num_tris += 1; } else { write_tri(outf,&int1,&ot1n,&ot1,1); write_tri(outf,&int2,&int1,&ot1,1); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p3,&p3n,&p4n,female,&top,&down,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int1,&top,&int2,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ot1,1); num_tris += 1; } else { write_tri(outf,&int1,&ot1n,&ot1,1); write_tri(outf,&int2,&int1,&ot1,1); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p3,&p4n,&p4,female,&top,&down,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int1,&top,&int2,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ot1,1); num_tris += 1; } else { write_tri(outf,&int1,&ot1n,&ot1,1); write_tri(outf,&int2,&int1,&ot1,1); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p4,&p4n,&p5n,female,&top,&down,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int1,&top,&int2,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ot1,1); num_tris += 1; } else { write_tri(outf,&int1,&ot1n,&ot1,1); write_tri(outf,&int2,&int1,&ot1,1); wrote_outer_tri = 1; num_tris += 2; } } } num_tris += tris_written; if(write_sliced_tri(outf, &p4,&p5n,&p5,female,&top,&down,&int1,&int2,&tris_written)) { if(male) { write_tri(outf,&int1,&top,&int2,female); num_tris += 1; } else { if(wrote_outer_tri) { write_tri(outf,&int2,&int1,&ot1,1); num_tris += 1; } else { write_tri(outf,&int1,&ot1n,&ot1,1); write_tri(outf,&int2,&int1,&ot1,1); wrote_outer_tri = 1; num_tris += 2; } } if(i == total_segments && !vec_equals(&int2,&p5)) { needsExtraTris = 1; vec_copy(&int2,&sliced8Int); } } num_tris += tris_written; } else { write_quad(outf, &p1,&p1n,&p2n,&p2,female); write_quad(outf, &p2,&p2n,&p3n,&p3,female); write_quad(outf, &p3,&p3n,&p4n,&p4,female); write_quad(outf, &p4,&p4n,&p5n,&p5,female); num_tris += 8; } } if(female) { for(int i = 0; i < segments; i++) { vec ob1,ob1n; vec ot1,ot1n; float ang = (float)360*i/segments; float angn = (float)360*(i+1)/segments; float cosa = cos(ang*M_PI/180); float sina = sin(ang*M_PI/180); float cosan = cos(angn*M_PI/180); float sinan = sin(angn*M_PI/180); ob1.x = fD*cosa; ob1.y = fD*sina; ob1.z = 0; ob1n.x = fD*cosan; ob1n.y = fD*sinan; ob1n.z = 0; ot1.x = fD*cosa; ot1.y = fD*sina; ot1.z = screwHeight; ot1n.x = fD*cosan; ot1n.y = fD*sinan; ot1n.z = screwHeight; write_quad(outf,&ob1,&ob1n,&ot1n,&ot1,0); num_tris += 2; } } fseek(outf, 80, SEEK_SET); fwrite(&num_tris, 4, 1, outf); fclose(outf); return 0; }
void write_poly(FILE *f, vec *poly, int num_pts, int rev) { for(int i = 1; i < num_pts-1; i++) { write_tri(f, &poly[0], &poly[i], &poly[i+1], rev); } }
// returns true if triangle intersects plane, int1 and int2 will be set // to the intersection points // returns false if all points are above or below the plane int write_sliced_tri(FILE *f, vec *p1, vec *p2, vec *p3, int rev, vec *p, // point that lies in the slicing plane vec *n, // normal of slicing plane, keep points in the direction of normal vec *int1, // output, intersecting pt1, returned only if intersection occurs vec *int2, // output, intersecting pt2, returned only if intersection occurs int *tris) // output, number of tris written { vec trin; tri_normal(p1,p2,p3,rev,&trin); point_state_t state1; point_state_t state2; point_state_t state3; state1 = point_state(p1,p,n); state2 = point_state(p2,p,n); state3 = point_state(p3,p,n); if((state1 == ABOVE || state1 == ON) && (state2 == ABOVE || state2 == ON) && (state3 == ABOVE || state3 == ON)) { // all points are above or on plane, write tri normally write_tri(f,p1,p2,p3,rev); *tris = 1; return 0; } else if((state1 == BELOW || state1 == ON) && (state2 == BELOW || state2 == ON) && (state3 == BELOW || state3 == ON)) { // all points are below or on plane, cull entire tri *tris = 0; return 0; } else { // triangle intersects plane if(state1 == ON) { vec tmp1,tmp2; float r; vec_copy(p1, int1); vec_sub(p2,p3,&tmp1); vec_sub(p,p3,&tmp2); r = vec_dot(n,&tmp2)/vec_dot(n,&tmp1); int2->x = p3->x + r*tmp1.x; int2->y = p3->y + r*tmp1.y; int2->z = p3->z + r*tmp1.z; if(state2 == ABOVE) { write_tri(f,p1,p2,int2,rev); } else { write_tri(f,p1,int2,p3,rev); } *tris = 1; return 1; } if(state2 == ON) { vec tmp1,tmp2; float r; vec_copy(p2, int1); vec_sub(p1,p3,&tmp1); vec_sub(p,p3,&tmp2); r = vec_dot(n,&tmp2)/vec_dot(n,&tmp1); int2->x = p3->x + r*tmp1.x; int2->y = p3->y + r*tmp1.y; int2->z = p3->z + r*tmp1.z; if(state1 == ABOVE) { write_tri(f,p1,p2,int2,rev); } else { write_tri(f,p2,p3,int2,rev); } *tris = 1; return 1; } if(state3 == ON) { vec tmp1,tmp2; float r; vec_copy(p3, int2); vec_sub(p1,p2,&tmp1); vec_sub(p,p2,&tmp2); r = vec_dot(n,&tmp2)/vec_dot(n,&tmp1); int1->x = p2->x + r*tmp1.x; int1->y = p2->y + r*tmp1.y; int1->z = p2->z + r*tmp1.z; if(state1 == ABOVE) { write_tri(f,p1,int1,p3,rev); } else { write_tri(f,int1,p2,p3,rev); } *tris = 1; return 1; } if((state1 == ABOVE && state2 == ABOVE) || (state1 == BELOW && state2 == BELOW)) { vec tmp1,tmp2,tmp3; float r1,r2; vec_sub(p2,p3,&tmp1); vec_sub(p1,p3,&tmp2); vec_sub(p,p3,&tmp3); r1 = vec_dot(n,&tmp3)/vec_dot(n,&tmp1); r2 = vec_dot(n,&tmp3)/vec_dot(n,&tmp2); int1->x = p3->x + r1*tmp1.x; int1->y = p3->y + r1*tmp1.y; int1->z = p3->z + r1*tmp1.z; int2->x = p3->x + r2*tmp2.x; int2->y = p3->y + r2*tmp2.y; int2->z = p3->z + r2*tmp2.z; if(state3 == ABOVE) { write_tri(f,int1,p3,int2,rev); *tris = 1; } else { write_quad(f,p1,p2,int1,int2,rev); *tris = 2; } return 1; } if((state2 == ABOVE && state3 == ABOVE) || (state2 == BELOW && state3 == BELOW)) { vec tmp1,tmp2,tmp3; float r1,r2; vec_sub(p2,p1,&tmp1); vec_sub(p3,p1,&tmp2); vec_sub(p,p1,&tmp3); r1 = vec_dot(n,&tmp3)/vec_dot(n,&tmp1); r2 = vec_dot(n,&tmp3)/vec_dot(n,&tmp2); int1->x = p1->x + r1*tmp1.x; int1->y = p1->y + r1*tmp1.y; int1->z = p1->z + r1*tmp1.z; int2->x = p1->x + r2*tmp2.x; int2->y = p1->y + r2*tmp2.y; int2->z = p1->z + r2*tmp2.z; if(state1 == ABOVE) { write_tri(f,p1,int1,int2,rev); *tris = 1; } else { write_quad(f,int1,p2,p3,int2,rev); *tris = 2; } return 1; } if((state1 == ABOVE && state3 == ABOVE) || (state1 == BELOW && state3 == BELOW)) { vec tmp1,tmp2,tmp3; float r1,r2; vec_sub(p1,p2,&tmp1); vec_sub(p3,p2,&tmp2); vec_sub(p,p2,&tmp3); r1 = vec_dot(n,&tmp3)/vec_dot(n,&tmp1); r2 = vec_dot(n,&tmp3)/vec_dot(n,&tmp2); int1->x = p2->x + r1*tmp1.x; int1->y = p2->y + r1*tmp1.y; int1->z = p2->z + r1*tmp1.z; int2->x = p2->x + r2*tmp2.x; int2->y = p2->y + r2*tmp2.y; int2->z = p2->z + r2*tmp2.z; if(state2 == ABOVE) { write_tri(f,int1,p2,int2,rev); *tris = 1; } else { write_quad(f,p1,int1,int2,p3,rev); *tris = 2; } return 1; } } *tris = 0; return 0; }