From 8d9a85f55f132502c212024565c4df8ca7cc1dbe Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Mon, 12 Dec 2011 10:04:55 +0000
Subject: [PATCH] automagic 2D graphs with onelab

---
 Fltk/graphicWindow.cpp |  18 ++++++
 Fltk/inputRange.h      | 116 ++++++++++++++++++++++++++----------
 Fltk/onelabWindow.cpp  | 132 ++++++++++++++++++++++++++++++-----------
 Post/PView.cpp         |   8 +--
 4 files changed, 204 insertions(+), 70 deletions(-)

diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index 2ac53c8588..d1f0b9d9fc 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -110,6 +110,22 @@ static void gmsh_gear(Fl_Color c)
   fl_line_style(FL_SOLID);
 }
 
+static void gmsh_graph_x(Fl_Color c)
+{
+  fl_color(c);
+  fl_begin_line(); vv(-0.8,0.8); vv(0.8,0.8); fl_end_line();
+  fl_begin_polygon(); vv(0.8,0.8); vv(0.2,1.1); vv(0.2,0.5); fl_end_polygon();
+  fl_begin_line(); vv(-0.8,0.3); vv(-0.2,-0.2); vv(0.3,0.1); vv(0.8,-0.4); fl_end_line();
+}
+
+static void gmsh_graph_y(Fl_Color c)
+{
+  fl_color(c);
+  fl_begin_line(); vv(-0.8,-0.8); vv(-0.8,0.8); fl_end_line();
+  fl_begin_polygon(); vv(-0.8,-1.1); vv(-1.1, -0.5); vv(-0.5, -0.5); fl_end_polygon();
+  fl_begin_line(); vv(-0.8,0.3); vv(-0.2,-0.2); vv(0.3,0.1); vv(0.8,-0.4); fl_end_line();
+}
+
 #undef vv
 #undef bl
 #undef el
@@ -487,6 +503,8 @@ graphicWindow::graphicWindow(bool main, int numTiles)
     fl_add_symbol("gmsh_models", gmsh_models, 1);
     fl_add_symbol("gmsh_clscale", gmsh_clscale, 1);
     fl_add_symbol("gmsh_gear", gmsh_gear, 1);
+    fl_add_symbol("gmsh_graph_x", gmsh_graph_x, 1);
+    fl_add_symbol("gmsh_graph_y", gmsh_graph_y, 1);
     first = false;
   }
   
