1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <set>
7 #include "GModel.h"
8 #include "MLine.h"
9 #include "ExtrudeParams.h"
10 #include "GmshMessage.h"
11 
createElements(GEdge * ge)12 static void createElements(GEdge *ge)
13 {
14   // create elements
15   for(std::size_t i = 0; i < ge->mesh_vertices.size() + 1; i++) {
16     MVertex *v0 = (i == 0) ? ge->getBeginVertex()->mesh_vertices[0] :
17                              ge->mesh_vertices[i - 1];
18     MVertex *v1 = (i == ge->mesh_vertices.size()) ?
19                     ge->getEndVertex()->mesh_vertices[0] :
20                     ge->mesh_vertices[i];
21     MLine *newElem = new MLine(v0, v1);
22     ge->lines.push_back(newElem);
23   }
24 }
25 
extrudeMesh(GVertex * from,GEdge * to)26 static void extrudeMesh(GVertex *from, GEdge *to)
27 {
28   ExtrudeParams *ep = to->meshAttributes.extrude;
29 
30   MVertex *v = from->mesh_vertices[0];
31   for(int j = 0; j < ep->mesh.NbLayer; j++) {
32     for(int k = 0; k < ep->mesh.NbElmLayer[j]; k++) {
33       double x = v->x(), y = v->y(), z = v->z();
34       ep->Extrude(j, k + 1, x, y, z);
35       if(j != ep->mesh.NbLayer - 1 || k != ep->mesh.NbElmLayer[j] - 1) {
36         Range<double> r = to->parBounds(0);
37         double t = r.low() + ep->u(j, k + 1) * (r.high() - r.low());
38         MEdgeVertex *newv = new MEdgeVertex(x, y, z, to, t);
39         to->mesh_vertices.push_back(newv);
40       }
41     }
42   }
43   createElements(to);
44 }
45 
copyMesh(GEdge * from,GEdge * to)46 static void copyMesh(GEdge *from, GEdge *to)
47 {
48   ExtrudeParams *ep = to->meshAttributes.extrude;
49 
50   int direction = (ep->geo.Source > 0) ? 1 : -1;
51 
52   Range<double> u_bounds = from->parBounds(0);
53   double u_min = u_bounds.low();
54   double u_max = u_bounds.high();
55 
56 #if 0
57   // old version, which directly uses nodes; this can lead to unexpected results
58   // if the nodes in from->mesh_vertices.size() are not sorted, which can happen
59   // e.g. if createTopology() has been called
60   for(std::size_t i = 0; i < from->mesh_vertices.size(); i++) {
61     int index = (direction < 0) ? (from->mesh_vertices.size() - 1 - i) : i;
62     MVertex *v = from->mesh_vertices[index];
63     double x = v->x(), y = v->y(), z = v->z();
64     ep->Extrude(ep->mesh.NbLayer - 1, ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1],
65                 x, y, z);
66     double u;
67     v->getParameter(0, u);
68     double newu = (direction > 0) ? u : (u_max - u + u_min);
69     MEdgeVertex *newv = new MEdgeVertex(x, y, z, to, newu);
70     to->mesh_vertices.push_back(newv);
71   }
72 #else
73   // so it's better to go back to the elements, which are assumed to be stored
74   // in the correct order
75   for(int i = 0; i < (int)from->lines.size() - 1; i++) {
76     int index = (direction < 0) ? (from->lines.size() - i - 2) : i;
77     MVertex *v = from->lines[index]->getVertex(1);
78     double x = v->x(), y = v->y(), z = v->z();
79     ep->Extrude(ep->mesh.NbLayer - 1, ep->mesh.NbElmLayer[ep->mesh.NbLayer - 1],
80                 x, y, z);
81     double u;
82     v->getParameter(0, u);
83     double newu = (direction > 0) ? u : (u_max - u + u_min);
84     MEdgeVertex *newv = new MEdgeVertex(x, y, z, to, newu);
85     to->mesh_vertices.push_back(newv);
86   }
87 #endif
88 
89   createElements(to);
90 }
91 
MeshExtrudedCurve(GEdge * ge)92 int MeshExtrudedCurve(GEdge *ge)
93 {
94   ExtrudeParams *ep = ge->meshAttributes.extrude;
95 
96   if(!ep || !ep->mesh.ExtrudeMesh) return 0;
97 
98   if(!ge->getBeginVertex() || !ge->getEndVertex()) {
99     Msg::Error("Cannot extrude curve %d with no begin or end point", ge->tag());
100     return 0;
101   }
102 
103   Msg::Info("Meshing curve %d (Extruded)", ge->tag());
104 
105   if(ep->geo.Mode == EXTRUDED_ENTITY) {
106     // curve is extruded from a point
107     extrudeMesh(ge->getBeginVertex(), ge);
108   }
109   else {
110     GEdge *from = ge->model()->getEdgeByTag(std::abs(ep->geo.Source));
111     // curve is a copy of another curve (the "top" of the extrusion)
112     if(!from) {
113       Msg::Error("Unknown source curve %d for extrusion", ep->geo.Source);
114       return 0;
115     }
116     else if(from->geomType() != GEntity::DiscreteCurve &&
117             from->meshStatistics.status != GEdge::DONE) {
118       // cannot mesh this edge yet: will do it later
119       return 1;
120     }
121 
122     copyMesh(from, ge);
123     if(ge->getMeshMaster() == from) {
124       // explicit periodic constraint, to store node correspondance
125       ge->setMeshMaster(from, ge->affineTransform);
126     }
127   }
128 
129   ge->meshStatistics.status = GEdge::DONE;
130   return 1;
131 }
132