Newer
Older
// Gmsh - Copyright (C) 1997-2012 C. Geuzaine, J.-F. Remacle
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <gmsh@geuz.org>.
#include "GmshConfig.h"

Christophe Geuzaine
committed
#include "GmshMessage.h"
#include "Geo.h"
#include "GModel.h"
#include "Numeric.h"
#include "Context.h"
#include "OpenFile.h"
#include "CommandLine.h"
#include "ReadImg.h"
#include "OS.h"
#include "StringUtils.h"

Jean-François Remacle
committed
#include "GeomMeshMatcher.h"
#include "PView.h"
#include "PViewData.h"

Christophe Geuzaine
committed
#include "PViewOptions.h"

Christophe Geuzaine
committed
#include <FL/fl_ask.H>
#include "FlGui.h"
#include "menuWindow.h"
#if defined(HAVE_3M)
#include "3M.h"
#endif
static void FinishUpBoundingBox()
{
double range[3];
range[i] = CTX::instance()->max[i] - CTX::instance()->min[i];
if(range[0] < CTX::instance()->geom.tolerance &&
range[1] < CTX::instance()->geom.tolerance &&
range[2] < CTX::instance()->geom.tolerance) {
CTX::instance()->min[0] -= 1.; CTX::instance()->min[1] -= 1.;
CTX::instance()->max[0] += 1.; CTX::instance()->max[1] += 1.;
else if(range[0] < CTX::instance()->geom.tolerance &&
range[1] < CTX::instance()->geom.tolerance) {
CTX::instance()->min[0] -= range[2]; CTX::instance()->min[1] -= range[2];
CTX::instance()->max[0] += range[2]; CTX::instance()->max[1] += range[2];
else if(range[0] < CTX::instance()->geom.tolerance &&
range[2] < CTX::instance()->geom.tolerance) {
CTX::instance()->min[0] -= range[1]; CTX::instance()->max[0] += range[1];
else if(range[1] < CTX::instance()->geom.tolerance &&
range[2] < CTX::instance()->geom.tolerance) {
CTX::instance()->min[1] -= range[0]; CTX::instance()->max[1] += range[0];
else if(range[0] < CTX::instance()->geom.tolerance) {
CTX::instance()->min[0] -= l; CTX::instance()->max[0] += l;
else if(range[1] < CTX::instance()->geom.tolerance) {
CTX::instance()->min[1] -= l; CTX::instance()->max[1] += l;
}
}
void SetBoundingBox(double xmin, double xmax,
CTX::instance()->min[0] = xmin; CTX::instance()->max[0] = xmax;
CTX::instance()->min[1] = ymin; CTX::instance()->max[1] = ymax;
CTX::instance()->min[2] = zmin; CTX::instance()->max[2] = zmax;
CTX::instance()->lc = sqrt(SQU(CTX::instance()->max[0] - CTX::instance()->min[0]) +
SQU(CTX::instance()->max[1] - CTX::instance()->min[1]) +
SQU(CTX::instance()->max[2] - CTX::instance()->min[2]));
CTX::instance()->cg[i] = 0.5 * (CTX::instance()->min[i] + CTX::instance()->max[i]);

Christophe Geuzaine
committed
void SetBoundingBox(bool aroundVisible)
if(CTX::instance()->forcedBBox) return;

Christophe Geuzaine
committed
SBoundingBox3d bb = GModel::current()->bounds(aroundVisible);
if(bb.empty()) {
for(unsigned int i = 0; i < PView::list.size(); i++)
if(!PView::list[i]->getData()->getBoundingBox().empty())

Christophe Geuzaine
committed
if(!aroundVisible || PView::list[i]->getOptions()->visible)
bb += PView::list[i]->getData()->getBoundingBox();
if(bb.empty()){
bb += SPoint3(-1., -1., -1.);
bb += SPoint3(1., 1., 1.);
}
CTX::instance()->min[0] = bb.min().x(); CTX::instance()->max[0] = bb.max().x();
CTX::instance()->min[1] = bb.min().y(); CTX::instance()->max[1] = bb.max().y();
CTX::instance()->min[2] = bb.min().z(); CTX::instance()->max[2] = bb.max().z();
CTX::instance()->lc = sqrt(SQU(CTX::instance()->max[0] - CTX::instance()->min[0]) +
SQU(CTX::instance()->max[1] - CTX::instance()->min[1]) +

Christophe Geuzaine
committed
SQU(CTX::instance()->max[2] - CTX::instance()->min[2]));
CTX::instance()->cg[i] = 0.5 * (CTX::instance()->min[i] + CTX::instance()->max[i]);
// FIXME: this is necessary for now to have an approximate
// CTX::instance()->lc *while* parsing input files (it's important
// since some of the geometrical operations use a tolerance that
// depends on CTX::instance()->lc). This will be removed once the new
// database is filled directly during the parsing step
static SBoundingBox3d temp_bb;
void ResetTemporaryBoundingBox()
{
temp_bb.reset();
}
void AddToTemporaryBoundingBox(double x, double y, double z)
{
temp_bb += SPoint3(x, y, z);
CTX::instance()->lc = sqrt(SQU(temp_bb.max().x() - temp_bb.min().x()) +
SQU(temp_bb.max().y() - temp_bb.min().y()) +
if(CTX::instance()->lc == 0) CTX::instance()->lc = 1.;
// to get correct cg during interactive point creation
for(int i = 0; i < 3; i++) CTX::instance()->cg[i] = temp_bb.center()[i];

Christophe Geuzaine
committed
static std::vector<FILE*> openedFiles;
int ParseFile(const std::string &fileName, bool close, bool warnIfMissing)
Msg::Error("Gmsh parser is not compiled in this version");
return 0;
#else
// add 'b' for pure Windows programs: opening in text mode messes up
// fsetpos/fgetpos (used e.g. for user-defined functions)
FILE *fp;
if(!(fp = fopen(fileName.c_str(), "rb"))){
if(warnIfMissing)
Msg::Warning("Unable to open file '%s'", fileName.c_str());
int numViewsBefore = PView::list.size();
#endif
std::string old_yyname = gmsh_yyname;
FILE *old_yyin = gmsh_yyin;
int old_yyerrorstate = gmsh_yyerrorstate;
int old_yylineno = gmsh_yylineno;
int old_yyviewindex = gmsh_yyviewindex;
gmsh_yyname = fileName;
gmsh_yyin = fp;
gmsh_yyerrorstate = 0;
gmsh_yylineno = 1;
gmsh_yyviewindex = 0;
while(!feof(gmsh_yyin)){
gmsh_yyparse();
if(gmsh_yyerrorstate > 20){
Msg::Error("Too many errors: aborting...");
gmsh_yyflush();

Christophe Geuzaine
committed
if(close){
gmsh_yyflush();
fclose(gmsh_yyin);
}

Christophe Geuzaine
committed
else{
openedFiles.push_back(gmsh_yyin);
}
gmsh_yyname = old_yyname;
gmsh_yyin = old_yyin;
gmsh_yyerrorstate = old_yyerrorstate;
gmsh_yylineno = old_yylineno;
gmsh_yyviewindex = old_yyviewindex;
if(FlGui::available())
FlGui::instance()->updateViews(numViewsBefore != (int)PView::list.size());
#endif
return 1;
#endif
}
void ParseString(const std::string &str)
if(str.empty()) return;
std::string fileName = CTX::instance()->homeDir + CTX::instance()->tmpFileName;
FILE *fp = fopen(fileName.c_str(), "w");
if(fp){
fprintf(fp, "%s\n", str.c_str());
int MergeFile(const std::string &fileName, bool warnIfMissing)

Christophe Geuzaine
committed
if(GModel::current()->getName() == ""){
GModel::current()->setFileName(fileName);
GModel::current()->setName(SplitFileName(fileName)[1]);
}
#if defined(HAVE_FLTK)
if(FlGui::available())
FlGui::instance()->setGraphicTitle(GModel::current()->getFileName());
// added 'b' for pure Windows programs, since some of these files
// contain binary data
FILE *fp = fopen(fileName.c_str(), "rb");
Msg::Warning("Unable to open file '%s'", fileName.c_str());
return 0;
}
char header[256];
if(!fgets(header, sizeof(header), fp)) return 0;
Msg::StatusBar(2, true, "Reading '%s'...", fileName.c_str());
std::vector<std::string> split = SplitFileName(fileName);
std::string noExt = split[0] + split[1], ext = split[2];
if(ext == ".gz") {
// the real solution would be to rewrite all our I/O functions in
// terms of gzFile, but until then, this is better than nothing
std::ostringstream sstream;
sstream << "File '"<< fileName << "' is in gzip format.\n\n"
<< "Do you want to uncompress it?";
if(Msg::GetAnswer(sstream.str().c_str(), 0, "Cancel", "Uncompress")){
if(SystemCall(std::string("gunzip -c ") + fileName + " > " + noExt, true))
Msg::Error("Failed to uncompress `%s': check directory permissions",

Christophe Geuzaine
committed
GModel::current()->setFileName(noExt);

Christophe Geuzaine
committed
// force reading msh file even if wrong extension if the header
// matches
// if(!strncmp(header, "$MeshFormat", 11)) ext = "";
CTX::instance()->geom.draw = 0; // don't try to draw the model while reading
#if defined(HAVE_FLTK) && defined(HAVE_POST)
int numViewsBefore = PView::list.size();
#endif
int status = 0;
if(ext == ".stl" || ext == ".STL"){
status = GModel::current()->readSTL(fileName, CTX::instance()->geom.tolerance);
else if(ext == ".brep" || ext == ".rle" || ext == ".brp" || ext == ".BRP"){
status = GModel::current()->readOCCBREP(fileName);
else if(ext == ".iges" || ext == ".IGES" || ext == ".igs" || ext == ".IGS"){
status = GModel::current()->readOCCIGES(fileName);
else if(ext == ".step" || ext == ".STEP" || ext == ".stp" || ext == ".STP"){
status = GModel::current()->readOCCSTEP(fileName);
else if(ext == ".sat" || ext == ".SAT"){
status = GModel::current()->readACISSAT(fileName);
}
else if(ext == ".unv" || ext == ".UNV"){
status = GModel::current()->readUNV(fileName);
else if(ext == ".vtk" || ext == ".VTK"){
status = GModel::current()->readVTK(fileName, CTX::instance()->bigEndian);
else if(ext == ".wrl" || ext == ".WRL" || ext == ".vrml" || ext == ".VRML" ||
ext == ".iv" || ext == ".IV"){
status = GModel::current()->readVRML(fileName);
else if(ext == ".mesh" || ext == ".MESH"){
status = GModel::current()->readMESH(fileName);
else if(ext == ".diff" || ext == ".DIFF"){
status = GModel::current()->readDIFF(fileName);
}
else if(ext == ".med" || ext == ".MED" || ext == ".mmed" || ext == ".MMED" ||
ext == ".rmed" || ext == ".RMED"){
status = GModel::readMED(fileName);
if(status > 1) status = PView::readMED(fileName);

Christophe Geuzaine
committed
}
else if(ext == ".bdf" || ext == ".BDF" || ext == ".nas" || ext == ".NAS" ||
ext == ".dat" || ext == ".DAT"){
status = GModel::current()->readBDF(fileName);
else if(ext == ".p3d" || ext == ".P3D"){
status = GModel::current()->readP3D(fileName);
else if(ext == ".fm" || ext == ".FM") {
status = GModel::current()->readFourier(fileName);
else if(ext == ".pnm" || ext == ".PNM" || ext == ".pbm" || ext == ".PBM" ||
ext == ".pgm" || ext == ".PGM" || ext == ".ppm" || ext == ".PPM") {
status = read_pnm(fileName);
else if(ext == ".bmp" || ext == ".BMP") {
status = read_bmp(fileName);
else if(ext == ".jpg" || ext == ".JPG" || ext == ".jpeg" || ext == ".JPEG") {
status = read_jpeg(fileName);
}
#endif
#if defined(HAVE_LIBPNG)
else if(ext == ".png" || ext == ".PNG") {
status = read_png(fileName);
Emilie Marchandise
committed
status = GModel::current()->readPLY2(fileName);
}
Emilie Marchandise
committed
status = GModel::current()->readPLY(fileName);
}
else if(ext == ".geom" || ext == ".GEOM"){
status = GModel::current()->readGEOM(fileName);
}
Bastien Gorissen
committed
#if defined(HAVE_LIBCGNS)
else if(ext == ".cgns" || ext == ".CGNS"){
status = GModel::current()->readCGNS(fileName);
}
#endif
#if defined(HAVE_3M)
else if(ext == ".csv"){
status = readFile3M(fileName);
}
Bastien Gorissen
committed
#endif
CTX::instance()->geom.draw = 1;
if(!strncmp(header, "$PTS", 4) || !strncmp(header, "$NO", 3) ||
!strncmp(header, "$PARA", 5) || !strncmp(header, "$ELM", 4) ||
!strncmp(header, "$MeshFormat", 11) || !strncmp(header, "$Comments", 9)) {
if(CTX::instance()->geom.matchGeomAndMesh && !GModel::current()->empty()) {
GModel* tmp2 = GModel::current();
GModel* tmp = new GModel();
status = GeomMeshMatcher::instance()->match(tmp2, tmp);
GModel::setCurrent(tmp2);
tmp2->setVisibility(1);

Christophe Geuzaine
committed
}
else
status = GModel::current()->readMSH(fileName);
if(status > 1) status = PView::readMSH(fileName);
SetOrderN(GModel::current(), CTX::instance()->mesh.order,
CTX::instance()->mesh.secondOrderIncomplete);
else if(!strncmp(header, "$PostFormat", 11) ||
status = PView::readPOS(fileName);
CTX::instance()->geom.draw = 1;
CTX::instance()->mesh.changed = ENT_ALL;
// go directly to the first non-empty step
for(unsigned int i = numViewsBefore; i < PView::list.size(); i++)
opt_view_timestep(i, GMSH_SET | GMSH_GUI,
PView::list[i]->getData()->getFirstNonEmptyTimeStep());
FlGui::instance()->updateViews(numViewsBefore != (int)PView::list.size());
Msg::ImportPhysicalsAsOnelabRegions();
if(!status) Msg::Error("Error loading '%s'", fileName.c_str());
Msg::StatusBar(2, true, "Done reading '%s'", fileName.c_str());
// merge the associated option file if there is one
if(!StatFile(fileName + ".opt"))
MergeFile(fileName + ".opt");
int MergePostProcessingFile(const std::string &fileName, bool showLastStep,
bool hideNewViews, bool warnIfMissing)
{
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
// check if there is a mesh in the file
FILE *fp = fopen(fileName.c_str(), "rb");
if(!fp){
if(warnIfMissing) Msg::Warning("Unable to open file '%s'", fileName.c_str());
return 0;
}
char header[256];
if(!fgets(header, sizeof(header), fp)) return 0;
bool haveMesh = false;
if(!strncmp(header, "$MeshFormat", 11)){
while(!feof(fp) && fgets(header, sizeof(header), fp)){
if(!strncmp(header, "$Nodes", 6)){
haveMesh = true;
break;
}
else if(!strncmp(header, "$NodeData", 9) ||
!strncmp(header, "$ElementData", 12) ||
!strncmp(header, "$ElementNodeData", 16)){
break;
}
}
}
fclose(fp);
// store old step values
unsigned int n = PView::list.size();
std::vector<int> steps(n, 0);
if(showLastStep){
for(unsigned int i = 0; i < PView::list.size(); i++)
steps[i] = (int)opt_view_nb_timestep(i, GMSH_GET, 0);
}
// if there is a mesh, create a new model to store it (don't merge elements in
// the current mesh!)
GModel *old = GModel::current();
if(haveMesh){
GModel *m = new GModel();
GModel::setCurrent(m);
}
int ret = MergeFile(fileName, warnIfMissing);
GModel::setCurrent(old);
old->setVisibility(1);
// hide everything except the onelab X-Y graphs
if(hideNewViews){
for(unsigned int i = 0; i < PView::list.size(); i++){
if(PView::list[i]->getData()->getFileName().substr(0, 6) != "OneLab")
PView::list[i]->getOptions()->visible = 0;
}
}
else if(n != PView::list.size()){
// if we created new views, assume we only want to see those (and the
// onelab X-Y graphs)
for(unsigned int i = 0; i < n; i++){
if(PView::list[i]->getData()->getFileName().substr(0, 6) != "OneLab")
PView::list[i]->getOptions()->visible = 0;
}
}
// if we added steps, go to the last one
if(showLastStep){
steps.resize(PView::list.size(), 0);
for(unsigned int i = 0; i < PView::list.size(); i++){
int step = (int)opt_view_nb_timestep(i, GMSH_GET, 0);
if(step > steps[i])
opt_view_timestep(i, GMSH_SET|GMSH_GUI, step - 1);
}
}
return ret;
}
for(int i = PView::list.size() - 1; i >= 0; i--)
delete PView::list[i];
#endif
gmsh_yysymbols.clear();
#endif
for(int i = GModel::list.size() - 1; i >= 0; i--)
delete GModel::list[i];

Christophe Geuzaine
committed
// close the files that might have been left open by ParseFile
if(openedFiles.size()){
for(unsigned int i = 0; i < openedFiles.size(); i++)
fclose(openedFiles[i]);
openedFiles.clear();
}
new GModel();

Christophe Geuzaine
committed
GModel::current()->setFileName(CTX::instance()->defaultFileName);
GModel::current()->setName("");
#if defined(HAVE_FLTK)
if(FlGui::available()){
FlGui::instance()->setGraphicTitle(GModel::current()->getFileName());
FlGui::instance()->resetVisibility();
FlGui::instance()->updateViews();
FlGui::instance()->updateFields();
GModel::current()->setSelection(0);
}
#endif
}
void OpenProject(const std::string &fileName)
if(CTX::instance()->lock) {
Msg::Info("I'm busy! Ask me that later...");
return;
}
CTX::instance()->lock = 1;
if(GModel::current()->empty()){
// if the current model is empty, make sure it's reaaally
// cleaned-up, and reuse it (don't clear the parser variables: if
// the model is empty we probably just launched gmsh, and we don't
// want to delete variables set e.g. using the -string command
// line option)
GModel::current()->destroy();
GModel::current()->getGEOInternals()->destroy();
}
else{
// if the current model is not empty make it invisible, clear the
gmsh_yysymbols.clear();
new GModel();
GModel::current(GModel::list.size() - 1);
}
// temporary hack until we fill the current GModel on the fly during
// parsing
if(MergeFile(fileName)) {

Christophe Geuzaine
committed
if(fileName != CTX::instance()->recentFiles.front())
CTX::instance()->recentFiles.insert
(CTX::instance()->recentFiles.begin(), fileName);
if(CTX::instance()->recentFiles.size() > 5)
CTX::instance()->recentFiles.resize(5);
Bastien Gorissen
committed
#if defined(HAVE_FLTK)
if(FlGui::available())
FlGui::instance()->menu->fillRecentHistoryMenu();
#endif

Christophe Geuzaine
committed
// close the files that might have been left open by ParseFile
if(openedFiles.size()){
for(unsigned int i = 0; i < openedFiles.size(); i++)
fclose(openedFiles[i]);
openedFiles.clear();
}
CTX::instance()->lock = 0;
if(FlGui::available()){

Christophe Geuzaine
committed
file_watch_cb(0, 0);
FlGui::instance()->resetVisibility();
FlGui::instance()->updateViews();
FlGui::instance()->updateFields();
GModel::current()->setSelection(0);
GModel::current()->setCompoundVisibility();
void OpenProjectMacFinder(const char *fileName)
if(FlGui::available()){
FlGui::instance()->setOpenedThroughMacFinder(true);
OpenProject(fileName);