diff --git a/Fltk/inputRange.h b/Fltk/inputRange.h
index 383686ee81..ed5ec0b118 100644
--- a/Fltk/inputRange.h
+++ b/Fltk/inputRange.h
@@ -16,7 +16,8 @@ class inputRange : public Fl_Group {
  private:
   Fl_Value_Input *_input;
   Fl_Input *_range;
-  Fl_Toggle_Button *_range_butt, *_loop_butt;
+  Fl_Toggle_Button *_range_butt, *_loop_butt, *_graph_butt[2];
+  std::string _loop_val, _graph_val[2];
   double _min, _max, _step, _max_number;
   std::vector<double> _choices;
   void _values2string()
@@ -123,60 +124,104 @@ class inputRange : public Fl_Group {
   }
   void _set_loop_value(const std::string &val)
   {
+    _loop_val = val;
     if(val == "1"){
-      _loop_butt->label("1");
+      //_loop_butt->label("1");
       _loop_butt->selection_color(FL_GREEN);
       _loop_butt->value(1);
     }
     else if(val == "2"){
-      _loop_butt->label("2");
+      //_loop_butt->label("2");
       _loop_butt->selection_color(FL_BLUE);
       _loop_butt->value(1);
     }
     else if(val == "3"){
-      _loop_butt->label("3");
+      //_loop_butt->label("3");
       _loop_butt->selection_color(FL_RED);
       _loop_butt->value(1);
     }
     else{
-      _loop_butt->label("@-1gmsh_rotate");
+      //_loop_butt->label("@-1gmsh_rotate");
       _loop_butt->selection_color(_loop_butt->color());
       _loop_butt->value(0);
     }
+    _loop_butt->redraw();
+  }
+  void _set_graph_value(int axis, const std::string &val)
+  {
+    _graph_val[axis] = val;
+    if(val == "1"){
+      //_graph_butt[axis]->label("1");
+      _graph_butt[axis]->selection_color(FL_GREEN);
+      _graph_butt[axis]->value(1);
+    }
+    else if(val == "2"){
+      //_graph_butt[axis]->label("2");
+      _graph_butt[axis]->selection_color(FL_BLUE);
+      _graph_butt[axis]->value(1);
+    }
+    else if(val == "3"){
+      //_graph_butt[axis]->label("3");
+      _graph_butt[axis]->selection_color(FL_RED);
+      _graph_butt[axis]->value(1);
+    }
+    else{
+      //_graph_butt[axis]->label(axis == 0 ? "@-1gmsh_graph_x" : "@-1gmsh_graph_y");
+      _graph_butt[axis]->selection_color(_graph_butt[axis]->color());
+      _graph_butt[axis]->value(0);
+    }
+    _graph_butt[axis]->redraw();
   }
   static void _input_cb(Fl_Widget *w, void *data)
   {
-    ((inputRange*)data)->do_callback();
+    inputRange *b = (inputRange*)data;
+    b->do_callback();
   }
   static void _range_cb(Fl_Widget *w, void *data)
   {
-    ((inputRange*)data)->_string2values();
-    ((inputRange*)data)->do_callback();
+    inputRange *b = (inputRange*)data;
+    b->_string2values();
+    b->do_callback();
   }
   static void _range_butt_cb(Fl_Widget *w, void *data)
   {
-    ((inputRange*)data)->_show_range(); 
+    inputRange *b = (inputRange*)data;
+    b->_show_range(); 
   }
   static void _loop_butt_cb(Fl_Widget *w, void *data)
   {
-    Fl_Toggle_Button *b = (Fl_Toggle_Button*)w;
-    if(std::string(b->label()) == "1")
-      ((inputRange*)data)->_set_loop_value("2");
-    else if(std::string(b->label()) == "2")
-      ((inputRange*)data)->_set_loop_value("3");
-    else if(std::string(b->label()) == "3")
-      ((inputRange*)data)->_set_loop_value("0");
-    else
-      ((inputRange*)data)->_set_loop_value("1");
-    ((inputRange*)data)->do_callback(); 
+    inputRange *b = (inputRange*)data;
+    if(b->_loop_val == "1")      b->_set_loop_value("2");
+    else if(b->_loop_val == "2") b->_set_loop_value("3");
+    else if(b->_loop_val == "3") b->_set_loop_value("0");
+    else                         b->_set_loop_value("1");
+    b->do_callback(); 
+  }
+  static void _graph_butt_x_cb(Fl_Widget *w, void *data)
+  {
+    inputRange *b = (inputRange*)data;
+    if(b->_graph_val[0] == "1")      b->_set_graph_value(0, "2");
+    else if(b->_graph_val[0] == "2") b->_set_graph_value(0, "3");
+    else if(b->_graph_val[0] == "3") b->_set_graph_value(0, "0");
+    else                             b->_set_graph_value(0, "1");
+    b->do_callback();
+  }
+  static void _graph_butt_y_cb(Fl_Widget *w, void *data)
+  {
+    inputRange *b = (inputRange*)data;
+    if(b->_graph_val[1] == "1")      b->_set_graph_value(1, "2");
+    else if(b->_graph_val[1] == "2") b->_set_graph_value(1, "3");
+    else if(b->_graph_val[1] == "3") b->_set_graph_value(1, "0");
+    else                             b->_set_graph_value(1, "1");
+    b->do_callback();
   }
  public:
   inputRange(int x, int y, int w, int h, double max_number, const char *l=0) 
     : Fl_Group(x,y,w,h,l), _min(-max_number), _max(max_number), _step(1.),
       _max_number(max_number)
   {
-    int dot_w = FL_NORMAL_SIZE - 2, loop_w = FL_NORMAL_SIZE + 6;
-    int input_w = w - dot_w - loop_w;
+    int dot_w = FL_NORMAL_SIZE - 2, loop_w = FL_NORMAL_SIZE + 6, graph_w = loop_w;
+    int input_w = w - dot_w - loop_w - 2 * graph_w;
     int range_w = input_w / 2;
 
     _input = new Fl_Value_Input(x, y, input_w, h);
@@ -198,6 +243,20 @@ class inputRange : public Fl_Group {
     _loop_butt->callback(_loop_butt_cb, this);
     _loop_butt->tooltip("Loop over range when computing");
 
+    _graph_butt[0] = new Fl_Toggle_Button
+      (x + input_w + dot_w + loop_w, y, graph_w, h);
+    _graph_butt[0]->label("@-1gmsh_graph_x");
+    _graph_butt[0]->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
+    _graph_butt[0]->callback(_graph_butt_x_cb, this);
+    _graph_butt[0]->tooltip("Use range as abscissa of X-Y graph");
+
+    _graph_butt[1] = new Fl_Toggle_Button
+      (x + input_w + dot_w + loop_w + graph_w, y, graph_w, h);
+    _graph_butt[1]->label("@-1gmsh_graph_y");
+    _graph_butt[1]->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE);
+    _graph_butt[1]->callback(_graph_butt_y_cb, this);
+    _graph_butt[1]->tooltip("Use range as ordinate of X-Y graph");
+
     end(); // close the group
     resizable(_input);
   }
@@ -211,13 +270,10 @@ class inputRange : public Fl_Group {
   double maximum() { return _max; }
   void step(double val) { _step = val; _values2string(); }
   double step() { return _step; }
-  void loop(const std::string &val) 
-  {
-    _set_loop_value(val);
-  }
-  std::string loop()
-  { 
-    if(!_loop_butt->value()) return "0";
-    else return _loop_butt->label();
-  }
+  void loop(const std::string &val){ _set_loop_value(val); }
+  std::string loop(){ return _loop_val; }
+  void graph_x(const std::string &val){ _set_graph_value(0, val); }
+  std::string graph_x(){ return _graph_val[0]; }
+  void graph_y(const std::string &val){ _set_graph_value(1, val); }
+  std::string graph_y(){ return _graph_val[1]; }
 };
diff --git a/Fltk/onelabWindow.cpp b/Fltk/onelabWindow.cpp
index 9da6aba9da..ec961b282c 100644
--- a/Fltk/onelabWindow.cpp
+++ b/Fltk/onelabWindow.cpp
@@ -23,6 +23,7 @@
 #include "CreateFile.h"
 #include "drawContext.h"
 #include "PView.h"
+#include "PViewData.h"
 #include "PViewOptions.h"
 #include "FlGui.h"
 #include "paletteWindow.h"
@@ -181,34 +182,27 @@ bool onelab::localNetworkClient::run(const std::string &what)
       break;
     case GmshSocket::GMSH_PARAMETER_QUERY:
       {
-        std::string type, name;
+        std::string type, name, reply;
         onelab::parameter::getTypeAndNameFromChar(message, type, name);
         if(type == "number"){
           std::vector<onelab::number> par;
           get(par, name);
-          if(par.size() == 1){
-            std::string reply = par[0].toChar();
-            server->SendMessage(GmshSocket::GMSH_PARAMETER, reply.size(), &reply[0]);
-          }
-          else{
-            std::string reply = "Parameter (number) " + name + " not found";
-            server->SendMessage(GmshSocket::GMSH_INFO, reply.size(), &reply[0]);
-          }
+          if(par.size() == 1) reply = par[0].toChar();
         }
         else if(type == "string"){
           std::vector<onelab::string> par;
           get(par, name);
-          if(par.size() == 1){
-            std::string reply = par[0].toChar();
-            server->SendMessage(GmshSocket::GMSH_PARAMETER, reply.size(), &reply[0]);
-          }
-          else{
-            std::string reply = "Parameter (string) " + name + " not found";
-            server->SendMessage(GmshSocket::GMSH_INFO, reply.size(), &reply[0]);
-          }
+          if(par.size() == 1) reply = par[0].toChar();
         }
         else
           Msg::Error("FIXME query not done for this parameter type");
+        if(reply.size()){
+          server->SendMessage(GmshSocket::GMSH_PARAMETER, reply.size(), &reply[0]);
+        }
+        else{
+          reply = "Parameter '" + name + "' not found";
+          server->SendMessage(GmshSocket::GMSH_INFO, reply.size(), &reply[0]);
+        }
       }
       break;
     case GmshSocket::GMSH_PROGRESS:
@@ -429,6 +423,83 @@ static bool stopOnError(const std::string &client)
   return false;
 }
 
