Skip to content
Snippets Groups Projects
OpenFile.cpp 14.4 KiB
Newer Older
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to <gmsh@geuz.org>.

#include <string.h>
#include "Geo.h"
#include "GModel.h"
#include "Numeric.h"
#include "HighOrder.h"
#include "Context.h"
#include "OpenFile.h"
#include "CommandLine.h"
#include "ReadImg.h"
#include "OS.h"
#include "StringUtils.h"

#if !defined(HAVE_NO_PARSER)
#include "Parser.h"
#endif

#if !defined(HAVE_NO_POST)
#include "PView.h"
#include "PViewData.h"
#endif

#if defined(HAVE_FLTK)
#include "Draw.h"
#endif

Christophe Geuzaine's avatar
Christophe Geuzaine committed
#define SQU(a)      ((a)*(a))

static void FinishUpBoundingBox()
{
  double range[3];
  for(int i = 0; i < 3; i++) 
    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) {
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    double l = sqrt(SQU(range[1]) + SQU(range[2]));
    CTX::instance()->min[0] -= l; CTX::instance()->max[0] += l;
  else if(range[1] < CTX::instance()->geom.tolerance) {
Christophe Geuzaine's avatar
Christophe Geuzaine committed
    double l = sqrt(SQU(range[0]) + SQU(range[2]));
    CTX::instance()->min[1] -= l; CTX::instance()->max[1] += l;
  }
}

void SetBoundingBox(double xmin, double xmax,
                    double ymin, double ymax, 
                    double zmin, double zmax)
{
  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;
  FinishUpBoundingBox();
  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]));
  for(int i = 0; i < 3; i++) 
    CTX::instance()->cg[i] = 0.5 * (CTX::instance()->min[i] + CTX::instance()->max[i]);
}

void SetBoundingBox()
{
  if(CTX::instance()->forcedBBox) return;

  SBoundingBox3d bb = GModel::current()->bounds();
  
#if !defined(HAVE_NO_POST)
  if(bb.empty()) {
    for(unsigned int i = 0; i < PView::list.size(); i++)
      if(!PView::list[i]->getData()->getBoundingBox().empty())
        bb += PView::list[i]->getData()->getBoundingBox();
  }
#endif
  
  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();
  FinishUpBoundingBox();
  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]));
  for(int i = 0; i < 3; i++) 
    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);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  if(temp_bb.empty()) return;
  CTX::instance()->lc = sqrt(SQU(temp_bb.max().x() - temp_bb.min().x()) +
Christophe Geuzaine's avatar
Christophe Geuzaine committed
                SQU(temp_bb.max().y() - temp_bb.min().y()) + 
                SQU(temp_bb.max().z() - temp_bb.min().z()));
  if(CTX::instance()->lc == 0) CTX::instance()->lc = 1.;
Christophe Geuzaine's avatar
Christophe Geuzaine committed
  // to get correct cg during interctive point creation
  for(int i = 0; i < 3; i++) CTX::instance()->cg[i] = temp_bb.center()[i];
int ParseFile(std::string fileName, bool close, bool warnIfMissing)
{
#if defined(HAVE_NO_PARSER)
  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());
    return 0;
  }

#if !defined(HAVE_NO_POST)
  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...");
      break;
    }
  }

  if(close) fclose(gmsh_yyin);

  gmsh_yyname = old_yyname;
  gmsh_yyin = old_yyin;
  gmsh_yyerrorstate = old_yyerrorstate;
  gmsh_yylineno = old_yylineno;
  gmsh_yyviewindex = old_yyviewindex;

#if defined(HAVE_FLTK) && !defined(HAVE_NO_POST)
  if(GUI::available() && numViewsBefore != (int)PView::list.size())
    GUI::instance()->updateViews();
void ParseString(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());
    fclose(fp);
    ParseFile(fileName, true);
    GModel::current()->importGEOInternals();
  }
}

static void SetProjectName(std::string fileName)
  GModel::current()->setFileName(fileName);
  GModel::current()->setName(SplitFileName(fileName)[1]);
int MergeFile(std::string fileName, bool warnIfMissing)
  if(GModel::current()->getName() == "")
    SetProjectName(fileName);

#if defined(HAVE_FLTK)
  if(GUI::available())
    GUI::instance()->setGraphicTitle(GModel::current()->getFileName());
