From 61366f3b102ed39f651297aac06d3bf2c0ca7f15 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sat, 1 Apr 2017 09:00:15 +0100
Subject: [PATCH] GUI for Fillet + Fillet now deletes the original shape

---
 Fltk/contextWindow.cpp     | 19 ++++++--
 Fltk/graphicWindow.cpp     | 93 ++++++++++++++++++++++++++++++++++++--
 Geo/GModelIO_OCC.cpp       | 26 ++++++-----
 Geo/GModelIO_OCC.h         |  3 +-
 Geo/GeoStringInterface.cpp |  9 ++++
 Geo/GeoStringInterface.h   |  2 +
 Parser/Gmsh.tab.cpp        |  4 +-
 Parser/Gmsh.y              |  2 +-
 demos/boolean/fillet.geo   |  6 ---
 demos/boolean/fillet2.geo  |  2 -
 demos/boolean/fillet3.geo  |  2 -
 11 files changed, 135 insertions(+), 33 deletions(-)

diff --git a/Fltk/contextWindow.cpp b/Fltk/contextWindow.cpp
index bebdccf86e..3155cb726b 100644
--- a/Fltk/contextWindow.cpp
+++ b/Fltk/contextWindow.cpp
@@ -663,7 +663,7 @@ transformContextWindow::transformContextWindow(int deltaFontSize)
 {
   FL_NORMAL_SIZE -= deltaFontSize;
 
-  int width = 31 * FL_NORMAL_SIZE;
+  int width = 34 * FL_NORMAL_SIZE;
   int height = 5 * WB + 10 * BH;
 
   win = new paletteWindow(width, height, CTX::instance()->nonModalWindows ? true : false,
@@ -776,13 +776,22 @@ transformContextWindow::transformContextWindow(int deltaFontSize)
       butt[5]->value(1);
       group[4]->end();
     }
-    // 5: Delete
+    // 5: Fillet
     {
       group[5] = new Fl_Group
+        (WB, WB + BH, width - 2 * WB, height - 2 * WB - BH, "Fillet");
+      input[18] = new Fl_Input(2 * WB, 2 * WB + 1 * BH, IW, BH, "Radius");
+      input[18]->value("0.1");
+      input[18]->align(FL_ALIGN_RIGHT);
+      group[5]->end();
+    }
+    // 6: Delete
+    {
+      group[6] = new Fl_Group
         (WB, WB + BH, width - 2 * WB, height - 2 * WB - BH, "Delete");
       butt[6] = new Fl_Check_Button(2 * WB, 2 * WB + 1 * BH, IW, BH, "Recursive");
       butt[6]->value(1);
-      group[5]->end();
+      group[6]->end();
     }
     o->end();
   }