+static std::vector<double> getRange(onelab::number &p)
+{
+  std::vector<double> v;
+  if(p.getChoices().size()){
+    v = p.getChoices();
+  }
+  else if(p.getMin() != -onelab::parameter::maxNumber() &&
+          p.getMax() != onelab::parameter::maxNumber() && p.getStep()){
+    for(double d = p.getMin(); d <= p.getMax(); d += p.getStep())
+      v.push_back(d);
+  }
+  return v;
+}
+
+static std::string getShortName(const std::string &name, const std::string &ok="") 
+{
+  if(ok.size()) return ok;
+  std::string s = name;
+  // remove path
+  std::string::size_type last = name.find_last_of('/');
+  if(last != std::string::npos)
+    s = name.substr(last + 1);
+  // remove starting numbers
+  while(s.size() && s[0] >= '0' && s[0] <= '9')
+    s = s.substr(1);
+  return s;
+}
+
+static void updateOnelabGraph(std::string num)
+{
+  bool changed = false;
+  for(unsigned int i = 0; i < PView::list.size(); i++){
+    if(PView::list[i]->getData()->getFileName() == "ONELAB" + num){
+      delete PView::list[i];
+      changed = true;
+      break;
+    }
+  }
+  
+  std::vector<double> x, y;
+  std::string xName, yName;
+  std::vector<onelab::number> numbers;
+  onelab::server::instance()->get(numbers);
+  for(unsigned int i = 0; i < numbers.size(); i++){
+    if(numbers[i].getAttribute("graph_x") == num){
+      x = getRange(numbers[i]);
+      xName = getShortName(numbers[i].getName(), numbers[i].getShortHelp());
+    }
+    if(numbers[i].getAttribute("graph_y") == num){
+      y = getRange(numbers[i]);
+      yName = getShortName(numbers[i].getName(), numbers[i].getShortHelp());
+    }
+  }
+  if(x.size() != y.size()){
+    x.clear(); xName.clear();
+    for(unsigned int i = 0; i < y.size(); i++) x.push_back(i);
+  }
+  if(y.size()){
+    PView *v = new PView(xName, yName, x, y);
+    v->getData()->setFileName("ONELAB" + num);
+    v->getOptions()->intervalsType = PViewOptions::Discrete;
+    changed = true;
+  }
+  
+  if(changed){
+    FlGui::instance()->updateViews();
+    drawContext::global()->draw();
+  }
+}
+
+static void updateOnelabGraphs()
+{
+  updateOnelabGraph("1");
+  updateOnelabGraph("2");
+  updateOnelabGraph("3");
+}
+
 void onelab_cb(Fl_Widget *w, void *data)
 {
   if(!data) return;
@@ -538,6 +609,7 @@ void onelab_cb(Fl_Widget *w, void *data)
       if(stop) break;
     }
 
