diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp index 46313931e14be03b38ba1712687f3a81c1383013..c55eacd260275a58e16de5969204c3dc9ebaa3f7 100644 --- a/Common/CommandLine.cpp +++ b/Common/CommandLine.cpp @@ -537,6 +537,10 @@ void Get_Options(int argc, char *argv[]) CTX.mesh.dual = 1; i++; } + else if(!strcmp(argv[i] + 1, "voronoi")) { + CTX.mesh.voronoi = 1; + i++; + } else if(!strcmp(argv[i] + 1, "noview")) { opt_view_visible(0, GMSH_SET, 0); i++; diff --git a/Common/Context.h b/Common/Context.h index 81a26ba0b78d8211da215f21f936df3772f65e50..3e4161a615c5dfdec903055efee20f8743d32a8d 100644 --- a/Common/Context.h +++ b/Common/Context.h @@ -160,7 +160,7 @@ class Context_T { double quality_inf, quality_sup, radius_inf, radius_sup; double scaling_factor, lc_factor, rand_factor, lc_integration_precision, lc_min, lc_max; int lc_from_points, lc_from_curvature, lc_extend_from_boundary; - int dual, draw_skin_only; + int dual, voronoi, draw_skin_only; int light, light_two_side, light_lines; int format, nb_smoothing, algo2d, algo3d, algo_recombine; int order, second_order_linear, second_order_incomplete; @@ -202,7 +202,7 @@ class Context_T { int jpeg_quality, jpeg_smoothing; int gif_dither, gif_sort, gif_interlace, gif_transparent; int geo_labels; - int pos_elementary, pos_element, pos_gamma, pos_eta, pos_rho; + int pos_elementary, pos_element, pos_gamma, pos_eta, pos_rho,pos_disto; int text, tex_as_equation; } print; diff --git a/Common/CreateFile.cpp b/Common/CreateFile.cpp index 043e0253a9264c45c5c9d4ecd864c6f683114281..f65c4fa0e37657b8cd9d689ec9ff98b8938a0df4 100644 --- a/Common/CreateFile.cpp +++ b/Common/CreateFile.cpp @@ -185,7 +185,7 @@ void CreateOutputFile(const char *filename, int format) case FORMAT_POS: GModel::current()->writePOS(name, CTX.print.pos_elementary, CTX.print.pos_element, CTX.print.pos_gamma, CTX.print.pos_eta, CTX.print.pos_rho, - CTX.mesh.save_all, CTX.mesh.scaling_factor); + CTX.print.pos_disto,CTX.mesh.save_all, CTX.mesh.scaling_factor); break; case FORMAT_GEO: diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h index 90401d760ffb0cab5adf70574d3f981042cb8bad..9f854006e7203b3ea4757f6365be6a818cdd7b62 100644 --- a/Common/DefaultOptions.h +++ b/Common/DefaultOptions.h @@ -1102,6 +1102,9 @@ StringXNumber MeshOptions_Number[] = { "Display faces of volume mesh?" }, { F|O, "VolumeNumbers" , opt_mesh_volumes_num , 0. , "Display volume mesh element numbers?" }, + { F|O, "Voronoi" , opt_mesh_voronoi , 0. , + "Display the voronoi diagram" }, + { F|O, "ZoneDefinition" , opt_mesh_zone_definition , 2. , "Method for defining a zone (0=single zone, 1=by partition, 2=by physical)" }, @@ -1474,6 +1477,8 @@ StringXNumber PrintOptions_Number[] = { "Save Eta quality measure in mesh statistics exported as post-processing views" }, { F|O, "PostRho" , opt_print_pos_rho , 0. , "Save Rho quality measure in mesh statistics exported as post-processing views" }, + { F|O, "PostDisto" , opt_print_pos_disto , 0. , + "Save Disto quality measure in mesh statistics exported as post-processing views" }, { F|O, "TexAsEquation" , opt_print_tex_as_equation , 0. , "Print all TeX strings as equations" }, diff --git a/Common/GmshMatrix.h b/Common/GmshMatrix.h index 49c0ec3e1c15d09f1e7838f4c055dbafc5caac60..f5c03b178b0b1c5246680b619c6439eabe163a3c 100644 --- a/Common/GmshMatrix.h +++ b/Common/GmshMatrix.h @@ -293,6 +293,11 @@ class GSL_Matrix { gsl_blas_dgemv(CblasNoTrans, 1.0, data, x.data, 1.0, b.data); } + inline void blas_dgemm(const GSL_Matrix & x, const GSL_Matrix& b, + const double c_a = 1.0, const double c_b = 1.0) + { + gsl_blas_dgemm(CblasNoTrans,CblasNoTrans, c_a, x.data, b.data, c_b, data); + } inline gsl_matrix_view touchSubmatrix(int i0, int ni, int j0, int nj) { return gsl_matrix_submatrix(data, i0, j0, ni, nj); diff --git a/Common/Options.cpp b/Common/Options.cpp index bf984c53fcec5675be3a7466e9943b7f89c4a6b2..f70550c8c6906640470b0a6c83785c19c9af0eb5 100644 --- a/Common/Options.cpp +++ b/Common/Options.cpp @@ -4546,7 +4546,7 @@ double opt_mesh_quality_type(OPT_ARGS_NUM) if(CTX.mesh.quality_type != val) CTX.mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME); CTX.mesh.quality_type = (int)val; - if(CTX.mesh.quality_type < 0 || CTX.mesh.quality_type > 2) + if(CTX.mesh.quality_type < 0 || CTX.mesh.quality_type > 3) CTX.mesh.quality_type = 0; } #if defined(HAVE_FLTK) @@ -5198,6 +5198,14 @@ double opt_mesh_dual(OPT_ARGS_NUM) return CTX.mesh.dual; } +double opt_mesh_voronoi(OPT_ARGS_NUM) +{ + if(action & GMSH_SET) { + CTX.mesh.voronoi= (int)val; + } + return CTX.mesh.voronoi; +} + double opt_mesh_draw_skin_only(OPT_ARGS_NUM) { if(action & GMSH_SET) { @@ -7878,6 +7886,13 @@ double opt_print_pos_rho(OPT_ARGS_NUM) return CTX.print.pos_rho; } +double opt_print_pos_disto(OPT_ARGS_NUM) +{ + if(action & GMSH_SET) + CTX.print.pos_disto = (int)val; + return CTX.print.pos_disto; +} + double opt_print_gif_dither(OPT_ARGS_NUM) { if(action & GMSH_SET) diff --git a/Common/Options.h b/Common/Options.h index 8116a499641c51d0b56df04cc0a9c53a6f1810c7..d46301269a01616dfe2702230bf402b02d319643 100644 --- a/Common/Options.h +++ b/Common/Options.h @@ -486,6 +486,7 @@ double opt_mesh_second_order_experimental(OPT_ARGS_NUM); double opt_mesh_second_order_linear(OPT_ARGS_NUM); double opt_mesh_second_order_incomplete(OPT_ARGS_NUM); double opt_mesh_dual(OPT_ARGS_NUM); +double opt_mesh_voronoi(OPT_ARGS_NUM); double opt_mesh_draw_skin_only(OPT_ARGS_NUM); double opt_mesh_save_all(OPT_ARGS_NUM); double opt_mesh_save_groups_of_nodes(OPT_ARGS_NUM); @@ -675,6 +676,7 @@ double opt_print_pos_element(OPT_ARGS_NUM); double opt_print_pos_gamma(OPT_ARGS_NUM); double opt_print_pos_eta(OPT_ARGS_NUM); double opt_print_pos_rho(OPT_ARGS_NUM); +double opt_print_pos_disto(OPT_ARGS_NUM); double opt_print_gif_dither(OPT_ARGS_NUM); double opt_print_gif_sort(OPT_ARGS_NUM); double opt_print_gif_interlace(OPT_ARGS_NUM); diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp index 48bb2c9b03a91c1bad89cc02f591dbaea2a1553d..e44a72d74298bd31bda100bdc5fea88eb706ee1c 100644 --- a/Fltk/Callbacks.cpp +++ b/Fltk/Callbacks.cpp @@ -1844,8 +1844,10 @@ void statistics_histogram_cb(CALLBACK_ARGS) type = 0; else if(!strcmp(name, "Eta")) type = 1; - else + else if(!strcmp(name, "Rho")) type = 2; + else + type = 3; std::vector<double> x, y; for(int i = 0; i < 100; i++) y.push_back(WID->quality[type][i]); new PView(name, "# Elements", x, y); @@ -3681,6 +3683,7 @@ void mesh_inspect_cb(CALLBACK_ARGS) Msg::Direct(" Rho: %g", elements[0]->rhoShapeMeasure()); Msg::Direct(" Gamma: %g", elements[0]->gammaShapeMeasure()); Msg::Direct(" Eta: %g", elements[0]->etaShapeMeasure()); + Msg::Direct(" Disto: %g", elements[0]->distoShapeMeasure()); CTX.mesh.changed = ENT_ALL; Draw(); WID->create_message_window(); diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp index 86083c9a7be7f02db4a91ce3ae727db875e6abc8..6caa0418e3cfb07b572833c7e1a491d48b02d7e8 100644 --- a/Fltk/GUI.cpp +++ b/Fltk/GUI.cpp @@ -2617,6 +2617,7 @@ void GUI::create_option_window() {"Gamma", 0, 0, 0}, {"Eta", 0, 0, 0}, {"Rho", 0, 0, 0}, + {"Disto", 0, 0, 0}, {0} }; mesh_choice[6] = new Fl_Choice(L + 2 * WB + IW / 2, 2 * WB + 8 * BH, IW/2, BH, "Quality range"); @@ -4008,7 +4009,7 @@ void GUI::create_statistics_window() } int width = 26 * fontsize; - int height = 5 * WB + 17 * BH; + int height = 5 * WB + 18 * BH; stat_window = new Dialog_Window(width, height, CTX.non_modal_windows, "Statistics"); stat_window->box(GMSH_WINDOW_BOX); @@ -4045,6 +4046,8 @@ void GUI::create_statistics_window() stat_value[num]->tooltip("~ volume^(2/3) / sum_edge_length^2"); num++; stat_value[num] = new Fl_Output(2 * WB, 2 * WB + 15 * BH, IW, BH, "Rho"); stat_value[num]->tooltip("~ min_edge_length / max_edge_length"); num++; + stat_value[num] = new Fl_Output(2 * WB, 2 * WB + 16 * BH, IW, BH, "Disto"); + stat_value[num]->tooltip("~ min (J0/J, J/J0)"); num++; stat_butt[0] = new Fl_Button(width - BB - 5 * WB, 2 * WB + 13 * BH, BB, BH, "Graph"); stat_butt[0]->callback(statistics_histogram_cb, (void *)"Gamma"); @@ -4052,6 +4055,8 @@ void GUI::create_statistics_window() stat_butt[1]->callback(statistics_histogram_cb, (void *)"Eta"); stat_butt[2] = new Fl_Button(width - BB - 5 * WB, 2 * WB + 15 * BH, BB, BH, "Graph"); stat_butt[2]->callback(statistics_histogram_cb, (void *)"Rho"); + stat_butt[3] = new Fl_Button(width - BB - 5 * WB, 2 * WB + 16 * BH, BB, BH, "Graph"); + stat_butt[3]->callback(statistics_histogram_cb, (void *)"Disto"); g[1]->end(); } @@ -4124,7 +4129,10 @@ void GUI::set_statistics(bool compute_quality) sprintf(label[num], "%g", s[15]); stat_value[num]->value(label[num]); num++; if(!compute_quality){ - for(int i = 0; i < 3; i++) stat_butt[i]->deactivate(); + for(int i = 0; i < 4; i++) stat_butt[i]->deactivate(); + sprintf(label[num], "Press Update"); + stat_value[num]->deactivate(); + stat_value[num]->value(label[num]); num++; sprintf(label[num], "Press Update"); stat_value[num]->deactivate(); stat_value[num]->value(label[num]); num++; @@ -4136,7 +4144,7 @@ void GUI::set_statistics(bool compute_quality) stat_value[num]->value(label[num]); num++; } else{ - for(int i = 0; i < 3; i++) stat_butt[i]->activate(); + for(int i = 0; i < 4; i++) stat_butt[i]->activate(); sprintf(label[num], "%.4g (%.4g->%.4g)", s[17], s[18], s[19]); stat_value[num]->activate(); stat_value[num]->value(label[num]); num++; @@ -4146,6 +4154,9 @@ void GUI::set_statistics(bool compute_quality) sprintf(label[num], "%.4g (%.4g->%.4g)", s[23], s[24], s[25]); stat_value[num]->activate(); stat_value[num]->value(label[num]); num++; + sprintf(label[num], "%.4g (%.4g->%.4g)", s[46], s[47], s[48]); + stat_value[num]->activate(); + stat_value[num]->value(label[num]); num++; } // post diff --git a/Fltk/GUI.h b/Fltk/GUI.h index 48a5336919ca0ed754a9a8325773843237d5f6c7..7f44a933798b6b66a603007a277632bcf92341db 100644 --- a/Fltk/GUI.h +++ b/Fltk/GUI.h @@ -229,8 +229,8 @@ public: // statistics window Fl_Window *stat_window; Fl_Output *stat_value[50]; - Fl_Button *stat_butt[3]; - double quality[3][100]; + Fl_Button *stat_butt[4]; + double quality[4][100]; // message window Fl_Window *msg_window; diff --git a/Fltk/GUI_Extras.cpp b/Fltk/GUI_Extras.cpp index 896c0625f056b896b599dae9a45611a1d440e161..3c034ca49405503e4b2c94d5ecc0e6b8cefc3ed2 100644 --- a/Fltk/GUI_Extras.cpp +++ b/Fltk/GUI_Extras.cpp @@ -763,7 +763,7 @@ int pos_dialog(const char *name) { struct _pos_dialog{ Fl_Window *window; - Fl_Check_Button *b[6]; + Fl_Check_Button *b[7]; Fl_Button *ok, *cancel; }; static _pos_dialog *dialog = NULL; @@ -774,7 +774,7 @@ int pos_dialog(const char *name) if(!dialog){ dialog = new _pos_dialog; - int h = 3 * WB + 7 * BH, w = 2 * BB + 3 * WB, y = WB; + int h = 3 * WB + 8 * BH, w = 2 * BB + 3 * WB, y = WB; // not a "Dialog_Window" since it is modal dialog->window = new Fl_Double_Window(w, h, "POS Options"); dialog->window->box(GMSH_WINDOW_BOX); @@ -784,7 +784,8 @@ int pos_dialog(const char *name) dialog->b[3] = new Fl_Check_Button(WB, y, 2 * BB + WB, BH, "Print Gamma quality measure"); y += BH; dialog->b[4] = new Fl_Check_Button(WB, y, 2 * BB + WB, BH, "Print Eta quality measure"); y += BH; dialog->b[5] = new Fl_Check_Button(WB, y, 2 * BB + WB, BH, "Print Rho quality measure"); y += BH; - for(int i = 0; i < 5; i++) + dialog->b[6] = new Fl_Check_Button(WB, y, 2 * BB + WB, BH, "Print Disto quality measure"); y += BH; + for(int i = 0; i < 6; i++) dialog->b[i]->type(FL_TOGGLE_BUTTON); dialog->ok = new Fl_Return_Button(WB, y + WB, BB, BH, "OK"); dialog->cancel = new Fl_Button(2 * WB + BB, y + WB, BB, BH, "Cancel"); @@ -813,6 +814,7 @@ int pos_dialog(const char *name) opt_print_pos_gamma(0, GMSH_SET | GMSH_GUI, dialog->b[3]->value() ? 1 : 0); opt_print_pos_eta(0, GMSH_SET | GMSH_GUI, dialog->b[4]->value() ? 1 : 0); opt_print_pos_rho(0, GMSH_SET | GMSH_GUI, dialog->b[5]->value() ? 1 : 0); + opt_print_pos_disto(0, GMSH_SET | GMSH_GUI, dialog->b[6]->value() ? 1 : 0); CreateOutputFile(name, FORMAT_POS); dialog->window->hide(); return 1; diff --git a/Geo/GModel.h b/Geo/GModel.h index a0bfcff95b4141141952a8a03aa61cb1799de16c..a98a560b8a030e57e698a18c4844da6cea1713a1 100644 --- a/Geo/GModel.h +++ b/Geo/GModel.h @@ -270,7 +270,7 @@ class GModel // Mesh statistics (as Gmsh post-processing views) int writePOS(const std::string &name, bool printElementary, bool printElementNumber, bool printGamma, bool printEta, bool printRho, - bool saveAll=false, double scalingFactor=1.0); + bool printDisto,bool saveAll=false, double scalingFactor=1.0); // Stereo lithography format int readSTL(const std::string &name, double tolerance=1.e-3); diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp index 6483527b4a41d5d9a4448fec1678003b20ce8bbb..7499a99a2729a850e16e0c59375ed5e76f254e60 100644 --- a/Geo/GModelIO_Mesh.cpp +++ b/Geo/GModelIO_Mesh.cpp @@ -613,7 +613,7 @@ int GModel::writeMSH(const std::string &name, double version, bool binary, int GModel::writePOS(const std::string &name, bool printElementary, bool printElementNumber, bool printGamma, bool printEta, - bool printRho, bool saveAll, double scalingFactor) + bool printRho, bool printDisto, bool saveAll, double scalingFactor) { FILE *fp = fopen(name.c_str(), "w"); if(!fp){ @@ -621,7 +621,7 @@ int GModel::writePOS(const std::string &name, bool printElementary, return 0; } - bool f[5] = {printElementary, printElementNumber, printGamma, printEta, printRho}; + bool f[6] = {printElementary, printElementNumber, printGamma, printEta, printRho,printDisto}; bool first = true; std::string names; @@ -645,6 +645,10 @@ int GModel::writePOS(const std::string &name, bool printElementary, if(first) first = false; else names += ","; names += "\"Rho\""; } + if(f[5]){ + if(first) first = false; else names += ","; + names += "\"Disto\""; + } if(names.empty()) return 0; @@ -656,7 +660,7 @@ int GModel::writePOS(const std::string &name, bool printElementary, for(eiter it = firstEdge(); it != lastEdge(); ++it) { if(saveAll || (*it)->physicals.size()){ for(unsigned int i = 0; i < (*it)->lines.size(); i++) - (*it)->lines[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], + (*it)->lines[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], f[5], scalingFactor, (*it)->tag()); } } @@ -664,10 +668,10 @@ int GModel::writePOS(const std::string &name, bool printElementary, for(fiter it = firstFace(); it != lastFace(); ++it) { if(saveAll || (*it)->physicals.size()){ for(unsigned int i = 0; i < (*it)->triangles.size(); i++) - (*it)->triangles[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], + (*it)->triangles[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], f[5], scalingFactor, (*it)->tag()); for(unsigned int i = 0; i < (*it)->quadrangles.size(); i++) - (*it)->quadrangles[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], + (*it)->quadrangles[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], f[5], scalingFactor, (*it)->tag()); } } @@ -675,16 +679,16 @@ int GModel::writePOS(const std::string &name, bool printElementary, for(riter it = firstRegion(); it != lastRegion(); ++it) { if(saveAll || (*it)->physicals.size()){ for(unsigned int i = 0; i < (*it)->tetrahedra.size(); i++) - (*it)->tetrahedra[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], + (*it)->tetrahedra[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], f[5], scalingFactor, (*it)->tag()); for(unsigned int i = 0; i < (*it)->hexahedra.size(); i++) - (*it)->hexahedra[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], + (*it)->hexahedra[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], f[5], scalingFactor, (*it)->tag()); for(unsigned int i = 0; i < (*it)->prisms.size(); i++) - (*it)->prisms[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], + (*it)->prisms[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], f[5], scalingFactor, (*it)->tag()); for(unsigned int i = 0; i < (*it)->pyramids.size(); i++) - (*it)->pyramids[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], + (*it)->pyramids[i]->writePOS(fp, f[0], f[1], f[2], f[3], f[4], f[5], scalingFactor, (*it)->tag()); } } diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index bc476d6eb4e7ad9fa04cfeb17c444789f8a1a44f..20a7f3f10e039e754dd044808495a942c6e89cb2 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -18,6 +18,8 @@ # include "Message.h" # include "Context.h" # include "qualityMeasures.h" +# include "meshGFaceDelaunayInsertion.h" +# include "meshGRegionDelaunayInsertion.h" #endif #define SQU(a) ((a)*(a)) @@ -96,6 +98,51 @@ void MElement::getIntegrationPoints(int pOrder, int *npts, IntPt **pts) const Msg::Error("No integration points defined for this type of element"); } +SPoint3 MTriangle::circumcenter() +{ +#if defined(HAVE_GMSH_EMBEDDED) + return 0.; +#else + double p1[3] = {_v[0]->x(),_v[0]->y(),_v[0]->z()}; + double p2[3] = {_v[1]->x(),_v[1]->y(),_v[1]->z()}; + double p3[3] = {_v[2]->x(),_v[2]->y(),_v[2]->z()}; + double res[3]; + circumCenterXYZ(p1,p2,p3,res); + return SPoint3(res[0],res[1],res[2]); +#endif +} + +SPoint3 MTetrahedron::circumcenter() +{ +#if defined(HAVE_GMSH_EMBEDDED) + return 0.; +#else + MTet4 t(this,0); + double res[3]; + t.circumcenter(res); + return SPoint3(res[0],res[1],res[2]); +#endif +} + + +double MTriangle::distoShapeMeasure() +{ +#if defined(HAVE_GMSH_EMBEDDED) + return 1.; +#else + return qmDistorsionOfMapping(this); +#endif +} + +double MTetrahedron::distoShapeMeasure() +{ +#if defined(HAVE_GMSH_EMBEDDED) + return 1.; +#else + return qmDistorsionOfMapping(this); +#endif +} + double MTriangle::gammaShapeMeasure() { #if defined(HAVE_GMSH_EMBEDDED) @@ -420,7 +467,7 @@ void MElement::writeMSH(FILE *fp, double version, bool binary, int num, void MElement::writePOS(FILE *fp, bool printElementary, bool printElementNumber, bool printGamma, bool printEta, bool printRho, - double scalingFactor, int elementary) + bool printDisto, double scalingFactor, int elementary) { const char *str = getStringForPOS(); if(!str) return; @@ -467,6 +514,13 @@ void MElement::writePOS(FILE *fp, bool printElementary, bool printElementNumber, fprintf(fp, "%g", rho); } } + if(printDisto){ + double disto = distoShapeMeasure(); + for(int i = 0; i < n; i++){ + if(first) first = false; else fprintf(fp, ","); + fprintf(fp, "%g", disto); + } + } fprintf(fp, "};\n"); } diff --git a/Geo/MElement.h b/Geo/MElement.h index 2012099606a3725b6b3fb24fb23ba7ddcaa60ef9..c976e651db2d9c28b2e6923c0343c65483171b7f 100644 --- a/Geo/MElement.h +++ b/Geo/MElement.h @@ -138,6 +138,7 @@ class MElement virtual double rhoShapeMeasure(); virtual double gammaShapeMeasure(){ return 0.; } virtual double etaShapeMeasure(){ return 0.; } + virtual double distoShapeMeasure() {return 1.0;} // compute the barycenter virtual SPoint3 barycenter(); @@ -193,7 +194,7 @@ class MElement int num=0, int elementary=1, int physical=1); virtual void writePOS(FILE *fp, bool printElementary, bool printElementNumber, bool printGamma, bool printEta, bool printRho, - double scalingFactor=1.0, int elementary=1); + bool printDisto,double scalingFactor=1.0, int elementary=1); virtual void writeSTL(FILE *fp, bool binary=false, double scalingFactor=1.0); virtual void writeVRML(FILE *fp); virtual void writeUNV(FILE *fp, int num=0, int elementary=1, int physical=1); @@ -459,6 +460,7 @@ class MTriangle : public MElement { ~MTriangle(){} virtual int getDim(){ return 2; } virtual double gammaShapeMeasure(); + virtual double distoShapeMeasure(); virtual int getNumVertices(){ return 3; } virtual MVertex *getVertex(int num){ return _v[num]; } virtual MVertex *getVertexMED(int num) @@ -550,6 +552,7 @@ class MTriangle : public MElement { pnt(1, 0, u, v, w, p); } virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts) const; + virtual SPoint3 circumcenter(); private: int edges_tri(const int edge, const int vert) const { @@ -1185,6 +1188,7 @@ class MTetrahedron : public MElement { virtual double getVolume(); virtual int getVolumeSign(){ return (getVolume() >= 0) ? 1 : -1; } virtual double gammaShapeMeasure(); + virtual double distoShapeMeasure(); virtual double etaShapeMeasure(); void xyz2uvw(double xyz[3], double uvw[3]); virtual void getShapeFunction(int num, double u, double v, double w, double &s) @@ -1236,6 +1240,7 @@ class MTetrahedron : public MElement { pnt(1, 0, u, v, w, p); } virtual void getIntegrationPoints(int pOrder, int *npts, IntPt **pts) const; + virtual SPoint3 circumcenter(); private: int edges_tetra(const int edge, const int vert) const { diff --git a/Graphics/Mesh.cpp b/Graphics/Mesh.cpp index 62a8268debbc8be09e66fc5ffca3e23dfb642888..e34dbf68bdcb5104d997f371069fc50a25bb0580 100644 --- a/Graphics/Mesh.cpp +++ b/Graphics/Mesh.cpp @@ -99,7 +99,9 @@ static bool isElementVisible(MElement *ele) if(!ele->getVisibility()) return false; if(CTX.mesh.quality_sup) { double q; - if(CTX.mesh.quality_type == 2) + if(CTX.mesh.quality_type == 3) + q = ele->distoShapeMeasure(); + else if(CTX.mesh.quality_type == 2) q = ele->rhoShapeMeasure(); else if(CTX.mesh.quality_type == 1) q = ele->etaShapeMeasure(); @@ -363,6 +365,59 @@ static void drawBarycentricDual(std::vector<T*> &elements) gl2psDisable(GL2PS_LINE_STIPPLE); } +template<class T> +static void drawVoronoiDual(std::vector<T*> &elements) +{ + glColor4ubv((GLubyte *) & CTX.color.fg); + glEnable(GL_LINE_STIPPLE); + glLineStipple(1, 0x0F0F); + gl2psEnable(GL2PS_LINE_STIPPLE); + glBegin(GL_LINES); + for(unsigned int i = 0; i < elements.size(); i++){ + T *ele = elements[i]; + if(!isElementVisible(ele)) continue; + SPoint3 pc = ele->circumcenter(); + if(ele->getDim() == 2){ + for(int j = 0; j < ele->getNumEdges(); j++){ + MEdge e = ele->getEdge(j); + SVector3 p2p1 ( e.getVertex(1)->x() - e.getVertex(0)->x(), + e.getVertex(1)->y() - e.getVertex(0)->y(), + e.getVertex(1)->z() - e.getVertex(0)->z()); + SVector3 pcp1 ( pc.x() - e.getVertex(0)->x(), + pc.y() - e.getVertex(0)->y(), + pc.z() - e.getVertex(0)->z()); + + double alpha = dot(pcp1,p2p1) / dot(p2p1,p2p1); + + SPoint3 p ((1.-alpha)*e.getVertex(0)->x() + alpha*e.getVertex(1)->x(), + (1.-alpha)*e.getVertex(0)->y() + alpha*e.getVertex(1)->y(), + (1.-alpha)*e.getVertex(0)->z() + alpha*e.getVertex(1)->z()); + glVertex3d(pc.x(), pc.y(), pc.z()); + glVertex3d(p.x(), p.y(), p.z()); + } + } + else if(ele->getDim() == 3){ + for(int j = 0; j < ele->getNumFaces(); j++){ + MFace f = ele->getFace(j); + SPoint3 p = f.barycenter(); + glVertex3d(pc.x(), pc.y(), pc.z()); + glVertex3d(p.x(), p.y(), p.z()); + for(int k = 0; k < f.getNumVertices(); k++){ + MEdge e(f.getVertex(k), (k == f.getNumVertices() - 1) ? + f.getVertex(0) : f.getVertex(k + 1)); + SPoint3 pe = e.barycenter(); + glVertex3d(p.x(), p.y(), p.z()); + glVertex3d(pe.x(), pe.y(), pe.z()); + } + } + } + } + glEnd(); + glDisable(GL_LINE_STIPPLE); + gl2psDisable(GL2PS_LINE_STIPPLE); +} + + // Routine to fill the smooth normal container template<class T> @@ -696,6 +751,10 @@ class drawMeshGFace { if(CTX.mesh.triangles) drawBarycentricDual(f->triangles); if(CTX.mesh.quadrangles) drawBarycentricDual(f->quadrangles); } + else if(CTX.mesh.voronoi) { + if(CTX.mesh.triangles) drawVoronoiDual(f->triangles); + } + if(CTX.render_mode == GMSH_SELECT) { glPopName(); diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp index 7384b21347a2c4e23f9319a14f517f3c2d1532f7..71d3e7a76d24c4893c55f593fc1edc65b894a263 100644 --- a/Mesh/Generator.cpp +++ b/Mesh/Generator.cpp @@ -30,7 +30,8 @@ static void GetQualityMeasure(std::vector<T*> &ele, double &gamma, double &gammaMin, double &gammaMax, double &eta, double &etaMin, double &etaMax, double &rho, double &rhoMin, double &rhoMax, - double quality[3][100]) + double &disto, double &distoMin, double &distoMax, + double quality[4][100]) { for(unsigned int i = 0; i < ele.size(); i++){ double g = ele[i]->gammaShapeMeasure(); @@ -45,15 +46,20 @@ static void GetQualityMeasure(std::vector<T*> &ele, rho += r; rhoMin = std::min(rhoMin, r); rhoMax = std::max(rhoMax, r); + double d = ele[i]->distoShapeMeasure(); + disto += d; + distoMin = std::min(distoMin, d); + distoMax = std::max(distoMax, d); for(int j = 0; j < 100; j++){ if(g > j / 100. && g <= (j + 1) / 100.) quality[0][j]++; if(e > j / 100. && e <= (j + 1) / 100.) quality[1][j]++; if(r > j / 100. && r <= (j + 1) / 100.) quality[2][j]++; + if(d > j / 100. && d <= (j + 1) / 100.) quality[3][j]++; } } } -void GetStatistics(double stat[50], double quality[3][100]) +void GetStatistics(double stat[50], double quality[4][100]) { for(int i = 0; i < 50; i++) stat[i] = 0.; @@ -99,15 +105,32 @@ void GetStatistics(double stat[50], double quality[3][100]) double gamma=0., gammaMin=1., gammaMax=0.; double eta=0., etaMin=1., etaMax=0.; double rho=0., rhoMin=1., rhoMax=0.; - for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){ - GetQualityMeasure((*it)->tetrahedra, gamma, gammaMin, gammaMax, - eta, etaMin, etaMax, rho, rhoMin, rhoMax, quality); - GetQualityMeasure((*it)->hexahedra, gamma, gammaMin, gammaMax, - eta, etaMin, etaMax, rho, rhoMin, rhoMax, quality); - GetQualityMeasure((*it)->prisms, gamma, gammaMin, gammaMax, - eta, etaMin, etaMax, rho, rhoMin, rhoMax, quality); - GetQualityMeasure((*it)->pyramids, gamma, gammaMin, gammaMax, - eta, etaMin, etaMax, rho, rhoMin, rhoMax, quality); + double disto=0., distoMin=1., distoMax=0.; + if (m->firstRegion() == m->lastRegion()){ + for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){ + GetQualityMeasure((*it)->quadrangles, gamma, gammaMin, gammaMax, + eta, etaMin, etaMax, rho, rhoMin, rhoMax, + disto, distoMin,distoMax,quality); + GetQualityMeasure((*it)->triangles, gamma, gammaMin, gammaMax, + eta, etaMin, etaMax, rho, rhoMin, rhoMax, + disto, distoMin,distoMax,quality); + } + } + else{ + for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){ + GetQualityMeasure((*it)->tetrahedra, gamma, gammaMin, gammaMax, + eta, etaMin, etaMax, rho, rhoMin, rhoMax, + disto, distoMin,distoMax,quality); + GetQualityMeasure((*it)->hexahedra, gamma, gammaMin, gammaMax, + eta, etaMin, etaMax, rho, rhoMin, rhoMax, + disto, distoMin,distoMax,quality); + GetQualityMeasure((*it)->prisms, gamma, gammaMin, gammaMax, + eta, etaMin, etaMax, rho, rhoMin, rhoMax, + disto, distoMin,distoMax,quality); + GetQualityMeasure((*it)->pyramids, gamma, gammaMin, gammaMax, + eta, etaMin, etaMax, rho, rhoMin, rhoMax, + disto, distoMin,distoMax,quality); + } } double N = stat[9] + stat[10] + stat[11] + stat[12]; stat[17] = N ? gamma / N : 0.; @@ -119,6 +142,9 @@ void GetStatistics(double stat[50], double quality[3][100]) stat[23] = N ? rho / N : 0; stat[24] = rhoMin; stat[25] = rhoMax; + stat[46] = N ? disto / N : 0; + stat[47] = distoMin; + stat[48] = distoMax; } #if !defined(HAVE_NO_POST) diff --git a/Mesh/Generator.h b/Mesh/Generator.h index 8c6959fec3934b0daa13b84601dc1417e01fb940..bef74f51ad754824e39c1a7331a262ed2c754eb8 100644 --- a/Mesh/Generator.h +++ b/Mesh/Generator.h @@ -8,7 +8,7 @@ class GModel; -void GetStatistics(double stat[50], double quality[3][100]=0); +void GetStatistics(double stat[50], double quality[4][100]=0); void AdaptMesh(GModel *m); void GenerateMesh(GModel *m, int dimension); void OptimizeMesh(GModel *m); diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp index abc6b5b3ea27d36e71a56c6dfabfee0bd78c43f1..985c21489a52f60a080439b595b5667499b507cf 100644 --- a/Mesh/meshGFace.cpp +++ b/Mesh/meshGFace.cpp @@ -709,7 +709,7 @@ static bool gmsh2DMeshGenerator(GFace *gf, int RECUR_ITER, bool debug = true) // vertices if(AlgoDelaunay2D(gf)){ gmshBowyerWatson(gf); - laplaceSmoothing(gf); + for (int i=0;i<CTX.mesh.nb_smoothing;i++)laplaceSmoothing(gf); } else if (debug){ char name[256]; diff --git a/Mesh/qualityMeasures.cpp b/Mesh/qualityMeasures.cpp index 1193db51e6248fef4c0de96600ec6b9f4989f0ce..f3b45dfc8e8845d24a271b747ee24e4985ebdc20 100644 --- a/Mesh/qualityMeasures.cpp +++ b/Mesh/qualityMeasures.cpp @@ -171,3 +171,56 @@ double qmTet(const double &x1, const double &y1, const double &z1, return 0.; } } + + +static double mesh_functional_distorsion(MTriangle *t, double u, double v) +{ + // compute uncurved element jacobian d_u x and d_v x + double mat[2][3]; + t->jac(1, 0, 0, 0, 0, mat); + double v1[3] = {mat[0][0], mat[0][1], mat[0][2]}; + double v2[3] = {mat[1][0], mat[1][1], mat[1][2]}; + double normal1[3]; + prodve(v1, v2, normal1); + double nn = sqrt(normal1[0]*normal1[0] + + normal1[1]*normal1[1] + + normal1[2]*normal1[2]); + + // compute uncurved element jacobian d_u x and d_v x + t->jac(u, v, 0, mat); + double v1b[3] = {mat[0][0], mat[0][1], mat[0][2]}; + double v2b[3] = {mat[1][0], mat[1][1], mat[1][2]}; + double normal[3]; + prodve(v1b, v2b, normal); + + double sign; + prosca(normal1, normal, &sign); + double det = norm3(normal) * (sign > 0 ? 1. : -1.) / nn; + + // compute distorsion + double dist = std::min(1. / det, det); + return dist; +} + + +double qmDistorsionOfMapping (MTriangle *e) +{ + if (e->getPolynomialOrder() == 1)return 1.0; + IntPt *pts; + int npts; + e->getIntegrationPoints(e->getPolynomialOrder(),&npts, &pts); + double dmin; + for (int i=0;i<npts;i++){ + const double u = pts[i].pt[0]; + const double v = pts[i].pt[1]; + const double w = pts[i].pt[2]; + const double di = mesh_functional_distorsion (e,u,v); + dmin = (i==0)? di : std::min(dmin,di); + } + return dmin; +} + +double qmDistorsionOfMapping (MTetrahedron *e) +{ + return 1.0; +} diff --git a/Mesh/qualityMeasures.h b/Mesh/qualityMeasures.h index 06ba20f05cba540cf20464e184eaf91f53b57491..198c4188c6f43a38ba3d24205620a51a1a059ded 100644 --- a/Mesh/qualityMeasures.h +++ b/Mesh/qualityMeasures.h @@ -14,6 +14,10 @@ class MTetrahedron; enum gmshQualityMeasure4Triangle {QMTRI_RHO, QMTRI_COND}; enum gmshQualityMeasure4Tet{QMTET_1, QMTET_2, QMTET_3, QMTET_ONE, QMTET_COND}; + +double qmDistorsionOfMapping (MTriangle *e); +double qmDistorsionOfMapping (MTetrahedron *e); + double qmTriangle(MTriangle *f, const gmshQualityMeasure4Triangle &cr); double qmTriangle(BDS_Face *f, const gmshQualityMeasure4Triangle &cr); double qmTriangle(const BDS_Point *p1, const BDS_Point *p2, const BDS_Point *p3,