#endif
  // added 'b' for pure Windows programs, since some of these files
  // contain binary data
  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];
  fgets(header, sizeof(header), fp);
  fclose(fp);

  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 defined(HAVE_FLTK)
    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
      if(fl_choice("File '%s' is in gzip format.\n\nDo you want to uncompress it?", 
                   "Cancel", "Uncompress", NULL, fileName.c_str())){
        if(SystemCall(std::string("gunzip -c ") + fileName + " > " + noExt))
          Msg::Error("Failed to uncompress `%s': check directory permissions", 
                     fileName.c_str());
        SetProjectName(noExt);
        return MergeFile(noExt);
  CTX::instance()->geom.draw = 0; // don't try to draw the model while reading

#if !defined(HAVE_NO_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 == ".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 == ".med" || ext == ".MED" || ext == ".mmed" || ext == ".MMED" ||
	  ext == ".rmed" || ext == ".RMED"){
    status = GModel::readMED(fileName);
    if(status > 1) status = PView::readMED(fileName);
  else if(ext == ".bdf" || ext == ".BDF" || ext == ".nas" || ext == ".NAS"){
    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);
  }
#if defined(HAVE_FLTK)
  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);
  }
#if defined(HAVE_LIBJPEG)
  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);
  }
#endif
#endif
  else {
    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)) {

      // MATCHER
      if(CTX::instance()->geom.matchGeomAndMesh  && !GModel::current()->empty() ) {
        GModel* tmp_model = new GModel();
        tmp_model->readMSH(fileName);
        //tmp_model->scaleMesh(1000);
	int match_status = GeomMeshMatcher::instance()->match(GModel::current(), tmp_model);
        if (match_status)
	  fileName = "out.msh";
        delete tmp_model;
      }
      // MATCHER END

      status = GModel::current()->readMSH(fileName);
#if !defined(HAVE_NO_POST)
      if(status > 1) status = PView::readMSH(fileName);
      if(CTX::instance()->mesh.order > 1) 
        SetOrderN(GModel::current(), CTX::instance()->mesh.order,
                  CTX::instance()->mesh.secondOrderLinear, 
                  CTX::instance()->mesh.secondOrderIncomplete);
    }
#if !defined(HAVE_NO_POST)
    else if(!strncmp(header, "$PostFormat", 11) || 
            !strncmp(header, "$View", 5)) {
      status = PView::readPOS(fileName);
      status = GModel::current()->readGEO(fileName);
  CTX::instance()->geom.draw = 1;
  CTX::instance()->mesh.changed = ENT_ALL;

#if defined(HAVE_FLTK) && !defined(HAVE_NO_POST)
  if(GUI::available() && numViewsBefore != (int)PView::list.size())
    GUI::instance()->updateViews();
  if(!status) Msg::Error("Error loading '%s'", fileName.c_str());
  Msg::StatusBar(2, true, "Read '%s'", fileName.c_str());
  return status;
}

{
#if !defined(HAVE_NO_POST)
  for(int i = PView::list.size() - 1; i >= 0; i--)
    delete PView::list[i];
#endif
#if !defined(HAVE_NO_PARSER)
  gmsh_yysymbols.clear();
#endif
  for(int i = GModel::list.size() - 1; i >= 0; i--)
  SetProjectName(CTX::instance()->defaultFileName);
#if defined(HAVE_FLTK)
  if(GUI::available()){
    GUI::instance()->setGraphicTitle(GModel::current()->getFileName());
    GUI::instance()->resetVisibility();
    GUI::instance()->updateViews();
    GUI::instance()->updateFields();
    GModel::current()->setSelection(0);
  }
#endif
}

void OpenProject(std::string fileName)
  if(CTX::instance()->lock) {
    Msg::Info("I'm busy! Ask me that later...");
    return;
  }
  if(GModel::current()->empty()){
    // if the current model is empty, make sure it's reaaally
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
    // 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
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
    // parser variables and add a new model
    GModel::current()->setVisibility(0);
    new GModel();
    GModel::current(GModel::list.size() - 1);
  }

  // temporary hack until we fill the current GModel on the fly during
  // parsing
  ResetTemporaryBoundingBox();
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed

  // merge the file
Christophe Geuzaine's avatar
 
Christophe Geuzaine committed
  // merge the associated option file if there is one
  if(!StatFile(fileName + ".opt"))
    MergeFile(fileName + ".opt");


#if defined(HAVE_FLTK)
  if(GUI::available()){
    GUI::instance()->resetVisibility();
    GUI::instance()->updateViews();
    GUI::instance()->updateFields();
    GModel::current()->setSelection(0);
void OpenProjectMacFinder(const char *fileName)
Christophe Geuzaine's avatar
Christophe Geuzaine committed
#if defined(HAVE_FLTK)
  static int first = 1;
    // just copy the filename: it will be opened when the GUI is ready
    // in main()
    GModel::current()->setFileName(fileName);
    first = 0;
  }
  else{
    OpenProject(fileName);
Christophe Geuzaine's avatar
Christophe Geuzaine committed
#endif