+    updateOnelabGraphs();
     FlGui::instance()->onelab->rebuildTree();
 
   } while(action == "compute" && incrementLoop() && !stop);
@@ -573,7 +645,10 @@ static void onelab_input_range_cb(Fl_Widget *w, void *data)
     numbers[0].setStep(o->step());
     numbers[0].setChoices(o->choices());
     numbers[0].setAttribute("loop", o->loop());
+    numbers[0].setAttribute("graph_x", o->graph_x());
+    numbers[0].setAttribute("graph_y", o->graph_y());
     onelab::server::instance()->set(numbers[0]);
+    updateOnelabGraphs();
   }
 }
 
@@ -658,7 +733,7 @@ onelabWindow::onelabWindow(int deltaFontSize)
   _gear->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE);
   _gear->add("Reset database", 0, onelab_cb, (void*)"reset");
   _gear->add("Print database", 0, onelab_dump_cb);
-  _gear->add("Remesh automatically", 0, 0, 0, FL_MENU_TOGGLE);
+  _gear->add("_Remesh automatically", 0, 0, 0, FL_MENU_TOGGLE);
   ((Fl_Menu_Item*)_gear->menu())[2].set();
   _gearFrozenMenuSize = _gear->menu()->size();
 
@@ -675,19 +750,6 @@ onelabWindow::onelabWindow(int deltaFontSize)
   FL_NORMAL_SIZE += deltaFontSize;
 }
 