@@ -800,8 +809,8 @@ transformContextWindow::transformContextWindow(int deltaFontSize)
 
 void transformContextWindow::show(int pane, bool extrude)
 {
-  if(pane < 0 || pane > 5) return;
-  for(int i = 0; i < 6; i++)
+  if(pane < 0 || pane > 6) return;
+  for(int i = 0; i < 7; i++)
     group[i]->hide();
   for(int i = 0; i < 4; i++){
     if(extrude) butt[i]->deactivate();
diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index 71e3295f03..b19b394f1f 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -1536,7 +1536,7 @@ static void geometry_elementary_extrude_rotate_cb(Fl_Widget *w, void *data)
 
 static void geometry_elementary_delete_cb(Fl_Widget *w, void *data)
 {
-  FlGui::instance()->transformContext->show(5);
+  FlGui::instance()->transformContext->show(6);
   action_point_line_surface_volume(6);
 }
 
@@ -1653,6 +1653,91 @@ static void geometry_elementary_boolean_cb(Fl_Widget *w, void *data)
   Msg::StatusGl("");
 }
 
+static void geometry_elementary_fillet_cb(Fl_Widget *w, void *data)
+{
+  opt_geometry_volumes(0, GMSH_SET | GMSH_GUI, 1);
+  opt_geometry_lines(0, GMSH_SET | GMSH_GUI, 1);
+
+  FlGui::instance()->transformContext->show(5);
+
+  bool selectRegions = true;
+  std::vector<int> regions, edges;
+
+  while(1) {
+    if(regions.empty())
+      Msg::StatusGl("Select volume\n"
+                    "[Press 'e' to end selection or 'q' to abort]");
+    else if(selectRegions)
+      Msg::StatusGl("Select volume\n"
+                    "[Press 'e' to end selection, 'u' to undo last selection or "
+                    "'q' to abort]");
+    else if(edges.empty())
+      Msg::StatusGl("Select line\n"
+                    "[Press 'e' to end selection or 'q' to abort]");
+    else
+      Msg::StatusGl("Select line\n"
+                    "[Press 'e' to end selection, 'u' to undo last selection or "
+                    "'q' to abort]");
+
+    char ib = FlGui::instance()->selectEntity(selectRegions ? ENT_VOLUME : ENT_LINE);
+    if(ib == 'l') {
+      for(unsigned int i = 0; i < FlGui::instance()->selectedEdges.size(); i++){
+        if(FlGui::instance()->selectedEdges[i]->getSelection() != 1){
+          FlGui::instance()->selectedEdges[i]->setSelection(1);
+          edges.push_back(FlGui::instance()->selectedEdges[i]->tag());
+        }
+      }
+      for(unsigned int i = 0; i < FlGui::instance()->selectedRegions.size(); i++){
+        if(FlGui::instance()->selectedRegions[i]->getSelection() != 1){
+          FlGui::instance()->selectedRegions[i]->setSelection(1);
+          regions.push_back(FlGui::instance()->selectedRegions[i]->tag());
+        }
+      }
+    }
+    if(ib == 'r') {
+      Msg::Warning("Entity de-selection not supported yet during boolean operation");
+    }
+    if(ib == 'u') {
+      if(selectRegions && regions.size()){
+        GRegion *ge = GModel::current()->getRegionByTag(regions.back());
+        if(ge) ge->setSelection(0);
+        regions.pop_back();
+      }
+      else if(edges.size()){
+        GEdge *ge = GModel::current()->getEdgeByTag(edges.back());
+        if(ge) ge->setSelection(0);
+        edges.pop_back();
+      }
+    }
+    if(ib == 'e') {
+      if(selectRegions){
+        if(regions.empty())
+          Msg::Error("At least one volume must be selected");
+        else
+          selectRegions = false;
+      }
+      else if(edges.empty()){
+        Msg::Error("At least one line must be selected");
+      }
+      else{
+        apply_fillet(GModel::current()->getFileName(), regions, edges,
+                     FlGui::instance()->transformContext->input[18]->value());
+        GModel::current()->setSelection(0);
+        selectRegions = true;
+        regions.clear();
+        edges.clear();
+      }
+    }
+    if(ib == 'q') {
+      GModel::current()->setSelection(0);
+      break;
+    }
+  }
+
+  drawContext::global()->draw();
+  Msg::StatusGl("");
+}
+
 static void geometry_elementary_split_cb(Fl_Widget *w, void *data)
 {
   if(!data) return;
@@ -3921,8 +4006,6 @@ static menuItem static_modules[] = {
    (Fl_Callback *)geometry_elementary_scale_cb} ,
   {"0Modules/Geometry/Elementary entities/Transform/Symmetry",
    (Fl_Callback *)geometry_elementary_symmetry_cb} ,
-  {"0Modules/Geometry/Elementary entities/Transform/Split line",
-   (Fl_Callback *)geometry_elementary_split_cb,(void*)"Line"},
   {"0Modules/Geometry/Elementary entities/Extrude/Translate",
    (Fl_Callback *)geometry_elementary_extrude_translate_cb} ,
   {"0Modules/Geometry/Elementary entities/Extrude/Rotate",
@@ -3935,6 +4018,10 @@ static menuItem static_modules[] = {
    (Fl_Callback *)geometry_elementary_boolean_cb, (void*)"BooleanDifference"} ,
   {"0Modules/Geometry/Elementary entities/Boolean/Fragments",
    (Fl_Callback *)geometry_elementary_boolean_cb, (void*)"BooleanFragments"} ,
+  {"0Modules/Geometry/Elementary entities/Fillet",
+   (Fl_Callback *)geometry_elementary_fillet_cb},
+  {"0Modules/Geometry/Elementary entities/Split line",
+   (Fl_Callback *)geometry_elementary_split_cb, (void*)"Line"},
   {"0Modules/Geometry/Elementary entities/Delete",
    (Fl_Callback *)geometry_elementary_delete_cb} ,
   {"0Modules/Geometry/Elementary entities/Coherence",
diff --git a/Geo/GModelIO_OCC.cpp b/Geo/GModelIO_OCC.cpp
index 4b8bdd2739..208928cf31 100644
--- a/Geo/GModelIO_OCC.cpp
+++ b/Geo/GModelIO_OCC.cpp
@@ -1711,8 +1711,18 @@ bool OCC_Internals::addPipe(const std::vector<std::pair<int, int> > &inDimTags,
 
 bool OCC_Internals::fillet(const std::vector<int> &regionTags,
                            const std::vector<int> &edgeTags, double radius,
-                           std::vector<std::pair<int, int> > &outDimTags)
+                           std::vector<std::pair<int, int> > &outDimTags,
+                           bool removeRegion)
 {
+  std::vector<TopoDS_Edge> edges;
+  for(unsigned int i = 0; i < edgeTags.size(); i++){
+    if(!_tagEdge.IsBound(edgeTags[i])){
+      Msg::Error("Unknown OpenCASCADE edge with tag %d", edgeTags[i]);
+      return false;
+    }
+    edges.push_back(TopoDS::Edge(_tagEdge.Find(edgeTags[i])));
+  }
+
   // build a single compound shape
   BRep_Builder b;
   TopoDS_Compound c;
@@ -1724,21 +1734,15 @@ bool OCC_Internals::fillet(const std::vector<int> &regionTags,
     }
     TopoDS_Shape shape = find(3, regionTags[i]);
     b.Add(c, shape);
+    if(removeRegion) unbind(shape, 3, regionTags[i], true); // recursive
   }
   TopoDS_Shape result;
   try{
     BRepFilletAPI_MakeFillet f(c);
-    for(unsigned int i = 0; i < edgeTags.size(); i++){
-      if(!_tagEdge.IsBound(edgeTags[i])){
-        Msg::Error("Unknown OpenCASCADE edge with tag %d", edgeTags[i]);
-        return false;
-      }
-      TopoDS_Edge edge = TopoDS::Edge(_tagEdge.Find(edgeTags[i]));
-      f.Add(edge);
-    }
-    for(int i = 1; i <= f.NbContours(); i++){
+    for(unsigned int i = 0; i < edges.size(); i++)
+      f.Add(edges[i]);
+    for(int i = 1; i <= f.NbContours(); i++)
       f.SetRadius(radius, i, 1);
-    }
     f.Build();
     if(!f.IsDone()) {
       Msg::Error("Could not compute fillet");
diff --git a/Geo/GModelIO_OCC.h b/Geo/GModelIO_OCC.h
index cdc425420c..8868ff2ed9 100644
--- a/Geo/GModelIO_OCC.h
+++ b/Geo/GModelIO_OCC.h
@@ -206,7 +206,8 @@ class OCC_Internals {
 
   // fillet
   bool fillet(const std::vector<int> &regionTags, const std::vector<int> &edgeTags,
-              double radius, std::vector<std::pair<int, int> > &ouDimTags);
+              double radius, std::vector<std::pair<int, int> > &ouDimTags,
+              bool removeRegion);
 
   // apply boolean operator
   bool applyBooleanOperator(int tag, BooleanOperator op,
diff --git a/Geo/GeoStringInterface.cpp b/Geo/GeoStringInterface.cpp
index 1323e1aab5..5cb64f8ae4 100644
--- a/Geo/GeoStringInterface.cpp
+++ b/Geo/GeoStringInterface.cpp
@@ -669,6 +669,15 @@ void apply_boolean(const std::string &fileName, const std::string &op,
   add_infile(sstream.str(), fileName);
 }
 
+void apply_fillet(const std::string &fileName, const std::vector<int> &regions,
+                  const std::vector<int> &edges, const std::string &radius)
+{
+  std::ostringstream sstream;
+  sstream << "Fillet{" << vector2String(regions) << "}{"
+          << vector2String(edges) << "}{" << radius << "}";
+  add_infile(sstream.str(), fileName);
+}
+
 void coherence(const std::string &fileName)
 {
   add_infile("Coherence;", fileName);
diff --git a/Geo/GeoStringInterface.h b/Geo/GeoStringInterface.h
index 9e41ceda06..a66a8a2734 100644
--- a/Geo/GeoStringInterface.h
+++ b/Geo/GeoStringInterface.h
@@ -101,6 +101,8 @@ void apply_boolean(const std::string &fileName, const std::string &op,
                    const std::vector<std::pair<int, int> > &object,
                    const std::vector<std::pair<int, int> > &tool,
                    int deleteObject, int deleteTool);
+void apply_fillet(const std::string &fileName, const std::vector<int> &regions,
+                  const std::vector<int> &edges, const std::string &radius);
 void coherence(const std::string &fileName);
 void delete_entities(const std::string &fileName,
                      const std::vector<std::pair<int, int> > &l,
diff --git a/Parser/Gmsh.tab.cpp b/Parser/Gmsh.tab.cpp
index 7fd4b2379e..ea3f6e91fc 100644
--- a/Parser/Gmsh.tab.cpp
+++ b/Parser/Gmsh.tab.cpp
@@ -10652,7 +10652,7 @@ yyreduce:
         ListOfDouble2Vector((yyvsp[(3) - (10)].l), regions); ListOfDouble2Vector((yyvsp[(6) - (10)].l), edges);
         std::vector<std::pair<int, int> > outDimTags;
         r = GModel::current()->getOCCInternals()->fillet
-          (regions, edges, radius, outDimTags);
+          (regions, edges, radius, outDimTags, true);
         VectorOfPairs2ListOfShapes(outDimTags, (yyval.l));
       }
       else{
@@ -14742,7 +14742,7 @@ int NEWPHYSICAL()
   if(CTX::instance()->geom.oldNewreg)
     return NEWREG();
   else
-    return (GModel::current()->getGEOInternals()->getMaxPhysicalTag() + 1);
+    return GModel::current()->getGEOInternals()->getMaxPhysicalTag() + 1;
 }
 
 
diff --git a/Parser/Gmsh.y b/Parser/Gmsh.y
index 15ebb184fc..20fedd2ddb 100644
--- a/Parser/Gmsh.y
+++ b/Parser/Gmsh.y
@@ -3834,7 +3834,7 @@ Extrude :
         ListOfDouble2Vector($3, regions); ListOfDouble2Vector($6, edges);
         std::vector<std::pair<int, int> > outDimTags;
         r = GModel::current()->getOCCInternals()->fillet
-          (regions, edges, radius, outDimTags);
+          (regions, edges, radius, outDimTags, true);
         VectorOfPairs2ListOfShapes(outDimTags, $$);
       }
       else{
diff --git a/demos/boolean/fillet.geo b/demos/boolean/fillet.geo
index 9daa1a956c..c2eed50f22 100644
--- a/demos/boolean/fillet.geo
+++ b/demos/boolean/fillet.geo
@@ -8,9 +8,3 @@ f() = Abs(Boundary{ Volume{1}; });
 e() = Unique(Abs(Boundary{ Surface{f()}; }));
 
 Fillet{1}{e()}{0.2}
-
-tmp2() = Fillet{1}{1,2,4}{0.05};
-
-Translate{2,0,0} { Volume{tmp2(0)}; }
-
-Recursive Delete{ Volume{1}; }
diff --git a/demos/boolean/fillet2.geo b/demos/boolean/fillet2.geo
index 51c4fe22ce..22701a34b0 100644
--- a/demos/boolean/fillet2.geo
+++ b/demos/boolean/fillet2.geo
@@ -9,5 +9,3 @@ f() = Abs(Boundary{ Volume{a()}; });
 e() = Unique(Abs(Boundary{ Surface{f()}; }));
 
 Fillet{a()}{e()}{1}
-
-Recursive Delete{ Volume{a()}; }
diff --git a/demos/boolean/fillet3.geo b/demos/boolean/fillet3.geo
index d83202da2f..46d7fadecf 100644
--- a/demos/boolean/fillet3.geo
+++ b/demos/boolean/fillet3.geo
@@ -14,7 +14,6 @@ v_ = v_out;
 f_[] = Abs(Boundary{ Volume{v_}; });
 e_[] = Unique( Abs(Boundary{ Surface{f_[]}; }) );
 v_out = Fillet{v_}{e_[2-1], e_[4-1], e_[6-1], e_[8-1]}{r_out};
-Recursive Delete{ Volume{v_}; }
 
 v_in = newv;
 Block(v_in) = {
@@ -25,6 +24,5 @@ v_ = v_in;
 f_[] = Abs(Boundary{ Volume{v_}; });
 e_[] = Unique( Abs(Boundary{ Surface{f_[]}; }) );
 v_in = Fillet{v_}{e_[2-1], e_[4-1], e_[6-1], e_[8-1]}{r_in};
-Recursive Delete{ Volume{v_}; }
 
 BooleanDifference { Volume{v_out}; Delete; }{ Volume{v_in}; Delete; }
-- 
GitLab