-static std::string getShortName(const std::string &name) 
-{
-  std::string s = name;
-  // remove path
-  std::string::size_type last = name.find_last_of('/');
-  if(last != std::string::npos)
-    s = name.substr(last + 1);
-  // remove starting numbers
-  while(s.size() && s[0] >= '0' && s[0] <= '9')
-    s = s.substr(1);
-  return s;
-}
-
 void onelabWindow::rebuildTree()
 {
   int width = (int)(0.5 * _tree->w());
@@ -705,8 +767,7 @@ void onelabWindow::rebuildTree()
   for(unsigned int i = 0; i < numbers.size(); i++){
     Fl_Tree_Item *n = _tree->add(numbers[i].getName().c_str());
     n->labelsize(FL_NORMAL_SIZE + 5);
-    std::string label = numbers[i].getShortHelp();
-    if(label.empty()) label = getShortName(numbers[i].getName());
+    std::string label = getShortName(numbers[i].getName(), numbers[i].getShortHelp());
     _tree->begin();
     if(numbers[i].getChoices().size() == 2 &&
        numbers[i].getChoices()[0] == 0 && numbers[i].getChoices()[1] == 1){
@@ -728,6 +789,8 @@ void onelabWindow::rebuildTree()
       but->step(numbers[i].getStep());
       but->choices(numbers[i].getChoices());
       but->loop(numbers[i].getAttribute("loop"));
+      but->graph_x(numbers[i].getAttribute("graph_x"));
+      but->graph_y(numbers[i].getAttribute("graph_y"));
       but->align(FL_ALIGN_RIGHT);
       but->callback(onelab_input_range_cb, (void*)n);
       but->when(FL_WHEN_RELEASE | FL_WHEN_ENTER_KEY);
@@ -741,8 +804,7 @@ void onelabWindow::rebuildTree()
   for(unsigned int i = 0; i < strings.size(); i++){
     Fl_Tree_Item *n = _tree->add(strings[i].getName().c_str());
     n->labelsize(FL_NORMAL_SIZE + 5);
-    std::string label = strings[i].getShortHelp();
-    if(label.empty()) label = getShortName(strings[i].getName());
+    std::string label = getShortName(strings[i].getName(), strings[i].getShortHelp());
     _tree->begin();
     Fl_Input_Choice *but = new Fl_Input_Choice(1, 1, width, 1);
     _treeWidgets.push_back(but);
diff --git a/Post/PView.cpp b/Post/PView.cpp
index 8cc88c76f2..5e5b65f237 100644
--- a/Post/PView.cpp
+++ b/Post/PView.cpp
@@ -86,17 +86,15 @@ PView::PView(std::string xname, std::string yname,
   _init();
   PViewDataList *data = new PViewDataList();
   for(unsigned int i = 0; i < y.size(); i++){
-    double d;
     if(x.size() == y.size()){
       data->SP.push_back(x[i]);
     }
     else{
-      d = y.size() > 1 ? (double)i / (double)(y.size() - 1) : 0.;
+      double d = y.size() > 1 ? (double)i / (double)(y.size() - 1) : 0.;
       data->SP.push_back(d);
     }
-    d = 0.;
-    data->SP.push_back(d);
-    data->SP.push_back(d);
+    data->SP.push_back(0.);
+    data->SP.push_back(0.);
     data->SP.push_back(y[i]);
     data->NbSP++;
   }
-- 
GitLab