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 <sstream>
7 #include "GmshConfig.h"
8 #include "GmshDefines.h"
9 #include "GmshGlobal.h"
10 #include "MallocUtils.h"
11 #include "GModel.h"
12 #include "GModelIO_GEO.h"
13 #include "GModelIO_OCC.h"
14 #include "GVertex.h"
15 #include "GEdge.h"
16 #include "GFace.h"
17 #include "GRegion.h"
18 #include "discreteVertex.h"
19 #include "discreteEdge.h"
20 #include "discreteFace.h"
21 #include "discreteRegion.h"
22 #include "partitionVertex.h"
23 #include "partitionEdge.h"
24 #include "partitionFace.h"
25 #include "partitionRegion.h"
26 #include "ghostEdge.h"
27 #include "ghostFace.h"
28 #include "ghostRegion.h"
29 #include "MVertex.h"
30 #include "MPoint.h"
31 #include "MLine.h"
32 #include "MTriangle.h"
33 #include "MQuadrangle.h"
34 #include "MTetrahedron.h"
35 #include "MHexahedron.h"
36 #include "MPrism.h"
37 #include "MPyramid.h"
38 #include "ExtrudeParams.h"
39 #include "StringUtils.h"
40 #include "Context.h"
41 #include "polynomialBasis.h"
42 #include "pyramidalBasis.h"
43 #include "Numeric.h"
44 #include "OS.h"
45 #include "HierarchicalBasisH1Quad.h"
46 #include "HierarchicalBasisH1Tria.h"
47 #include "HierarchicalBasisH1Line.h"
48 #include "HierarchicalBasisH1Brick.h"
49 #include "HierarchicalBasisH1Tetra.h"
50 #include "HierarchicalBasisH1Pri.h"
51 #include "HierarchicalBasisH1Point.h"
52 #include "HierarchicalBasisHcurlLine.h"
53 #include "HierarchicalBasisHcurlQuad.h"
54 #include "HierarchicalBasisHcurlBrick.h"
55 #include "HierarchicalBasisHcurlTria.h"
56 #include "HierarchicalBasisHcurlTetra.h"
57 #include "HierarchicalBasisHcurlPri.h"
58 
59 #if defined(HAVE_MESH)
60 #include "Field.h"
61 #include "meshGFace.h"
62 #include "meshGFaceDelaunayInsertion.h"
63 #include "meshGFaceOptimize.h"
64 #include "meshGRegionDelaunayInsertion.h"
65 #include "meshGRegionHxt.h"
66 #include "gmshCrossFields.h"
67 #endif
68 
69 #if defined(HAVE_POST)
70 #include "PView.h"
71 #include "PViewData.h"
72 #include "PViewDataList.h"
73 #include "PViewDataGModel.h"
74 #include "PViewOptions.h"
75 #endif
76 
77 #if defined(HAVE_PLUGINS)
78 #include "PluginManager.h"
79 #endif
80 
81 #if defined(HAVE_OPENGL)
82 #include "drawContext.h"
83 #endif
84 
85 #if defined(HAVE_FLTK)
86 #include "FlGui.h"
87 #endif
88 
89 #if defined(HAVE_ONELAB)
90 #include "onelab.h"
91 #include "onelabUtils.h"
92 #endif
93 
94 // automatically generated C++ and C headers (in gmsh/api)
95 #include "gmsh.h"
96 extern "C" {
97 #include "gmshc.h"
98 }
99 
100 static int _initialized = 0;
101 static int _argc = 0;
102 static char **_argv = nullptr;
103 
_checkInit()104 static bool _checkInit()
105 {
106   if(!_initialized) {
107     Msg::Error("Gmsh has not been initialized");
108     return false;
109   }
110   if(!GModel::current()) {
111     Msg::Error("Gmsh has no current model");
112     return false;
113   }
114   return true;
115 }
116 
117 // gmsh
118 
initialize(int argc,char ** argv,bool readConfigFiles,bool run)119 GMSH_API void gmsh::initialize(int argc, char **argv, bool readConfigFiles,
120                                bool run)
121 {
122   if(_initialized) {
123     Msg::Warning("Gmsh has aleady been initialized");
124     return;
125   }
126 
127   // when running the app, create a model (that will be used in GmshInitialize
128   // to e.g. set the project name)
129   if(run) new GModel();
130 
131   if(GmshInitialize(argc, argv, readConfigFiles, false)) {
132     _initialized = 1;
133     _argc = argc;
134     _argv = new char *[_argc + 1];
135     for(int i = 0; i < argc; i++) _argv[i] = argv[i];
136     if(run) {
137       if(CTX::instance()->batch) {
138         if(!Msg::GetGmshClient()) CTX::instance()->terminal = 1;
139         GmshBatch();
140       }
141       else {
142         GmshFLTK(argc, argv);
143       }
144     }
145     else {
146       // throw an exception as soon as an error occurs, unless the GUI is
147       // running (by default the Gmsh app - and thus also when "run" is set -
148       // always keeps going after errors)
149       CTX::instance()->abortOnError = 2;
150       // show messages on the terminal
151       CTX::instance()->terminal = 1;
152     }
153     return;
154   }
155   Msg::Error("Something went wrong when initializing Gmsh");
156 }
157 
finalize()158 GMSH_API void gmsh::finalize()
159 {
160   if(!_checkInit()) return;
161   if(GmshFinalize()) {
162     _argc = 0;
163     if(_argv) delete[] _argv;
164     _argv = nullptr;
165     _initialized = 0;
166     return;
167   }
168   Msg::Error("Something went wrong when finalizing Gmsh");
169 }
170 
open(const std::string & fileName)171 GMSH_API void gmsh::open(const std::string &fileName)
172 {
173   if(!_checkInit()) return;
174   if(!GmshOpenProject(fileName))
175     Msg::Error("Could not open file '%s'", fileName.c_str());
176 }
177 
merge(const std::string & fileName)178 GMSH_API void gmsh::merge(const std::string &fileName)
179 {
180   if(!_checkInit()) return;
181   if(!GmshMergeFile(fileName))
182     Msg::Error("Could not merge file '%s'", fileName.c_str());
183 }
184 
write(const std::string & fileName)185 GMSH_API void gmsh::write(const std::string &fileName)
186 {
187   if(!_checkInit()) return;
188   if(!GmshWriteFile(fileName))
189     Msg::Error("Could not write file '%s'", fileName.c_str());
190 }
191 
clear()192 GMSH_API void gmsh::clear()
193 {
194   if(!_checkInit()) return;
195   if(!GmshClearProject()) Msg::Error("Could not clear project");
196 }
197 
198 // gmsh::option
199 
setNumber(const std::string & name,const double value)200 GMSH_API void gmsh::option::setNumber(const std::string &name,
201                                       const double value)
202 {
203   if(!_checkInit()) return;
204   std::string c, n;
205   int i;
206   SplitOptionName(name, c, n, i);
207   if(!GmshSetOption(c, n, value, i))
208     Msg::Error("Could not set option '%s'", name.c_str());
209 }
210 
getNumber(const std::string & name,double & value)211 GMSH_API void gmsh::option::getNumber(const std::string &name, double &value)
212 {
213   if(!_checkInit()) return;
214   std::string c, n;
215   int i;
216   SplitOptionName(name, c, n, i);
217   if(!GmshGetOption(c, n, value, i))
218     Msg::Error("Could not get option '%s'", name.c_str());
219 }
220 
setString(const std::string & name,const std::string & value)221 GMSH_API void gmsh::option::setString(const std::string &name,
222                                       const std::string &value)
223 {
224   if(!_checkInit()) return;
225   std::string c, n;
226   int i;
227   SplitOptionName(name, c, n, i);
228   if(!GmshSetOption(c, n, value, i))
229     Msg::Error("Could not set option '%s'", name.c_str());
230 }
231 
getString(const std::string & name,std::string & value)232 GMSH_API void gmsh::option::getString(const std::string &name,
233                                       std::string &value)
234 {
235   if(!_checkInit()) return;
236   std::string c, n;
237   int i;
238   SplitOptionName(name, c, n, i);
239   if(!GmshGetOption(c, n, value, i))
240     Msg::Error("Could not get option '%s'", name.c_str());
241 }
242 
setColor(const std::string & name,const int r,const int g,const int b,const int a)243 GMSH_API void gmsh::option::setColor(const std::string &name, const int r,
244                                      const int g, const int b, const int a)
245 {
246   if(!_checkInit()) return;
247   std::string c, n;
248   int i;
249   SplitOptionName(name, c, n, i);
250   // allow "Category.Color.Option" name for compatibility with .geo parser
251   n = ReplaceSubString("Color.", "", n);
252   unsigned int value = CTX::instance()->packColor(r, g, b, a);
253   if(!GmshSetOption(c, n, value, i))
254     Msg::Error("Could not set option '%s'", name.c_str());
255 }
256 
getColor(const std::string & name,int & r,int & g,int & b,int & a)257 GMSH_API void gmsh::option::getColor(const std::string &name, int &r, int &g,
258                                      int &b, int &a)
259 {
260   if(!_checkInit()) return;
261   std::string c, n;
262   int i;
263   SplitOptionName(name, c, n, i);
264   // allow "Category.Color.Option" name for compatibility with .geo parser
265   n = ReplaceSubString("Color.", "", n);
266   unsigned int value;
267   if(GmshGetOption(c, n, value, i)) {
268     r = CTX::instance()->unpackRed(value);
269     g = CTX::instance()->unpackGreen(value);
270     b = CTX::instance()->unpackBlue(value);
271     a = CTX::instance()->unpackAlpha(value);
272   }
273   else {
274     Msg::Error("Could not get option '%s'", name.c_str());
275   }
276 }
277 
278 // gmsh::model
279 
add(const std::string & name)280 GMSH_API void gmsh::model::add(const std::string &name)
281 {
282   if(!_checkInit()) return;
283   GModel *m = new GModel(name);
284   GModel::current(GModel::list.size() - 1);
285   if(!m) Msg::Error("Could not add model '%s'", name.c_str());
286 }
287 
remove()288 GMSH_API void gmsh::model::remove()
289 {
290   if(!_checkInit()) return;
291   GModel *m = GModel::current();
292   if(m)
293     delete m;
294   else
295     Msg::Error("Could not remove current model");
296 }
297 
list(std::vector<std::string> & names)298 GMSH_API void gmsh::model::list(std::vector<std::string> &names)
299 {
300   if(!_checkInit()) return;
301   for(std::size_t i = 0; i < GModel::list.size(); i++)
302     names.push_back(GModel::list[i]->getName());
303 }
304 
getCurrent(std::string & name)305 GMSH_API void gmsh::model::getCurrent(std::string &name)
306 {
307   if(!_checkInit()) return;
308   name = GModel::current()->getName();
309 }
310 
setCurrent(const std::string & name)311 GMSH_API void gmsh::model::setCurrent(const std::string &name)
312 {
313   if(!_checkInit()) return;
314   GModel *m = GModel::findByName(name);
315   if(!m) {
316     Msg::Error("Could find model '%s'", name.c_str());
317     return;
318   }
319   GModel::setCurrent(m);
320   for(std::size_t i = 0; i < GModel::list.size(); i++)
321     GModel::list[i]->setVisibility(0);
322   GModel::current()->setVisibility(1);
323   CTX::instance()->mesh.changed = ENT_ALL;
324 }
325 
getFileName(std::string & fileName)326 GMSH_API void gmsh::model::getFileName(std::string &fileName)
327 {
328   if(!_checkInit()) return;
329   fileName = GModel::current()->getFileName();
330 }
331 
setFileName(const std::string & fileName)332 GMSH_API void gmsh::model::setFileName(const std::string &fileName)
333 {
334   if(!_checkInit()) return;
335   GModel::current()->setFileName(fileName);
336 }
337 
getEntities(vectorpair & dimTags,const int dim)338 GMSH_API void gmsh::model::getEntities(vectorpair &dimTags, const int dim)
339 {
340   if(!_checkInit()) return;
341   dimTags.clear();
342   std::vector<GEntity *> entities;
343   GModel::current()->getEntities(entities, dim);
344   for(std::size_t i = 0; i < entities.size(); i++)
345     dimTags.push_back(
346       std::make_pair(entities[i]->dim(), entities[i]->tag()));
347 }
348 
setEntityName(const int dim,const int tag,const std::string & name)349 GMSH_API void gmsh::model::setEntityName(const int dim, const int tag,
350                                          const std::string &name)
351 {
352   if(!_checkInit()) return;
353   GModel::current()->setElementaryName(dim, tag, name);
354 }
355 
getEntityName(const int dim,const int tag,std::string & name)356 GMSH_API void gmsh::model::getEntityName(const int dim, const int tag,
357                                          std::string &name)
358 {
359   if(!_checkInit()) return;
360   name = GModel::current()->getElementaryName(dim, tag);
361 }
362 
getPhysicalGroups(vectorpair & dimTags,const int dim)363 GMSH_API void gmsh::model::getPhysicalGroups(vectorpair &dimTags, const int dim)
364 {
365   if(!_checkInit()) return;
366   dimTags.clear();
367   std::map<int, std::vector<GEntity *> > groups[4];
368   GModel::current()->getPhysicalGroups(groups);
369   for(int d = 0; d < 4; d++) {
370     if(dim < 0 || d == dim) {
371       for(auto it = groups[d].begin(); it != groups[d].end(); it++)
372         dimTags.push_back(std::make_pair(d, it->first));
373     }
374   }
375 }
376 
_getEntityName(int dim,int tag)377 static std::string _getEntityName(int dim, int tag)
378 {
379   std::stringstream stream;
380   switch(dim) {
381   case 0: stream << "Point "; break;
382   case 1: stream << "Curve "; break;
383   case 2: stream << "Surface "; break;
384   case 3: stream << "Volume "; break;
385   }
386   stream << tag;
387   return stream.str();
388 }
389 
getEntitiesForPhysicalGroup(const int dim,const int tag,std::vector<int> & tags)390 GMSH_API void gmsh::model::getEntitiesForPhysicalGroup(const int dim,
391                                                        const int tag,
392                                                        std::vector<int> &tags)
393 {
394   if(!_checkInit()) return;
395   tags.clear();
396   std::map<int, std::vector<GEntity *> > groups;
397   GModel::current()->getPhysicalGroups(dim, groups);
398   auto it = groups.find(tag);
399   if(it != groups.end()) {
400     for(std::size_t j = 0; j < it->second.size(); j++)
401       tags.push_back(it->second[j]->tag());
402   }
403   else {
404     Msg::Error("Physical %s does not exist", _getEntityName(dim, tag).c_str());
405   }
406 }
407 
408 GMSH_API void
getPhysicalGroupsForEntity(const int dim,const int tag,std::vector<int> & physicalTags)409 gmsh::model::getPhysicalGroupsForEntity(const int dim, const int tag,
410                                         std::vector<int> &physicalTags)
411 {
412   if(!_checkInit()) return;
413   physicalTags.clear();
414   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
415   if(!ge) {
416     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
417     return;
418   }
419   std::vector<int> phy = ge->getPhysicalEntities();
420   physicalTags.resize(phy.size());
421   for(std::size_t i = 0; i < phy.size(); i++) { physicalTags[i] = phy[i]; }
422 }
423 
addPhysicalGroup(const int dim,const std::vector<int> & tags,const int tag)424 GMSH_API int gmsh::model::addPhysicalGroup(const int dim,
425                                            const std::vector<int> &tags,
426                                            const int tag)
427 {
428   // FIXME: 1) the "master" physical group definitions are still stored in the
429   // buil-in CAD kernel, so that built-in CAD operations (e.g. Coherence) can
430   // track physical groups; and 2) the synchronization of the built-in CAD
431   // kernel triggers a reset of physical groups in GModel, followed by a
432   // copy. So we currently need to maintain both copies when playing with
433   // physical groups in the api at the model level.
434   if(!_checkInit()) return -1;
435   int outTag = tag;
436   if(outTag < 0) {
437     outTag =
438       std::max(GModel::current()->getMaxPhysicalNumber(dim),
439                GModel::current()->getGEOInternals()->getMaxPhysicalTag()) +
440       1;
441   }
442   if(!GModel::current()->getGEOInternals()->modifyPhysicalGroup(dim, outTag, 0,
443                                                                 tags)) {
444     Msg::Error("Could not add physical group");
445     return -1;
446   }
447   GModel::current()->addPhysicalGroup(dim, outTag, tags);
448   return outTag;
449 }
450 
removePhysicalGroups(const vectorpair & dimTags)451 GMSH_API void gmsh::model::removePhysicalGroups(const vectorpair &dimTags)
452 {
453   if(!_checkInit()) return;
454   if(dimTags.empty()) {
455     GModel::current()->getGEOInternals()->resetPhysicalGroups();
456     GModel::current()->removePhysicalGroups();
457   }
458   else {
459     // FIXME: rewrite the unerlying code: it's slow
460     for(std::size_t i = 0; i < dimTags.size(); i++) {
461       std::vector<int> tags; // empty to delete the group
462       GModel::current()->getGEOInternals()->modifyPhysicalGroup(
463         dimTags[i].first, dimTags[i].second, 2, tags);
464       GModel::current()->removePhysicalGroup(dimTags[i].first,
465                                              dimTags[i].second);
466     }
467   }
468 }
469 
setPhysicalName(const int dim,const int tag,const std::string & name)470 GMSH_API void gmsh::model::setPhysicalName(const int dim, const int tag,
471                                            const std::string &name)
472 {
473   if(!_checkInit()) return;
474   GModel::current()->setPhysicalName(name, dim, tag);
475 }
476 
removePhysicalName(const std::string & name)477 GMSH_API void gmsh::model::removePhysicalName(const std::string &name)
478 {
479   if(!_checkInit()) return;
480   GModel::current()->removePhysicalName(name);
481 }
482 
getPhysicalName(const int dim,const int tag,std::string & name)483 GMSH_API void gmsh::model::getPhysicalName(const int dim, const int tag,
484                                            std::string &name)
485 {
486   if(!_checkInit()) return;
487   name = GModel::current()->getPhysicalName(dim, tag);
488 }
489 
setTag(const int dim,const int tag,const int newTag)490 GMSH_API void gmsh::model::setTag(const int dim, const int tag, const int newTag)
491 {
492   if(!_checkInit()) return;
493   GModel::current()->changeEntityTag(dim, tag, newTag);
494 }
495 
getBoundary(const vectorpair & dimTags,vectorpair & outDimTags,const bool combined,const bool oriented,const bool recursive)496 GMSH_API void gmsh::model::getBoundary(const vectorpair &dimTags,
497                                        vectorpair &outDimTags,
498                                        const bool combined, const bool oriented,
499                                        const bool recursive)
500 {
501   if(!_checkInit()) return;
502   outDimTags.clear();
503   if(!GModel::current()->getBoundaryTags(dimTags, outDimTags, combined,
504                                          oriented, recursive)) {
505     Msg::Error("Could not get boundary");
506   }
507 }
508 
getAdjacencies(const int dim,const int tag,std::vector<int> & upward,std::vector<int> & downward)509 GMSH_API void gmsh::model::getAdjacencies(const int dim, const int tag,
510                                           std::vector<int> &upward,
511                                           std::vector<int> &downward)
512 {
513   if(!_checkInit()) return;
514   upward.clear();
515   downward.clear();
516   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
517   if(!ge) {
518     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
519     return;
520   }
521   switch(dim) {
522   case 0:
523     for(auto &e : static_cast<GVertex *>(ge)->edges())
524       upward.push_back(e->tag());
525     break;
526   case 1:
527     for(auto &e : static_cast<GEdge *>(ge)->faces()) upward.push_back(e->tag());
528     for(auto &e : static_cast<GEdge *>(ge)->vertices())
529       downward.push_back(e->tag());
530     break;
531   case 2:
532     for(auto &e : static_cast<GFace *>(ge)->regions())
533       upward.push_back(e->tag());
534     for(auto &e : static_cast<GFace *>(ge)->edges())
535       downward.push_back(e->tag());
536     break;
537   case 3:
538     for(auto &e : static_cast<GRegion *>(ge)->faces())
539       downward.push_back(e->tag());
540     break;
541   }
542 }
543 
getEntitiesInBoundingBox(const double xmin,const double ymin,const double zmin,const double xmax,const double ymax,const double zmax,vectorpair & dimTags,const int dim)544 GMSH_API void gmsh::model::getEntitiesInBoundingBox(
545   const double xmin, const double ymin, const double zmin, const double xmax,
546   const double ymax, const double zmax, vectorpair &dimTags, const int dim)
547 {
548   if(!_checkInit()) return;
549   dimTags.clear();
550   SBoundingBox3d box(xmin, ymin, zmin, xmax, ymax, zmax);
551   std::vector<GEntity *> entities;
552   GModel::current()->getEntitiesInBox(entities, box, dim);
553   for(std::size_t i = 0; i < entities.size(); i++)
554     dimTags.push_back(
555       std::make_pair(entities[i]->dim(), entities[i]->tag()));
556 }
557 
getBoundingBox(const int dim,const int tag,double & xmin,double & ymin,double & zmin,double & xmax,double & ymax,double & zmax)558 GMSH_API void gmsh::model::getBoundingBox(const int dim, const int tag,
559                                           double &xmin, double &ymin,
560                                           double &zmin, double &xmax,
561                                           double &ymax, double &zmax)
562 {
563   if(!_checkInit()) return;
564 
565   SBoundingBox3d box;
566   if(dim < 0 && tag < 0) {
567     box = GModel::current()->bounds();
568     if(box.empty()) {
569       Msg::Error("Empty bounding box");
570       return;
571     }
572   }
573   else {
574     GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
575     if(!ge) {
576       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
577       return;
578     }
579     box = ge->bounds();
580   }
581   if(box.empty()) {
582     Msg::Error("Empty bounding box");
583     return;
584   }
585   xmin = box.min().x();
586   ymin = box.min().y();
587   zmin = box.min().z();
588   xmax = box.max().x();
589   ymax = box.max().y();
590   zmax = box.max().z();
591 }
592 
getDimension()593 GMSH_API int gmsh::model::getDimension()
594 {
595   if(!_checkInit()) return -1;
596   return GModel::current()->getDim();
597 }
598 
addDiscreteEntity(const int dim,const int tag,const std::vector<int> & boundary)599 GMSH_API int gmsh::model::addDiscreteEntity(const int dim, const int tag,
600                                             const std::vector<int> &boundary)
601 {
602   if(!_checkInit()) return -1;
603   int outTag = tag;
604   if(outTag < 0) {
605     outTag = GModel::current()->getMaxElementaryNumber(dim) + 1;
606   }
607   GEntity *e = GModel::current()->getEntityByTag(dim, outTag);
608   if(e) {
609     Msg::Error("%s already exists", _getEntityName(dim, outTag).c_str());
610     return -1;
611   }
612   switch(dim) {
613   case 0: {
614     discreteVertex *gv = new discreteVertex(GModel::current(), outTag);
615     GModel::current()->add(gv);
616     break;
617   }
618   case 1: {
619     GVertex *v0 = nullptr, *v1 = nullptr;
620     if(boundary.size() >= 1)
621       v0 = GModel::current()->getVertexByTag(boundary[0]);
622     if(boundary.size() >= 2)
623       v1 = GModel::current()->getVertexByTag(boundary[1]);
624     discreteEdge *ge = new discreteEdge(GModel::current(), outTag, v0, v1);
625     GModel::current()->add(ge);
626     break;
627   }
628   case 2: {
629     discreteFace *gf = new discreteFace(GModel::current(), outTag);
630     std::vector<int> tagEdges, signEdges;
631     for(std::size_t i = 0; i < boundary.size(); i++) {
632       tagEdges.push_back(std::abs(boundary[i]));
633       signEdges.push_back(gmsh_sign(boundary[i]));
634     }
635     if(!tagEdges.empty()) gf->setBoundEdges(tagEdges, signEdges);
636     GModel::current()->add(gf);
637     break;
638   }
639   case 3: {
640     discreteRegion *gr = new discreteRegion(GModel::current(), outTag);
641     std::vector<int> tagFaces, signFaces;
642     for(std::size_t i = 0; i < boundary.size(); i++) {
643       tagFaces.push_back(std::abs(boundary[i]));
644       signFaces.push_back(gmsh_sign(boundary[i]));
645     }
646     if(!tagFaces.empty()) gr->setBoundFaces(tagFaces, signFaces);
647     GModel::current()->add(gr);
648     break;
649   }
650   }
651   return outTag;
652 }
653 
removeEntities(const vectorpair & dimTags,const bool recursive)654 GMSH_API void gmsh::model::removeEntities(const vectorpair &dimTags,
655                                           const bool recursive)
656 {
657   if(!_checkInit()) return;
658   std::vector<GEntity*> removed;
659   GModel::current()->remove(dimTags, removed, recursive);
660   Msg::Debug("Destroying %lu entities in model", removed.size());
661   for(std::size_t i = 0; i < removed.size(); i++) delete removed[i];
662 }
663 
removeEntityName(const std::string & name)664 GMSH_API void gmsh::model::removeEntityName(const std::string &name)
665 {
666   if(!_checkInit()) return;
667   GModel::current()->removeElementaryName(name);
668 }
669 
getType(const int dim,const int tag,std::string & entityType)670 GMSH_API void gmsh::model::getType(const int dim, const int tag,
671                                    std::string &entityType)
672 {
673   if(!_checkInit()) return;
674   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
675   if(!ge) {
676     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
677     return;
678   }
679   entityType = ge->getTypeString();
680 }
681 
getParent(const int dim,const int tag,int & parentDim,int & parentTag)682 GMSH_API void gmsh::model::getParent(const int dim, const int tag,
683                                      int &parentDim, int &parentTag)
684 {
685   if(!_checkInit()) return;
686   parentDim = -1;
687   parentTag = -1;
688   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
689   if(!ge) {
690     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
691     return;
692   }
693   GEntity *parent = ge->getParentEntity();
694   if(parent) {
695     parentDim = parent->dim();
696     parentTag = parent->tag();
697   }
698 }
699 
getPartitions(const int dim,const int tag,std::vector<int> & partitions)700 GMSH_API void gmsh::model::getPartitions(const int dim, const int tag,
701                                          std::vector<int> &partitions)
702 {
703   if(!_checkInit()) return;
704   partitions.clear();
705   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
706   if(!ge) {
707     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
708     return;
709   }
710   std::vector<int> p;
711   if(ge->geomType() == GEntity::PartitionPoint)
712     p = static_cast<partitionVertex *>(ge)->getPartitions();
713   else if(ge->geomType() == GEntity::PartitionCurve)
714     p = static_cast<partitionEdge *>(ge)->getPartitions();
715   else if(ge->geomType() == GEntity::PartitionSurface)
716     p = static_cast<partitionFace *>(ge)->getPartitions();
717   else if(ge->geomType() == GEntity::PartitionVolume)
718     p = static_cast<partitionRegion *>(ge)->getPartitions();
719   else if(ge->geomType() == GEntity::GhostCurve)
720     p.push_back(static_cast<ghostEdge *>(ge)->getPartition());
721   else if(ge->geomType() == GEntity::GhostSurface)
722     p.push_back(static_cast<ghostFace *>(ge)->getPartition());
723   else if(ge->geomType() == GEntity::GhostVolume)
724     p.push_back(static_cast<ghostRegion *>(ge)->getPartition());
725 
726   for(std::size_t i = 0; i < p.size(); i++) partitions.push_back(p[i]);
727 }
728 
getNumberOfPartitions()729 GMSH_API int gmsh::model::getNumberOfPartitions()
730 {
731   if(!_checkInit()) return 0;
732   return GModel::current()->getNumPartitions();
733 }
734 
getValue(const int dim,const int tag,const std::vector<double> & parametricCoord,std::vector<double> & coord)735 GMSH_API void gmsh::model::getValue(const int dim, const int tag,
736                                     const std::vector<double> &parametricCoord,
737                                     std::vector<double> &coord)
738 {
739   if(!_checkInit()) return;
740   coord.clear();
741   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
742   if(!entity) {
743     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
744     return;
745   }
746   if(dim == 0) {
747     coord.push_back(static_cast<GVertex *>(entity)->x());
748     coord.push_back(static_cast<GVertex *>(entity)->y());
749     coord.push_back(static_cast<GVertex *>(entity)->z());
750   }
751   else if(dim == 1) {
752     GEdge *ge = static_cast<GEdge *>(entity);
753     for(std::size_t i = 0; i < parametricCoord.size(); i++) {
754       GPoint gp = ge->point(parametricCoord[i]);
755       coord.push_back(gp.x());
756       coord.push_back(gp.y());
757       coord.push_back(gp.z());
758     }
759   }
760   else if(dim == 2) {
761     if(parametricCoord.size() % 2) {
762       Msg::Error("Number of parametric coordinates should be even");
763       return;
764     }
765     GFace *gf = static_cast<GFace *>(entity);
766     for(std::size_t i = 0; i < parametricCoord.size(); i += 2) {
767       SPoint2 param(parametricCoord[i], parametricCoord[i + 1]);
768       GPoint gp = gf->point(param);
769       coord.push_back(gp.x());
770       coord.push_back(gp.y());
771       coord.push_back(gp.z());
772     }
773   }
774 }
775 
776 GMSH_API void
getDerivative(const int dim,const int tag,const std::vector<double> & parametricCoord,std::vector<double> & deriv)777 gmsh::model::getDerivative(const int dim, const int tag,
778                            const std::vector<double> &parametricCoord,
779                            std::vector<double> &deriv)
780 {
781   if(!_checkInit()) return;
782   deriv.clear();
783   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
784   if(!entity) {
785     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
786     return;
787   }
788   if(dim == 1) {
789     GEdge *ge = static_cast<GEdge *>(entity);
790     for(std::size_t i = 0; i < parametricCoord.size(); i++) {
791       SVector3 d = ge->firstDer(parametricCoord[i]);
792       deriv.push_back(d.x());
793       deriv.push_back(d.y());
794       deriv.push_back(d.z());
795     }
796   }
797   else if(dim == 2) {
798     if(parametricCoord.size() % 2) {
799       Msg::Error("Number of parametric coordinates should be even");
800       return;
801     }
802     GFace *gf = static_cast<GFace *>(entity);
803     for(std::size_t i = 0; i < parametricCoord.size(); i += 2) {
804       SPoint2 param(parametricCoord[i], parametricCoord[i + 1]);
805       Pair<SVector3, SVector3> d = gf->firstDer(param);
806       deriv.push_back(d.left().x());
807       deriv.push_back(d.left().y());
808       deriv.push_back(d.left().z());
809       deriv.push_back(d.right().x());
810       deriv.push_back(d.right().y());
811       deriv.push_back(d.right().z());
812     }
813   }
814 }
815 
816 GMSH_API void
getSecondDerivative(const int dim,const int tag,const std::vector<double> & parametricCoord,std::vector<double> & deriv)817 gmsh::model::getSecondDerivative(const int dim, const int tag,
818                                  const std::vector<double> &parametricCoord,
819                                  std::vector<double> &deriv)
820 {
821   if(!_checkInit()) return;
822   deriv.clear();
823   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
824   if(!entity) {
825     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
826     return;
827   }
828   if(dim == 1) {
829     GEdge *ge = static_cast<GEdge *>(entity);
830     for(std::size_t i = 0; i < parametricCoord.size(); i++) {
831       SVector3 d = ge->secondDer(parametricCoord[i]);
832       deriv.push_back(d.x());
833       deriv.push_back(d.y());
834       deriv.push_back(d.z());
835     }
836   }
837   else if(dim == 2) {
838     if(parametricCoord.size() % 2) {
839       Msg::Error("Number of parametric coordinates should be even");
840       return;
841     }
842     GFace *gf = static_cast<GFace *>(entity);
843     for(std::size_t i = 0; i < parametricCoord.size(); i += 2) {
844       SPoint2 param(parametricCoord[i], parametricCoord[i + 1]);
845       SVector3 dudu, dvdv, dudv;
846       gf->secondDer(param, dudu, dvdv, dudv);
847       deriv.push_back(dudu.x());
848       deriv.push_back(dudu.y());
849       deriv.push_back(dudu.z());
850       deriv.push_back(dvdv.x());
851       deriv.push_back(dvdv.y());
852       deriv.push_back(dvdv.z());
853       deriv.push_back(dudv.x());
854       deriv.push_back(dudv.y());
855       deriv.push_back(dudv.z());
856     }
857   }
858 }
859 
860 GMSH_API void
getCurvature(const int dim,const int tag,const std::vector<double> & parametricCoord,std::vector<double> & curvatures)861 gmsh::model::getCurvature(const int dim, const int tag,
862                           const std::vector<double> &parametricCoord,
863                           std::vector<double> &curvatures)
864 {
865   if(!_checkInit()) return;
866   curvatures.clear();
867   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
868   if(!entity) {
869     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
870     return;
871   }
872   if(dim == 1) {
873     GEdge *ge = static_cast<GEdge *>(entity);
874     for(std::size_t i = 0; i < parametricCoord.size(); i++)
875       curvatures.push_back(ge->curvature(parametricCoord[i]));
876   }
877   else if(dim == 2) {
878     if(parametricCoord.size() % 2) {
879       Msg::Error("Number of parametric coordinates should be even");
880       return;
881     }
882     GFace *gf = static_cast<GFace *>(entity);
883     for(std::size_t i = 0; i < parametricCoord.size(); i += 2) {
884       SPoint2 param(parametricCoord[i], parametricCoord[i + 1]);
885       curvatures.push_back(gf->curvatureMax(param));
886     }
887   }
888 }
889 
getPrincipalCurvatures(const int tag,const std::vector<double> & parametricCoord,std::vector<double> & curvaturesMax,std::vector<double> & curvaturesMin,std::vector<double> & directionsMax,std::vector<double> & directionsMin)890 GMSH_API void gmsh::model::getPrincipalCurvatures(
891   const int tag, const std::vector<double> &parametricCoord,
892   std::vector<double> &curvaturesMax, std::vector<double> &curvaturesMin,
893   std::vector<double> &directionsMax, std::vector<double> &directionsMin)
894 {
895   if(!_checkInit()) return;
896   GFace *gf = GModel::current()->getFaceByTag(tag);
897   if(!gf) {
898     Msg::Error("%s does not exist", _getEntityName(2, tag).c_str());
899     return;
900   }
901   curvaturesMax.clear();
902   curvaturesMin.clear();
903   directionsMax.clear();
904   directionsMin.clear();
905   if(parametricCoord.size() % 2) {
906     Msg::Error("Number of parametric coordinates should be even");
907     return;
908   }
909   for(std::size_t i = 0; i < parametricCoord.size(); i += 2) {
910     SPoint2 param(parametricCoord[i], parametricCoord[i + 1]);
911     double cmin, cmax;
912     SVector3 dmin, dmax;
913     gf->curvatures(param, dmax, dmin, cmax, cmin);
914     curvaturesMax.push_back(cmax);
915     curvaturesMin.push_back(cmin);
916     directionsMax.push_back(dmax.x());
917     directionsMax.push_back(dmax.y());
918     directionsMax.push_back(dmax.z());
919     directionsMin.push_back(dmin.x());
920     directionsMin.push_back(dmin.y());
921     directionsMin.push_back(dmin.z());
922   }
923 }
924 
getNormal(const int tag,const std::vector<double> & parametricCoord,std::vector<double> & normals)925 GMSH_API void gmsh::model::getNormal(const int tag,
926                                      const std::vector<double> &parametricCoord,
927                                      std::vector<double> &normals)
928 {
929   if(!_checkInit()) return;
930   GFace *gf = GModel::current()->getFaceByTag(tag);
931   if(!gf) {
932     Msg::Error("%s does not exist", _getEntityName(2, tag).c_str());
933     return;
934   }
935   normals.clear();
936   if(parametricCoord.size() % 2) {
937     Msg::Error("Number of parametric coordinates should be even");
938     return;
939   }
940   for(std::size_t i = 0; i < parametricCoord.size(); i += 2) {
941     SPoint2 param(parametricCoord[i], parametricCoord[i + 1]);
942     SVector3 n = gf->normal(param);
943     normals.push_back(n.x());
944     normals.push_back(n.y());
945     normals.push_back(n.z());
946   }
947 }
948 
949 GMSH_API void
getParametrization(const int dim,const int tag,const std::vector<double> & coord,std::vector<double> & parametricCoord)950 gmsh::model::getParametrization(const int dim, const int tag,
951                                 const std::vector<double> &coord,
952                                 std::vector<double> &parametricCoord)
953 {
954   if(!_checkInit()) return;
955   parametricCoord.clear();
956   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
957   if(!entity) {
958     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
959     return;
960   }
961   if(coord.size() % 3) {
962     Msg::Error("Number of coordinates should be a multiple of 3");
963     return;
964   }
965   if(dim == 1) {
966     GEdge *ge = static_cast<GEdge *>(entity);
967     for(std::size_t i = 0; i < coord.size(); i += 3) {
968       SPoint3 p(coord[i], coord[i + 1], coord[i + 2]);
969       double t = ge->parFromPoint(p);
970       parametricCoord.push_back(t);
971     }
972   }
973   else if(dim == 2) {
974     GFace *gf = static_cast<GFace *>(entity);
975     for(std::size_t i = 0; i < coord.size(); i += 3) {
976       SPoint3 p(coord[i], coord[i + 1], coord[i + 2]);
977       SPoint2 uv = gf->parFromPoint(p, true, true);
978       parametricCoord.push_back(uv.x());
979       parametricCoord.push_back(uv.y());
980     }
981   }
982 }
983 
getParametrizationBounds(const int dim,const int tag,std::vector<double> & min,std::vector<double> & max)984 GMSH_API void gmsh::model::getParametrizationBounds(const int dim,
985                                                     const int tag,
986                                                     std::vector<double> &min,
987                                                     std::vector<double> &max)
988 {
989   if(!_checkInit()) return;
990   min.clear();
991   max.clear();
992   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
993   if(!entity) {
994     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
995     return;
996   }
997   for(int dim = 0; dim < entity->dim(); dim++) {
998     Range<double> r = entity->parBounds(dim);
999     min.push_back(r.low());
1000     max.push_back(r.high());
1001   }
1002 }
1003 
isInside(const int dim,const int tag,const std::vector<double> & coord,const bool parametric)1004 GMSH_API int gmsh::model::isInside(const int dim, const int tag,
1005                                    const std::vector<double> &coord,
1006                                    const bool parametric)
1007 {
1008   if(!_checkInit()) return -1;
1009   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
1010   if(!entity) {
1011     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1012     return 0;
1013   }
1014   int num = 0;
1015   if(parametric) {
1016     if(dim == 1) {
1017       GEdge *ge = static_cast<GEdge *>(entity);
1018       for(std::size_t i = 0; i < coord.size(); i++) {
1019         if(ge->containsParam(coord[i])) num++;
1020       }
1021     }
1022     else if(dim == 2) {
1023       GFace *gf = static_cast<GFace *>(entity);
1024       if(coord.size() % 2) {
1025         Msg::Error("Number of parametric coordinates should be even");
1026         return num;
1027       }
1028       for(std::size_t i = 0; i < coord.size(); i += 2) {
1029         SPoint2 param(coord[i], coord[i + 1]);
1030         if(gf->containsParam(param)) num++;
1031       }
1032     }
1033   }
1034   else {
1035     if(coord.size() % 3) {
1036       Msg::Error("Number of coordinates should be a multiple of 3");
1037       return 0;
1038     }
1039     for(std::size_t i = 0; i < coord.size(); i += 3) {
1040       SPoint3 pt(coord[i], coord[i + 1], coord[i + 2]);
1041       if(entity->containsPoint(pt)) num++;
1042     }
1043   }
1044   return num;
1045 }
1046 
reparametrizeOnSurface(const int dim,const int tag,const std::vector<double> & parametricCoord,const int surfaceTag,std::vector<double> & surfaceParametricCoord,const int which)1047 GMSH_API void gmsh::model::reparametrizeOnSurface(
1048   const int dim, const int tag, const std::vector<double> &parametricCoord,
1049   const int surfaceTag, std::vector<double> &surfaceParametricCoord,
1050   const int which)
1051 {
1052   if(!_checkInit()) return;
1053   surfaceParametricCoord.clear();
1054   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
1055   if(!entity) {
1056     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1057     return;
1058   }
1059   GFace *gf = GModel::current()->getFaceByTag(surfaceTag);
1060   if(!gf) {
1061     Msg::Error("%s does not exist", _getEntityName(2, surfaceTag).c_str());
1062     return;
1063   }
1064   if(dim == 0) {
1065     GVertex *gv = static_cast<GVertex *>(entity);
1066     SPoint2 p = gv->reparamOnFace(gf, which);
1067     surfaceParametricCoord.push_back(p.x());
1068     surfaceParametricCoord.push_back(p.y());
1069   }
1070   else if(dim == 1) {
1071     GEdge *ge = static_cast<GEdge *>(entity);
1072     for(std::size_t i = 0; i < parametricCoord.size(); i++) {
1073       SPoint2 p = ge->reparamOnFace(gf, parametricCoord[i], which);
1074       surfaceParametricCoord.push_back(p.x());
1075       surfaceParametricCoord.push_back(p.y());
1076     }
1077   }
1078 }
1079 
getClosestPoint(const int dim,const int tag,const std::vector<double> & coord,std::vector<double> & closestCoord,std::vector<double> & parametricCoord)1080 GMSH_API void gmsh::model::getClosestPoint(const int dim, const int tag,
1081                                            const std::vector<double> &coord,
1082                                            std::vector<double> &closestCoord,
1083                                            std::vector<double> &parametricCoord)
1084 {
1085   if(!_checkInit()) return;
1086   closestCoord.clear();
1087   parametricCoord.clear();
1088   GEntity *entity = GModel::current()->getEntityByTag(dim, tag);
1089   if(!entity) {
1090     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1091     return;
1092   }
1093   if(coord.size() % 3) {
1094     Msg::Error("Number of coordinates should be a multiple of 3");
1095     return;
1096   }
1097   if(dim == 1) {
1098     GEdge *ge = static_cast<GEdge *>(entity);
1099     for(std::size_t i = 0; i < coord.size(); i += 3) {
1100       SPoint3 p(coord[i], coord[i + 1], coord[i + 2]);
1101       double t;
1102       GPoint pp = ge->closestPoint(p, t);
1103       closestCoord.push_back(pp.x());
1104       closestCoord.push_back(pp.y());
1105       closestCoord.push_back(pp.z());
1106       parametricCoord.push_back(t);
1107     }
1108   }
1109   else if(dim == 2) {
1110     GFace *gf = static_cast<GFace *>(entity);
1111     for(std::size_t i = 0; i < coord.size(); i += 3) {
1112       SPoint3 p(coord[i], coord[i + 1], coord[i + 2]);
1113       double uv[2] = {0, 0};
1114       GPoint pp = gf->closestPoint(p, uv);
1115       closestCoord.push_back(pp.x());
1116       closestCoord.push_back(pp.y());
1117       closestCoord.push_back(pp.z());
1118       parametricCoord.push_back(uv[0]);
1119       parametricCoord.push_back(uv[1]);
1120     }
1121   }
1122 }
1123 
setVisibility(const vectorpair & dimTags,const int value,const bool recursive)1124 GMSH_API void gmsh::model::setVisibility(const vectorpair &dimTags,
1125                                          const int value, const bool recursive)
1126 {
1127   if(!_checkInit()) return;
1128   for(std::size_t i = 0; i < dimTags.size(); i++) {
1129     GEntity *ge = GModel::current()->getEntityByTag(
1130       dimTags[i].first, std::abs(dimTags[i].second));
1131     if(ge) ge->setVisibility(value, recursive);
1132   }
1133 }
1134 
getVisibility(const int dim,const int tag,int & value)1135 GMSH_API void gmsh::model::getVisibility(const int dim, const int tag,
1136                                          int &value)
1137 {
1138   if(!_checkInit()) return;
1139   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1140   if(!ge) {
1141     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1142     return;
1143   }
1144   value = ge->getVisibility();
1145 }
1146 
setVisibilityPerWindow(const int value,const int windowIndex)1147 GMSH_API void gmsh::model::setVisibilityPerWindow(const int value,
1148                                                   const int windowIndex)
1149 {
1150   if(!_checkInit()) return;
1151 #if defined(HAVE_FLTK)
1152   FlGui::instance()->setCurrentOpenglWindow(windowIndex);
1153   drawContext *ctx = FlGui::instance()->getCurrentDrawContext();
1154   GModel *m = GModel::current();
1155   if(value)
1156     ctx->show(m);
1157   else
1158     ctx->hide(m);
1159 #endif
1160 }
1161 
setColor(const vectorpair & dimTags,const int r,const int g,const int b,const int a,const bool recursive)1162 GMSH_API void gmsh::model::setColor(const vectorpair &dimTags, const int r,
1163                                     const int g, const int b, const int a,
1164                                     const bool recursive)
1165 {
1166   if(!_checkInit()) return;
1167   for(std::size_t i = 0; i < dimTags.size(); i++) {
1168     GEntity *ge = GModel::current()->getEntityByTag(
1169       dimTags[i].first, std::abs(dimTags[i].second));
1170     if(ge) {
1171       unsigned int val = CTX::instance()->packColor(r, g, b, a);
1172       ge->setColor(val, recursive);
1173     }
1174   }
1175 }
1176 
getColor(const int dim,const int tag,int & r,int & g,int & b,int & a)1177 GMSH_API void gmsh::model::getColor(const int dim, const int tag, int &r,
1178                                     int &g, int &b, int &a)
1179 {
1180   if(!_checkInit()) return;
1181   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1182   if(!ge) {
1183     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1184     return;
1185   }
1186   unsigned int value = ge->getColor();
1187   r = CTX::instance()->unpackRed(value);
1188   g = CTX::instance()->unpackGreen(value);
1189   b = CTX::instance()->unpackBlue(value);
1190   a = CTX::instance()->unpackAlpha(value);
1191 }
1192 
setCoordinates(const int tag,const double x,const double y,const double z)1193 GMSH_API void gmsh::model::setCoordinates(const int tag, const double x,
1194                                           const double y, const double z)
1195 {
1196   if(!_checkInit()) return;
1197   GVertex *gv = GModel::current()->getVertexByTag(tag);
1198   if(!gv) {
1199     Msg::Error("%s does not exist", _getEntityName(0, tag).c_str());
1200     return;
1201   }
1202   GPoint p(x, y, z);
1203   gv->setPosition(p);
1204 }
1205 
1206 // gmsh::model::mesh
1207 
generate(const int dim)1208 GMSH_API void gmsh::model::mesh::generate(const int dim)
1209 {
1210   if(!_checkInit()) return;
1211   GModel::current()->mesh(dim);
1212   CTX::instance()->mesh.changed = ENT_ALL;
1213 }
1214 
1215 GMSH_API void
partition(const int numPart,const std::vector<std::size_t> & elementTags,const std::vector<int> & partitions)1216 gmsh::model::mesh::partition(const int numPart,
1217                              const std::vector<std::size_t> &elementTags,
1218                              const std::vector<int> &partitions)
1219 {
1220   if(!_checkInit()) return;
1221   std::vector<std::pair<MElement *, int> > epart;
1222   if(elementTags.size()) {
1223     if(elementTags.size() != partitions.size()) {
1224       Msg::Error("Number of element tags (%d) does not match number of "
1225                  "partitions (%d)",
1226                  elementTags.size(), partitions.size());
1227       return;
1228     }
1229     epart.reserve(elementTags.size());
1230     for(std::size_t i = 0; i < elementTags.size(); i++) {
1231       MElement *el = GModel::current()->getMeshElementByTag(elementTags[i]);
1232       if(el)
1233         epart.push_back(std::make_pair(el, partitions[i]));
1234       else
1235         Msg::Error("Unknown element %d", elementTags[i]);
1236     }
1237   }
1238   GModel::current()->partitionMesh(
1239     numPart >= 0 ? numPart : CTX::instance()->mesh.numPartitions, epart);
1240   CTX::instance()->mesh.changed = ENT_ALL;
1241 }
1242 
unpartition()1243 GMSH_API void gmsh::model::mesh::unpartition()
1244 {
1245   if(!_checkInit()) return;
1246   GModel::current()->unpartitionMesh();
1247   CTX::instance()->mesh.changed = ENT_ALL;
1248 }
1249 
refine()1250 GMSH_API void gmsh::model::mesh::refine()
1251 {
1252   if(!_checkInit()) return;
1253   GModel::current()->refineMesh(CTX::instance()->mesh.secondOrderLinear,
1254                                 CTX::instance()->mesh.algoSubdivide == 1,
1255                                 CTX::instance()->mesh.algoSubdivide == 2,
1256                                 CTX::instance()->mesh.algoSubdivide == 3);
1257   CTX::instance()->mesh.changed = ENT_ALL;
1258 }
1259 
recombine()1260 GMSH_API void gmsh::model::mesh::recombine()
1261 {
1262   if(!_checkInit()) return;
1263   GModel::current()->recombineMesh();
1264   CTX::instance()->mesh.changed = ENT_ALL;
1265 }
1266 
optimize(const std::string & how,const bool force,const int niter,const vectorpair & dimTags)1267 GMSH_API void gmsh::model::mesh::optimize(const std::string &how,
1268                                           const bool force, const int niter,
1269                                           const vectorpair &dimTags)
1270 {
1271   if(!_checkInit()) return;
1272   if(dimTags.size()) {
1273     Msg::Warning(
1274       "Optimization of specified model entities is not interfaced yet");
1275   }
1276   GModel::current()->optimizeMesh(how, force, niter);
1277   CTX::instance()->mesh.changed = ENT_ALL;
1278 }
1279 
computeCrossField(std::vector<int> & tags)1280 GMSH_API void gmsh::model::mesh::computeCrossField(std::vector<int> &tags)
1281 {
1282   if(!_checkInit()) return;
1283 #if defined(HAVE_MESH)
1284   if(computeCrossField(GModel::current(), tags)) {
1285     Msg::Error("Could not compute cross field");
1286     return;
1287   }
1288 #else
1289   Msg::Error("computeCrossField requires the mesh module");
1290 #endif
1291 }
1292 
splitQuadrangles(const double quality,const int tag)1293 GMSH_API void gmsh::model::mesh::splitQuadrangles(const double quality,
1294                                                   const int tag)
1295 {
1296   if(!_checkInit()) return;
1297 #if defined(HAVE_MESH)
1298   std::vector<GEntity *> entities;
1299   if(tag < 0) { GModel::current()->getEntities(entities, 2); }
1300   else {
1301     GEntity *ge = GModel::current()->getEntityByTag(2, tag);
1302     if(!ge) {
1303       Msg::Error("%s does not exist", _getEntityName(2, tag).c_str());
1304       return;
1305     }
1306     entities.push_back(ge);
1307   }
1308   for(std::size_t i = 0; i < entities.size(); i++) {
1309     GFace *gf = static_cast<GFace *>(entities[i]);
1310     quadsToTriangles(gf, quality);
1311   }
1312   CTX::instance()->mesh.changed = ENT_ALL;
1313 #else
1314   Msg::Error("splitQuadrangles requires the mesh module");
1315 #endif
1316 }
1317 
setOrder(const int order)1318 GMSH_API void gmsh::model::mesh::setOrder(const int order)
1319 {
1320   if(!_checkInit()) return;
1321   GModel::current()->setOrderN(order, CTX::instance()->mesh.secondOrderLinear,
1322                                CTX::instance()->mesh.secondOrderIncomplete);
1323   CTX::instance()->mesh.changed = ENT_ALL;
1324 }
1325 
getLastEntityError(vectorpair & dimTags)1326 GMSH_API void gmsh::model::mesh::getLastEntityError(vectorpair &dimTags)
1327 {
1328   if(!_checkInit()) return;
1329   std::vector<GEntity *> e = GModel::current()->getLastMeshEntityError();
1330   dimTags.clear();
1331   for(std::size_t i = 0; i < e.size(); i++)
1332     dimTags.push_back(std::make_pair(e[i]->dim(), e[i]->tag()));
1333 }
1334 
1335 GMSH_API void
getLastNodeError(std::vector<std::size_t> & nodeTags)1336 gmsh::model::mesh::getLastNodeError(std::vector<std::size_t> &nodeTags)
1337 {
1338   if(!_checkInit()) return;
1339   std::vector<MVertex *> v = GModel::current()->getLastMeshVertexError();
1340   nodeTags.clear();
1341   for(std::size_t i = 0; i < v.size(); i++) nodeTags.push_back(v[i]->getNum());
1342 }
1343 
clear(const vectorpair & dimTags)1344 GMSH_API void gmsh::model::mesh::clear(const vectorpair &dimTags)
1345 {
1346   if(!_checkInit()) return;
1347   std::vector<GEntity *> entities;
1348   for(std::size_t i = 0; i < dimTags.size(); i++) {
1349     int dim = dimTags[i].first;
1350     int tag = dimTags[i].second;
1351     GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1352     if(!ge) {
1353       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1354       return;
1355     }
1356     entities.push_back(ge);
1357   }
1358   GModel::current()->deleteMesh(entities);
1359 }
1360 
_getEntities(const gmsh::vectorpair & dimTags,std::vector<GEntity * > & entities)1361 static void _getEntities(const gmsh::vectorpair &dimTags,
1362                          std::vector<GEntity *> &entities)
1363 {
1364   if(dimTags.empty()) { GModel::current()->getEntities(entities); }
1365   else {
1366     for(auto dimTag : dimTags) {
1367       int dim = dimTag.first, tag = dimTag.second;
1368       GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1369       if(!ge) {
1370         Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1371         return;
1372       }
1373       entities.push_back(ge);
1374     }
1375   }
1376 }
1377 
reverse(const vectorpair & dimTags)1378 GMSH_API void gmsh::model::mesh::reverse(const vectorpair &dimTags)
1379 {
1380   if(!_checkInit()) return;
1381   std::vector<GEntity *> entities;
1382   _getEntities(dimTags, entities);
1383   for(auto ge : entities) {
1384     for(std::size_t j = 0; j < ge->getNumMeshElements(); j++) {
1385       ge->getMeshElement(j)->reverse();
1386     }
1387   }
1388   GModel::current()->destroyMeshCaches();
1389 }
1390 
1391 GMSH_API void
affineTransform(const std::vector<double> & affineTransform,const vectorpair & dimTags)1392 gmsh::model::mesh::affineTransform(const std::vector<double> &affineTransform,
1393                                    const vectorpair &dimTags)
1394 {
1395   if(!_checkInit()) return;
1396   std::vector<GEntity *> entities;
1397   _getEntities(dimTags, entities);
1398   for(auto ge : entities) {
1399     for(std::size_t j = 0; j < ge->getNumMeshVertices(); j++) {
1400       MVertex *v = ge->getMeshVertex(j);
1401       SPoint3 pt = v->point();
1402       if(pt.transform(affineTransform))
1403         v->setXYZ(pt);
1404       else
1405         Msg::Error("Could not transform node %d (%g, %g, %g) on %s",
1406                    v->getNum(), v->x(), v->y(), v->z(),
1407                    _getEntityName(ge->dim(), ge->tag()).c_str());
1408     }
1409   }
1410 }
1411 
_getAdditionalNodesOnBoundary(GEntity * entity,std::vector<std::size_t> & nodeTags,std::vector<double> & coord,std::vector<double> & parametricCoord,bool parametric)1412 static void _getAdditionalNodesOnBoundary(GEntity *entity,
1413                                           std::vector<std::size_t> &nodeTags,
1414                                           std::vector<double> &coord,
1415                                           std::vector<double> &parametricCoord,
1416                                           bool parametric)
1417 {
1418   std::vector<GFace *> f;
1419   std::vector<GEdge *> e;
1420   std::vector<GVertex *> v;
1421   if(entity->dim() > 2) f = entity->faces();
1422   if(entity->dim() > 1) e = entity->edges();
1423   if(entity->dim() > 0) v = entity->vertices();
1424   for(auto it = f.begin(); it != f.end(); it++) {
1425     GFace *gf = *it;
1426     for(std::size_t j = 0; j < gf->mesh_vertices.size(); j++) {
1427       MVertex *v = gf->mesh_vertices[j];
1428       nodeTags.push_back(v->getNum());
1429       coord.push_back(v->x());
1430       coord.push_back(v->y());
1431       coord.push_back(v->z());
1432     }
1433   }
1434   for(auto it = e.begin(); it != e.end(); it++) {
1435     GEdge *ge = *it;
1436     for(std::size_t j = 0; j < ge->mesh_vertices.size(); j++) {
1437       MVertex *v = ge->mesh_vertices[j];
1438       nodeTags.push_back(v->getNum());
1439       coord.push_back(v->x());
1440       coord.push_back(v->y());
1441       coord.push_back(v->z());
1442       if(entity->dim() == 2 && parametric) {
1443         SPoint2 param;
1444         if(!reparamMeshVertexOnFace(v, (GFace *)entity, param, true, false))
1445           Msg::Warning("Failed to compute parameters of node %d on surface %d",
1446                        v->getNum(), entity->tag());
1447         parametricCoord.push_back(param.x());
1448         parametricCoord.push_back(param.y());
1449       }
1450     }
1451   }
1452   for(auto it = v.begin(); it != v.end(); it++) {
1453     GVertex *gv = *it;
1454     for(std::size_t j = 0; j < gv->mesh_vertices.size(); j++) {
1455       MVertex *v = gv->mesh_vertices[j];
1456       nodeTags.push_back(v->getNum());
1457       coord.push_back(v->x());
1458       coord.push_back(v->y());
1459       coord.push_back(v->z());
1460       if(entity->dim() == 2 && parametric) {
1461         SPoint2 param;
1462         if(!reparamMeshVertexOnFace(v, (GFace *)entity, param, true, false))
1463           Msg::Warning("Failed to compute parameters of node %d on surface %d",
1464                        v->getNum(), entity->tag());
1465         parametricCoord.push_back(param.x());
1466         parametricCoord.push_back(param.y());
1467       }
1468       else if(entity->dim() == 1 && parametric) {
1469         double param;
1470         if(!reparamMeshVertexOnEdge(v, (GEdge *)entity, param))
1471           Msg::Warning("Failed to compute parameters of node %d on curve %d",
1472                        v->getNum(), entity->tag());
1473         parametricCoord.push_back(param);
1474       }
1475     }
1476   }
1477 }
1478 
getNodes(std::vector<std::size_t> & nodeTags,std::vector<double> & coord,std::vector<double> & parametricCoord,const int dim,const int tag,const bool includeBoundary,const bool returnParametricCoord)1479 GMSH_API void gmsh::model::mesh::getNodes(std::vector<std::size_t> &nodeTags,
1480                                           std::vector<double> &coord,
1481                                           std::vector<double> &parametricCoord,
1482                                           const int dim, const int tag,
1483                                           const bool includeBoundary,
1484                                           const bool returnParametricCoord)
1485 {
1486   if(!_checkInit()) return;
1487   nodeTags.clear();
1488   coord.clear();
1489   parametricCoord.clear();
1490   std::vector<GEntity *> entities;
1491   if(dim >= 0 && tag >= 0) {
1492     GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1493     if(!ge) {
1494       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1495       return;
1496     }
1497     entities.push_back(ge);
1498   }
1499   else {
1500     GModel::current()->getEntities(entities, dim);
1501   }
1502   for(std::size_t i = 0; i < entities.size(); i++) {
1503     GEntity *ge = entities[i];
1504     for(std::size_t j = 0; j < ge->mesh_vertices.size(); j++) {
1505       MVertex *v = ge->mesh_vertices[j];
1506       nodeTags.push_back(v->getNum());
1507       coord.push_back(v->x());
1508       coord.push_back(v->y());
1509       coord.push_back(v->z());
1510       if(dim > 0 && returnParametricCoord) {
1511         double par;
1512         for(int k = 0; k < dim; k++) {
1513           if(v->getParameter(k, par)) parametricCoord.push_back(par);
1514         }
1515       }
1516     }
1517     if(includeBoundary)
1518       _getAdditionalNodesOnBoundary(ge, nodeTags, coord, parametricCoord,
1519                                     dim > 0 && returnParametricCoord);
1520   }
1521 }
1522 
getNodesByElementType(const int elementType,std::vector<std::size_t> & nodeTags,std::vector<double> & coord,std::vector<double> & parametricCoord,const int tag,const bool returnParametricCoord)1523 GMSH_API void gmsh::model::mesh::getNodesByElementType(
1524   const int elementType, std::vector<std::size_t> &nodeTags,
1525   std::vector<double> &coord, std::vector<double> &parametricCoord,
1526   const int tag, const bool returnParametricCoord)
1527 {
1528   if(!_checkInit()) return;
1529   nodeTags.clear();
1530   coord.clear();
1531   parametricCoord.clear();
1532   std::vector<GEntity *> entities;
1533   int dim = ElementType::getDimension(elementType);
1534   if(dim >= 0 && tag >= 0) {
1535     GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1536     if(!ge) {
1537       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1538       return;
1539     }
1540     entities.push_back(ge);
1541   }
1542   else {
1543     GModel::current()->getEntities(entities, dim);
1544   }
1545 
1546   int familyType = ElementType::getParentType(elementType);
1547   int numNodesByElements = ElementType::getNumVertices(elementType);
1548   std::size_t numElements = 0;
1549   for(std::size_t i = 0; i < entities.size(); ++i) {
1550     numElements += entities[i]->getNumMeshElementsByType(familyType);
1551   }
1552   std::size_t numNodes = numElements * numNodesByElements;
1553 
1554   nodeTags.reserve(numNodes);
1555   coord.reserve(numNodes * 3);
1556   if(returnParametricCoord) { parametricCoord.reserve(numNodes * 3); }
1557 
1558   for(std::size_t i = 0; i < entities.size(); i++) {
1559     GEntity *ge = entities[i];
1560     for(std::size_t j = 0;
1561         j < entities[i]->getNumMeshElementsByType(familyType); j++) {
1562       MElement *e = ge->getMeshElementByType(familyType, j);
1563       for(std::size_t k = 0; k < e->getNumVertices(); ++k) {
1564         MVertex *v = e->getVertex(k);
1565         nodeTags.push_back(v->getNum());
1566         coord.push_back(v->x());
1567         coord.push_back(v->y());
1568         coord.push_back(v->z());
1569         if(dim > 0 && returnParametricCoord) {
1570           double par;
1571           for(int k = 0; k < dim; k++) {
1572             if(v->getParameter(k, par)) parametricCoord.push_back(par);
1573           }
1574         }
1575       }
1576     }
1577   }
1578 }
1579 
getNode(const std::size_t nodeTag,std::vector<double> & coord,std::vector<double> & parametricCoord,int & dim,int & tag)1580 GMSH_API void gmsh::model::mesh::getNode(const std::size_t nodeTag,
1581                                          std::vector<double> &coord,
1582                                          std::vector<double> &parametricCoord,
1583                                          int &dim, int &tag)
1584 {
1585   if(!_checkInit()) return;
1586   MVertex *v = GModel::current()->getMeshVertexByTag(nodeTag);
1587   if(!v) {
1588     Msg::Error("Unknown node %d", nodeTag);
1589     return;
1590   }
1591   coord.resize(3);
1592   coord[0] = v->x();
1593   coord[1] = v->y();
1594   coord[2] = v->z();
1595   parametricCoord.reserve(2);
1596   double u;
1597   if(v->getParameter(0, u)) parametricCoord.push_back(u);
1598   if(v->getParameter(1, u)) parametricCoord.push_back(u);
1599   if(v->onWhat()) {
1600     dim = v->onWhat()->dim();
1601     tag = v->onWhat()->tag();
1602   }
1603   else {
1604     Msg::Warning("Node %d is not classified on any entity", nodeTag);
1605     dim = -1;
1606     tag = -1;
1607   }
1608 }
1609 
1610 GMSH_API void
setNode(const std::size_t nodeTag,const std::vector<double> & coord,const std::vector<double> & parametricCoord)1611 gmsh::model::mesh::setNode(const std::size_t nodeTag,
1612                            const std::vector<double> &coord,
1613                            const std::vector<double> &parametricCoord)
1614 {
1615   if(!_checkInit()) return;
1616   MVertex *v = GModel::current()->getMeshVertexByTag(nodeTag);
1617   if(!v) {
1618     Msg::Error("Unknown node %d", nodeTag);
1619     return;
1620   }
1621   if(coord.size() < 3) {
1622     Msg::Error("Less than three coordinates provided for node %d", nodeTag);
1623     return;
1624   }
1625   v->setXYZ(coord[0], coord[1], coord[2]);
1626   if(parametricCoord.size() >= 1) v->setParameter(0, parametricCoord[0]);
1627   if(parametricCoord.size() >= 2) v->setParameter(1, parametricCoord[1]);
1628 }
1629 
rebuildNodeCache(bool onlyIfNecessary)1630 GMSH_API void gmsh::model::mesh::rebuildNodeCache(bool onlyIfNecessary)
1631 {
1632   if(!_checkInit()) return;
1633   GModel::current()->rebuildMeshVertexCache(onlyIfNecessary);
1634 }
1635 
rebuildElementCache(bool onlyIfNecessary)1636 GMSH_API void gmsh::model::mesh::rebuildElementCache(bool onlyIfNecessary)
1637 {
1638   if(!_checkInit()) return;
1639   GModel::current()->rebuildMeshElementCache(onlyIfNecessary);
1640 }
1641 
1642 GMSH_API void
getNodesForPhysicalGroup(const int dim,const int tag,std::vector<std::size_t> & nodeTags,std::vector<double> & coord)1643 gmsh::model::mesh::getNodesForPhysicalGroup(const int dim, const int tag,
1644                                             std::vector<std::size_t> &nodeTags,
1645                                             std::vector<double> &coord)
1646 {
1647   if(!_checkInit()) return;
1648   nodeTags.clear();
1649   coord.clear();
1650   std::vector<MVertex *> v;
1651   GModel::current()->getMeshVerticesForPhysicalGroup(dim, tag, v);
1652   if(v.empty()) return;
1653   nodeTags.resize(v.size());
1654   coord.resize(v.size() * 3);
1655   for(std::size_t i = 0; i < v.size(); i++) {
1656     nodeTags[i] = v[i]->getNum();
1657     coord[3 * i + 0] = v[i]->x();
1658     coord[3 * i + 1] = v[i]->y();
1659     coord[3 * i + 2] = v[i]->z();
1660   }
1661 }
1662 
getMaxNodeTag(std::size_t & maxTag)1663 GMSH_API void gmsh::model::mesh::getMaxNodeTag(std::size_t &maxTag)
1664 {
1665   if(!_checkInit()) return;
1666   maxTag = GModel::current()->getMaxVertexNumber();
1667 }
1668 
addNodes(const int dim,const int tag,const std::vector<std::size_t> & nodeTags,const std::vector<double> & coord,const std::vector<double> & parametricCoord)1669 GMSH_API void gmsh::model::mesh::addNodes(
1670   const int dim, const int tag, const std::vector<std::size_t> &nodeTags,
1671   const std::vector<double> &coord, const std::vector<double> &parametricCoord)
1672 {
1673   if(!_checkInit()) return;
1674   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1675   if(!ge) {
1676     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1677     return;
1678   }
1679   int numNodeTags = nodeTags.size(), numNodes = nodeTags.size();
1680   if(!numNodeTags) { // this is allowed: we will assign new tags
1681     numNodes = coord.size() / 3;
1682   }
1683   if((int)coord.size() != 3 * numNodes) {
1684     Msg::Error("Wrong number of coordinates");
1685     return;
1686   }
1687   bool param = false;
1688   if(parametricCoord.size()) {
1689     if((int)parametricCoord.size() != dim * numNodes) {
1690       Msg::Error("Wrong number of parametric coordinates");
1691       return;
1692     }
1693     param = true;
1694   }
1695   for(int i = 0; i < numNodes; i++) {
1696     std::size_t tag = (numNodeTags ? nodeTags[i] : 0); // 0 = automatic tag
1697     double x = coord[3 * i];
1698     double y = coord[3 * i + 1];
1699     double z = coord[3 * i + 2];
1700     MVertex *vv = nullptr;
1701     if(param && dim == 1) {
1702       double u = parametricCoord[i];
1703       vv = new MEdgeVertex(x, y, z, ge, u, tag);
1704     }
1705     else if(param && dim == 2) {
1706       double u = parametricCoord[2 * i];
1707       double v = parametricCoord[2 * i + 1];
1708       vv = new MFaceVertex(x, y, z, ge, u, v, tag);
1709     }
1710     else
1711       vv = new MVertex(x, y, z, ge, tag);
1712     ge->mesh_vertices.push_back(vv);
1713   }
1714   GModel::current()->destroyMeshCaches();
1715 }
1716 
reclassifyNodes()1717 GMSH_API void gmsh::model::mesh::reclassifyNodes()
1718 {
1719   if(!_checkInit()) return;
1720   GModel::current()->pruneMeshVertexAssociations();
1721 }
1722 
relocateNodes(const int dim,const int tag)1723 GMSH_API void gmsh::model::mesh::relocateNodes(const int dim, const int tag)
1724 {
1725   if(!_checkInit()) return;
1726   std::vector<GEntity *> entities;
1727   if(dim >= 0 && tag >= 0) {
1728     GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1729     if(!ge) {
1730       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1731       return;
1732     }
1733     entities.push_back(ge);
1734   }
1735   else {
1736     GModel::current()->getEntities(entities, dim);
1737   }
1738   for(std::size_t i = 0; i < entities.size(); i++)
1739     entities[i]->relocateMeshVertices();
1740 }
1741 
1742 static void
_getEntitiesForElementTypes(int dim,int tag,std::map<int,std::vector<GEntity * >> & typeEnt)1743 _getEntitiesForElementTypes(int dim, int tag,
1744                             std::map<int, std::vector<GEntity *> > &typeEnt)
1745 {
1746   std::vector<GEntity *> entities;
1747   if(dim >= 0 && tag >= 0) {
1748     GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
1749     if(!ge) {
1750       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
1751       return;
1752     }
1753     entities.push_back(ge);
1754   }
1755   else {
1756     GModel::current()->getEntities(entities, dim);
1757   }
1758   for(std::size_t i = 0; i < entities.size(); i++) {
1759     GEntity *ge = entities[i];
1760     switch(ge->dim()) {
1761     case 0: {
1762       GVertex *v = static_cast<GVertex *>(ge);
1763       if(v->points.size())
1764         typeEnt[v->points.front()->getTypeForMSH()].push_back(ge);
1765       break;
1766     }
1767     case 1: {
1768       GEdge *e = static_cast<GEdge *>(ge);
1769       if(e->lines.size())
1770         typeEnt[e->lines.front()->getTypeForMSH()].push_back(ge);
1771       break;
1772     }
1773     case 2: {
1774       GFace *f = static_cast<GFace *>(ge);
1775       if(f->triangles.size())
1776         typeEnt[f->triangles.front()->getTypeForMSH()].push_back(ge);
1777       if(f->quadrangles.size())
1778         typeEnt[f->quadrangles.front()->getTypeForMSH()].push_back(ge);
1779       break;
1780     }
1781     case 3: {
1782       GRegion *r = static_cast<GRegion *>(ge);
1783       if(r->tetrahedra.size())
1784         typeEnt[r->tetrahedra.front()->getTypeForMSH()].push_back(ge);
1785       if(r->hexahedra.size())
1786         typeEnt[r->hexahedra.front()->getTypeForMSH()].push_back(ge);
1787       if(r->prisms.size())
1788         typeEnt[r->prisms.front()->getTypeForMSH()].push_back(ge);
1789       if(r->pyramids.size())
1790         typeEnt[r->pyramids.front()->getTypeForMSH()].push_back(ge);
1791       break;
1792     }
1793     }
1794   }
1795 }
1796 
getElements(std::vector<int> & elementTypes,std::vector<std::vector<std::size_t>> & elementTags,std::vector<std::vector<std::size_t>> & nodeTags,const int dim,const int tag)1797 GMSH_API void gmsh::model::mesh::getElements(
1798   std::vector<int> &elementTypes,
1799   std::vector<std::vector<std::size_t> > &elementTags,
1800   std::vector<std::vector<std::size_t> > &nodeTags, const int dim,
1801   const int tag)
1802 {
1803   if(!_checkInit()) return;
1804   elementTypes.clear();
1805   elementTags.clear();
1806   nodeTags.clear();
1807   std::map<int, std::vector<GEntity *> > typeEnt;
1808   _getEntitiesForElementTypes(dim, tag, typeEnt);
1809   for(auto it = typeEnt.begin(); it != typeEnt.end(); it++) {
1810     elementTypes.push_back(it->first);
1811     elementTags.push_back(std::vector<std::size_t>());
1812     nodeTags.push_back(std::vector<std::size_t>());
1813     int elementType = it->first;
1814     for(std::size_t i = 0; i < it->second.size(); i++) {
1815       GEntity *ge = it->second[i];
1816       for(std::size_t j = 0; j < ge->getNumMeshElements(); j++) {
1817         MElement *e = ge->getMeshElement(j);
1818         if(e->getTypeForMSH() == elementType) {
1819           elementTags.back().push_back(e->getNum());
1820           for(std::size_t k = 0; k < e->getNumVertices(); k++) {
1821             nodeTags.back().push_back(e->getVertex(k)->getNum());
1822           }
1823         }
1824       }
1825     }
1826   }
1827 }
1828 
getElement(const std::size_t elementTag,int & elementType,std::vector<std::size_t> & nodeTags,int & dim,int & tag)1829 GMSH_API void gmsh::model::mesh::getElement(const std::size_t elementTag,
1830                                             int &elementType,
1831                                             std::vector<std::size_t> &nodeTags,
1832                                             int &dim, int &tag)
1833 {
1834   if(!_checkInit()) return;
1835   int entityTag;
1836   MElement *e = GModel::current()->getMeshElementByTag(elementTag, entityTag);
1837   if(!e) {
1838     Msg::Error("Unknown element %d", elementTag);
1839     return;
1840   }
1841   elementType = e->getTypeForMSH();
1842   nodeTags.clear();
1843   for(std::size_t i = 0; i < e->getNumVertices(); i++) {
1844     MVertex *v = e->getVertex(i);
1845     if(!v) {
1846       Msg::Error("Unknown node in element %d", elementTag);
1847       return;
1848     }
1849     nodeTags.push_back(v->getNum());
1850   }
1851   dim = e->getDim();
1852   tag = entityTag;
1853 }
1854 
getElementByCoordinates(const double x,const double y,const double z,std::size_t & elementTag,int & elementType,std::vector<std::size_t> & nodeTags,double & u,double & v,double & w,const int dim,const bool strict)1855 GMSH_API void gmsh::model::mesh::getElementByCoordinates(
1856   const double x, const double y, const double z, std::size_t &elementTag,
1857   int &elementType, std::vector<std::size_t> &nodeTags, double &u, double &v,
1858   double &w, const int dim, const bool strict)
1859 {
1860   if(!_checkInit()) return;
1861   SPoint3 xyz(x, y, z), uvw;
1862   MElement *e = GModel::current()->getMeshElementByCoord(xyz, uvw, dim, strict);
1863   if(!e) {
1864     Msg::Error("No element found at (%g, %g, %g)", x, y, z);
1865     return;
1866   }
1867   elementTag = e->getNum();
1868   elementType = e->getTypeForMSH();
1869   nodeTags.clear();
1870   for(std::size_t i = 0; i < e->getNumVertices(); i++) {
1871     MVertex *v = e->getVertex(i);
1872     if(!v) {
1873       Msg::Error("Unknown node in element %d", elementTag);
1874       return;
1875     }
1876     nodeTags.push_back(v->getNum());
1877   }
1878   u = uvw.x();
1879   v = uvw.y();
1880   w = uvw.z();
1881 }
1882 
getElementsByCoordinates(const double x,const double y,const double z,std::vector<std::size_t> & elementTags,const int dim,const bool strict)1883 GMSH_API void gmsh::model::mesh::getElementsByCoordinates(
1884   const double x, const double y, const double z,
1885   std::vector<std::size_t> &elementTags, const int dim, const bool strict)
1886 {
1887   if(!_checkInit()) return;
1888   SPoint3 xyz(x, y, z), uvw;
1889   elementTags.clear();
1890   std::vector<MElement *> e =
1891     GModel::current()->getMeshElementsByCoord(xyz, dim, strict);
1892   if(e.empty()) {
1893     Msg::Error("No element found at (%g, %g, %g)", x, y, z);
1894     return;
1895   }
1896   for(std::size_t i = 0; i < e.size(); i++) {
1897     elementTags.push_back(e[i]->getNum());
1898   }
1899 }
1900 
getLocalCoordinatesInElement(const std::size_t elementTag,const double x,const double y,const double z,double & u,double & v,double & w)1901 GMSH_API void gmsh::model::mesh::getLocalCoordinatesInElement(
1902   const std::size_t elementTag, const double x, const double y, const double z,
1903   double &u, double &v, double &w)
1904 {
1905   if(!_checkInit()) return;
1906   MElement *e = GModel::current()->getMeshElementByTag(elementTag);
1907   if(!e) {
1908     Msg::Error("Unknown element %d", elementTag);
1909     return;
1910   }
1911   double xyz[3] = {x, y, z}, uvw[3];
1912   e->xyz2uvw(xyz, uvw);
1913   u = uvw[0];
1914   v = uvw[1];
1915   w = uvw[2];
1916 }
1917 
1918 template <class T>
_addElements(int dim,int tag,const std::vector<MElement * > & src,std::vector<T * > & dst)1919 static void _addElements(int dim, int tag, const std::vector<MElement *> &src,
1920                          std::vector<T *> &dst)
1921 {
1922   for(std::size_t i = 0; i < src.size(); i++)
1923     dst.push_back(static_cast<T *>(src[i]));
1924 }
1925 
_addElements(int dim,int tag,GEntity * ge,int type,const std::vector<std::size_t> & elementTags,const std::vector<std::size_t> & nodeTags)1926 static void _addElements(int dim, int tag, GEntity *ge, int type,
1927                          const std::vector<std::size_t> &elementTags,
1928                          const std::vector<std::size_t> &nodeTags)
1929 {
1930   unsigned int numNodesPerEle = MElement::getInfoMSH(type);
1931   if(!numNodesPerEle) return;
1932   std::size_t numEleTags = elementTags.size();
1933   std::size_t numEle = numEleTags;
1934   if(!numEle) { numEle = nodeTags.size() / numNodesPerEle; }
1935   if(!numEle) return;
1936   if(numEle * numNodesPerEle != nodeTags.size()) {
1937     Msg::Error("Wrong number of node tags for element type %d", type);
1938     return;
1939   }
1940   std::vector<MElement *> elements(numEle);
1941   std::vector<MVertex *> nodes(numNodesPerEle);
1942   for(std::size_t j = 0; j < numEle; j++) {
1943     std::size_t etag = (numEleTags ? elementTags[j] : 0); // 0 = automatic tag
1944     MElementFactory f;
1945     for(std::size_t k = 0; k < numNodesPerEle; k++) {
1946       std::size_t vtag = nodeTags[numNodesPerEle * j + k];
1947       // this will rebuild the node cache if necessary
1948       nodes[k] = GModel::current()->getMeshVertexByTag(vtag);
1949       if(!nodes[k]) {
1950         Msg::Error("Unknown node %d", vtag);
1951         return;
1952       }
1953     }
1954     elements[j] = f.create(type, nodes, etag);
1955   }
1956   bool ok = true;
1957   switch(dim) {
1958   case 0:
1959     if(elements[0]->getType() == TYPE_PNT)
1960       _addElements(dim, tag, elements, static_cast<GVertex *>(ge)->points);
1961     else
1962       ok = false;
1963     break;
1964   case 1:
1965     if(elements[0]->getType() == TYPE_LIN)
1966       _addElements(dim, tag, elements, static_cast<GEdge *>(ge)->lines);
1967     else
1968       ok = false;
1969     break;
1970   case 2:
1971     if(elements[0]->getType() == TYPE_TRI)
1972       _addElements(dim, tag, elements, static_cast<GFace *>(ge)->triangles);
1973     else if(elements[0]->getType() == TYPE_QUA)
1974       _addElements(dim, tag, elements, static_cast<GFace *>(ge)->quadrangles);
1975     else
1976       ok = false;
1977     break;
1978   case 3:
1979     if(elements[0]->getType() == TYPE_TET)
1980       _addElements(dim, tag, elements, static_cast<GRegion *>(ge)->tetrahedra);
1981     else if(elements[0]->getType() == TYPE_HEX)
1982       _addElements(dim, tag, elements, static_cast<GRegion *>(ge)->hexahedra);
1983     else if(elements[0]->getType() == TYPE_PRI)
1984       _addElements(dim, tag, elements, static_cast<GRegion *>(ge)->prisms);
1985     else if(elements[0]->getType() == TYPE_PYR)
1986       _addElements(dim, tag, elements, static_cast<GRegion *>(ge)->pyramids);
1987     else
1988       ok = false;
1989     break;
1990   }
1991   if(!ok)
1992     Msg::Error("Wrong type of element for %s",
1993                _getEntityName(dim, tag).c_str());
1994 }
1995 
getMaxElementTag(std::size_t & maxTag)1996 GMSH_API void gmsh::model::mesh::getMaxElementTag(std::size_t &maxTag)
1997 {
1998   if(!_checkInit()) return;
1999   maxTag = GModel::current()->getMaxElementNumber();
2000 }
2001 
addElements(const int dim,const int tag,const std::vector<int> & elementTypes,const std::vector<std::vector<std::size_t>> & elementTags,const std::vector<std::vector<std::size_t>> & nodeTags)2002 GMSH_API void gmsh::model::mesh::addElements(
2003   const int dim, const int tag, const std::vector<int> &elementTypes,
2004   const std::vector<std::vector<std::size_t> > &elementTags,
2005   const std::vector<std::vector<std::size_t> > &nodeTags)
2006 {
2007   if(!_checkInit()) return;
2008   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
2009   if(!ge) {
2010     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
2011     return;
2012   }
2013   if(elementTypes.size() != elementTags.size()) {
2014     Msg::Error("Wrong number of element tags");
2015     return;
2016   }
2017   if(elementTypes.size() != nodeTags.size()) {
2018     Msg::Error("Wrong number of node tags");
2019     return;
2020   }
2021 
2022   for(std::size_t i = 0; i < elementTypes.size(); i++)
2023     _addElements(dim, tag, ge, elementTypes[i], elementTags[i], nodeTags[i]);
2024   GModel::current()->destroyMeshCaches();
2025 }
2026 
addElementsByType(const int tag,const int elementType,const std::vector<std::size_t> & elementTags,const std::vector<std::size_t> & nodeTags)2027 GMSH_API void gmsh::model::mesh::addElementsByType(
2028   const int tag, const int elementType,
2029   const std::vector<std::size_t> &elementTags,
2030   const std::vector<std::size_t> &nodeTags)
2031 {
2032   if(!_checkInit()) return;
2033   int dim = ElementType::getDimension(elementType);
2034   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
2035   if(!ge) {
2036     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
2037     return;
2038   }
2039   _addElements(dim, tag, ge, elementType, elementTags, nodeTags);
2040   GModel::current()->destroyMeshCaches();
2041 }
2042 
getElementTypes(std::vector<int> & elementTypes,const int dim,const int tag)2043 GMSH_API void gmsh::model::mesh::getElementTypes(std::vector<int> &elementTypes,
2044                                                  const int dim, const int tag)
2045 {
2046   if(!_checkInit()) return;
2047   elementTypes.clear();
2048   std::map<int, std::vector<GEntity *> > typeEnt;
2049   _getEntitiesForElementTypes(dim, tag, typeEnt);
2050   for(auto it = typeEnt.begin(); it != typeEnt.end(); it++) {
2051     elementTypes.push_back(it->first);
2052   }
2053 }
2054 
getElementType(const std::string & family,const int order,const bool serendip)2055 GMSH_API int gmsh::model::mesh::getElementType(const std::string &family,
2056                                                const int order,
2057                                                const bool serendip)
2058 {
2059   if(!_checkInit()) return -1;
2060   int familyType =
2061     (family == "Point" || family == "point")             ? TYPE_PNT :
2062     (family == "Line" || family == "line")               ? TYPE_LIN :
2063     (family == "Triangle" || family == "triangle")       ? TYPE_TRI :
2064     (family == "Quadrangle" || family == "quadrangle")   ? TYPE_QUA :
2065     (family == "Tetrahedron" || family == "tetrahedron") ? TYPE_TET :
2066     (family == "Pyramid" || family == "pyramid")         ? TYPE_PYR :
2067     (family == "Prism" || family == "prism")             ? TYPE_PRI :
2068     (family == "Hexahedron" || family == "hexahedron")   ? TYPE_HEX :
2069     (family == "Polygon" || family == "polygon")         ? TYPE_POLYG :
2070     (family == "Polyhedron" || family == "polyhedron")   ? TYPE_POLYH :
2071     (family == "Trihedron" || family == "trihedron")     ? TYPE_TRIH :
2072                                                            -1;
2073   return ElementType::getType(familyType, order, serendip);
2074 }
2075 
getElementProperties(const int elementType,std::string & name,int & dim,int & order,int & numNodes,std::vector<double> & localNodeCoord,int & numPrimaryNodes)2076 GMSH_API void gmsh::model::mesh::getElementProperties(
2077   const int elementType, std::string &name, int &dim, int &order, int &numNodes,
2078   std::vector<double> &localNodeCoord, int &numPrimaryNodes)
2079 {
2080   if(!_checkInit()) return;
2081   const char *n;
2082   MElement::getInfoMSH(elementType, &n);
2083   name = n;
2084   int parentType = ElementType::getParentType(elementType);
2085   nodalBasis *basis = nullptr;
2086   if(parentType == TYPE_PYR)
2087     basis = new pyramidalBasis(elementType);
2088   else
2089     basis = new polynomialBasis(elementType);
2090   dim = basis->dimension;
2091   order = basis->order;
2092   numNodes = basis->points.size1();
2093   if(numNodes != ElementType::getNumVertices(elementType)) {
2094     Msg::Error("Size of basis incompatible with element type");
2095     return;
2096   }
2097   for(int i = 0; i < basis->points.size1(); i++)
2098     for(int j = 0; j < basis->points.size2(); j++)
2099       localNodeCoord.push_back(basis->points(i, j));
2100   delete basis;
2101   numPrimaryNodes =
2102     ElementType::getNumVertices(ElementType::getPrimaryType(elementType));
2103 }
2104 
getElementsByType(const int elementType,std::vector<std::size_t> & elementTags,std::vector<std::size_t> & nodeTags,const int tag,const std::size_t task,const std::size_t numTasks)2105 GMSH_API void gmsh::model::mesh::getElementsByType(
2106   const int elementType, std::vector<std::size_t> &elementTags,
2107   std::vector<std::size_t> &nodeTags, const int tag, const std::size_t task,
2108   const std::size_t numTasks)
2109 {
2110   if(!_checkInit()) return;
2111   int dim = ElementType::getDimension(elementType);
2112   std::map<int, std::vector<GEntity *> > typeEnt;
2113   _getEntitiesForElementTypes(dim, tag, typeEnt);
2114   const std::vector<GEntity *> &entities(typeEnt[elementType]);
2115   int familyType = ElementType::getParentType(elementType);
2116   std::size_t numElements = 0;
2117   for(std::size_t i = 0; i < entities.size(); i++)
2118     numElements += entities[i]->getNumMeshElementsByType(familyType);
2119   const int numNodes = ElementType::getNumVertices(elementType);
2120   if(!numTasks) {
2121     Msg::Error("Number of tasks should be > 0");
2122     return;
2123   }
2124   const std::size_t begin = (task * numElements) / numTasks;
2125   const std::size_t end = ((task + 1) * numElements) / numTasks;
2126   // check arrays
2127   bool haveElementTags = elementTags.size();
2128   bool haveNodeTags = nodeTags.size();
2129   if(!haveElementTags && !haveNodeTags) {
2130     if(numTasks > 1)
2131       Msg::Warning("ElementTags and nodeTags should be preallocated "
2132                    "if numTasks > 1");
2133     haveElementTags = haveNodeTags = true;
2134     preallocateElementsByType(elementType, haveElementTags, haveNodeTags,
2135                               elementTags, nodeTags, tag);
2136   }
2137   if(haveElementTags && (elementTags.size() < numElements)) {
2138     Msg::Error("Wrong size of elementTags array (%d < %d)", elementTags.size(),
2139                numElements);
2140     return;
2141   }
2142   if(haveNodeTags && (nodeTags.size() < numElements * numNodes)) {
2143     Msg::Error("Wrong size of nodeTags array (%d < %d)", nodeTags.size(),
2144                numElements * numNodes);
2145     return;
2146   }
2147   size_t o = 0;
2148   size_t idx = begin * numNodes;
2149   for(std::size_t i = 0; i < entities.size(); i++) {
2150     GEntity *ge = entities[i];
2151     for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType); j++) {
2152       if(o >= begin && o < end) {
2153         MElement *e = ge->getMeshElementByType(familyType, j);
2154         if(haveElementTags) elementTags[o] = e->getNum();
2155         if(haveNodeTags) {
2156           for(std::size_t k = 0; k < e->getNumVertices(); k++) {
2157             nodeTags[idx++] = e->getVertex(k)->getNum();
2158           }
2159         }
2160       }
2161       o++;
2162     }
2163   }
2164 }
2165 
preallocateElementsByType(const int elementType,const bool elementTag,const bool nodeTag,std::vector<std::size_t> & elementTags,std::vector<std::size_t> & nodeTags,const int tag)2166 GMSH_API void gmsh::model::mesh::preallocateElementsByType(
2167   const int elementType, const bool elementTag, const bool nodeTag,
2168   std::vector<std::size_t> &elementTags, std::vector<std::size_t> &nodeTags,
2169   const int tag)
2170 {
2171   if(!_checkInit()) return;
2172   int dim = ElementType::getDimension(elementType);
2173   std::map<int, std::vector<GEntity *> > typeEnt;
2174   _getEntitiesForElementTypes(dim, tag, typeEnt);
2175   const std::vector<GEntity *> &entities(typeEnt[elementType]);
2176   int familyType = ElementType::getParentType(elementType);
2177   std::size_t numElements = 0;
2178   for(std::size_t i = 0; i < entities.size(); i++)
2179     numElements += entities[i]->getNumMeshElementsByType(familyType);
2180   const int numNodesPerEle = ElementType::getNumVertices(elementType);
2181   if(!numElements) return;
2182   if(elementTag) {
2183     elementTags.clear();
2184     elementTags.resize(numElements, 0);
2185   }
2186   if(nodeTag) {
2187     nodeTags.clear();
2188     nodeTags.resize(numElements * numNodesPerEle, 0);
2189   }
2190 }
2191 
_getFunctionSpaceInfo(const std::string & fsType,std::string & fsName,int & fsOrder,int & fsComp)2192 static bool _getFunctionSpaceInfo(const std::string &fsType,
2193                                   std::string &fsName, int &fsOrder,
2194                                   int &fsComp)
2195 {
2196   if(fsType.empty() || fsType == "None") {
2197     fsName = "";
2198     fsOrder = 0;
2199     fsComp = 0;
2200     return true;
2201   }
2202   if(fsType.size() > 8 && fsType.substr(0,8) == "Lagrange") {
2203     fsName = "Lagrange";
2204     fsOrder = atoi(fsType.substr(8).c_str());
2205     fsComp = 1;
2206     return true;
2207   }
2208   if(fsType.size() > 12 && fsType.substr(0,12) == "GradLagrange") {
2209     fsName = "GradLagrange";
2210     fsOrder = atoi(fsType.substr(12).c_str());
2211     fsComp = 3;
2212     return true;
2213   }
2214   if(fsType == "IsoParametric" || fsType == "Lagrange") {
2215     fsName = "Lagrange";
2216     fsOrder = -1;
2217     fsComp = 1;
2218     return true;
2219   }
2220   if(fsType == "GradIsoParametric" || fsType == "GradLagrange") {
2221     fsName = "GradLagrange";
2222     fsOrder = -1;
2223     fsComp = 3;
2224     return true;
2225   }
2226   if(fsType.substr(0, 10) == "H1Legendre") {
2227     fsName = "H1Legendre";
2228     fsOrder = atoi(fsType.substr(10).c_str());
2229     fsComp = 1;
2230     return true;
2231   }
2232   if(fsType.substr(0, 14) == "GradH1Legendre") {
2233     fsName = "GradH1Legendre";
2234     fsOrder = atoi(fsType.substr(14).c_str());
2235     fsComp = 3;
2236     return true;
2237   }
2238   if(fsType.substr(0, 13) == "HcurlLegendre") {
2239     fsName = "HcurlLegendre";
2240     fsOrder = atoi(fsType.substr(13).c_str());
2241     fsComp = 3;
2242     return true;
2243   }
2244   if(fsType.substr(0, 17) == "CurlHcurlLegendre") {
2245     fsName = "CurlHcurlLegendre";
2246     fsOrder = atoi(fsType.substr(17).c_str());
2247     fsComp = 3;
2248     return true;
2249   }
2250   return false;
2251 }
2252 
getJacobians(const int elementType,const std::vector<double> & localCoord,std::vector<double> & jacobians,std::vector<double> & determinants,std::vector<double> & coord,const int tag,const std::size_t task,const std::size_t numTasks)2253 GMSH_API void gmsh::model::mesh::getJacobians(
2254   const int elementType, const std::vector<double> &localCoord,
2255   std::vector<double> &jacobians, std::vector<double> &determinants,
2256   std::vector<double> &coord, const int tag, const std::size_t task,
2257   const std::size_t numTasks)
2258 {
2259   if(!_checkInit()) return;
2260   int dim = ElementType::getDimension(elementType);
2261   std::map<int, std::vector<GEntity *> > typeEnt;
2262   _getEntitiesForElementTypes(dim, tag, typeEnt);
2263   const std::vector<GEntity *> &entities(typeEnt[elementType]);
2264   int familyType = ElementType::getParentType(elementType);
2265   int numPoints = localCoord.size() / 3;
2266   if(!numPoints) {
2267     Msg::Warning("No evaluation points in getJacobians");
2268     return;
2269   }
2270 
2271   // check arrays
2272   bool haveJacobians = jacobians.size();
2273   bool haveDeterminants = determinants.size();
2274   bool havePoints = coord.size();
2275   if(!haveDeterminants && !haveJacobians && !havePoints) {
2276     if(numTasks > 1)
2277       Msg::Warning("Jacobians, determinants and points should be preallocated "
2278                    "if numTasks > 1");
2279     haveJacobians = haveDeterminants = havePoints = true;
2280     preallocateJacobians(elementType, numPoints, haveJacobians,
2281                          haveDeterminants, havePoints, jacobians, determinants,
2282                          coord, tag);
2283   }
2284   // get data
2285   {
2286     std::size_t numElements = 0;
2287     for(std::size_t i = 0; i < entities.size(); i++) {
2288       GEntity *ge = entities[i];
2289       numElements += ge->getNumMeshElementsByType(familyType);
2290     }
2291     if(!numTasks) {
2292       Msg::Error("Number of tasks should be > 0");
2293       return;
2294     }
2295     const size_t begin = (task * numElements) / numTasks;
2296     const size_t end = ((task + 1) * numElements) / numTasks;
2297     if(haveDeterminants && (end * numPoints > determinants.size())) {
2298       Msg::Error("Wrong size of determinants array (%d < %d)",
2299                  determinants.size(), end * numPoints);
2300       return;
2301     }
2302     if(haveJacobians && (9 * end * numPoints > jacobians.size())) {
2303       Msg::Error("Wrong size of jacobians array (%d < %d)", jacobians.size(),
2304                  9 * end * numPoints);
2305       return;
2306     }
2307     if(havePoints && (3 * end * numPoints > coord.size())) {
2308       Msg::Error("Wrong size of points array (%d < %d)", coord.size(),
2309                  3 * end * numPoints);
2310       return;
2311     }
2312     if(haveDeterminants && haveJacobians && havePoints) {
2313       std::vector<std::vector<SVector3> > gsf;
2314       size_t o = 0;
2315       size_t idx = begin * numPoints;
2316       for(std::size_t i = 0; i < entities.size(); i++) {
2317         GEntity *ge = entities[i];
2318         for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType);
2319             j++) {
2320           if(o >= begin && o < end) {
2321             MElement *e = ge->getMeshElementByType(familyType, j);
2322             if(gsf.size() == 0) {
2323               gsf.resize(numPoints);
2324               for(int k = 0; k < numPoints; k++) {
2325                 double value[1256][3];
2326                 e->getGradShapeFunctions(localCoord[3 * k],
2327                                          localCoord[3 * k + 1],
2328                                          localCoord[3 * k + 2], value);
2329                 gsf[k].resize(e->getNumShapeFunctions());
2330                 for(std::size_t l = 0; l < e->getNumShapeFunctions(); l++) {
2331                   gsf[k][l][0] = value[l][0];
2332                   gsf[k][l][1] = value[l][1];
2333                   gsf[k][l][2] = value[l][2];
2334                 }
2335               }
2336             }
2337             for(int k = 0; k < numPoints; k++) {
2338               e->pnt(localCoord[3 * k], localCoord[3 * k + 1],
2339                      localCoord[3 * k + 2], &coord[idx * 3]);
2340               determinants[idx] = e->getJacobian(gsf[k], &jacobians[idx * 9]);
2341               idx++;
2342             }
2343           }
2344           o++;
2345         }
2346       }
2347     }
2348     else if(haveDeterminants && haveJacobians && !havePoints) {
2349       std::vector<std::vector<SVector3> > gsf;
2350       size_t o = 0;
2351       size_t idx = begin * numPoints;
2352       for(std::size_t i = 0; i < entities.size(); i++) {
2353         GEntity *ge = entities[i];
2354         for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType);
2355             j++) {
2356           if(o >= begin && o < end) {
2357             MElement *e = ge->getMeshElementByType(familyType, j);
2358             if(gsf.size() == 0) {
2359               gsf.resize(numPoints);
2360               for(int k = 0; k < numPoints; k++) {
2361                 double value[1256][3];
2362                 e->getGradShapeFunctions(localCoord[3 * k],
2363                                          localCoord[3 * k + 1],
2364                                          localCoord[3 * k + 2], value);
2365                 gsf[k].resize(e->getNumShapeFunctions());
2366                 for(std::size_t l = 0; l < e->getNumShapeFunctions(); l++) {
2367                   gsf[k][l][0] = value[l][0];
2368                   gsf[k][l][1] = value[l][1];
2369                   gsf[k][l][2] = value[l][2];
2370                 }
2371               }
2372             }
2373             for(int k = 0; k < numPoints; k++) {
2374               determinants[idx] = e->getJacobian(gsf[k], &jacobians[idx * 9]);
2375               idx++;
2376             }
2377           }
2378           o++;
2379         }
2380       }
2381     }
2382     else if(haveDeterminants && !haveJacobians && havePoints) {
2383       std::vector<double> jac(9, 0.);
2384       std::vector<std::vector<SVector3> > gsf;
2385       size_t o = 0;
2386       size_t idx = begin * numPoints;
2387       for(std::size_t i = 0; i < entities.size(); i++) {
2388         GEntity *ge = entities[i];
2389         for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType);
2390             j++) {
2391           if(o >= begin && o < end) {
2392             MElement *e = ge->getMeshElementByType(familyType, j);
2393             if(gsf.size() == 0) {
2394               gsf.resize(numPoints);
2395               for(int k = 0; k < numPoints; k++) {
2396                 double value[1256][3];
2397                 e->getGradShapeFunctions(localCoord[3 * k],
2398                                          localCoord[3 * k + 1],
2399                                          localCoord[3 * k + 2], value);
2400                 gsf[k].resize(e->getNumShapeFunctions());
2401                 for(std::size_t l = 0; l < e->getNumShapeFunctions(); l++) {
2402                   gsf[k][l][0] = value[l][0];
2403                   gsf[k][l][1] = value[l][1];
2404                   gsf[k][l][2] = value[l][2];
2405                 }
2406               }
2407             }
2408             for(int k = 0; k < numPoints; k++) {
2409               e->pnt(localCoord[3 * k], localCoord[3 * k + 1],
2410                      localCoord[3 * k + 2], &coord[idx * 3]);
2411               determinants[idx] = e->getJacobian(gsf[k], &jac[0]);
2412               idx++;
2413             }
2414           }
2415           o++;
2416         }
2417       }
2418     }
2419     else if(haveDeterminants && !haveJacobians && !havePoints) {
2420       std::vector<double> jac(9, 0.);
2421       std::vector<std::vector<SVector3> > gsf;
2422       size_t o = 0;
2423       size_t idx = begin * numPoints;
2424       for(std::size_t i = 0; i < entities.size(); i++) {
2425         GEntity *ge = entities[i];
2426         for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType);
2427             j++) {
2428           if(o >= begin && o < end) {
2429             MElement *e = ge->getMeshElementByType(familyType, j);
2430             if(gsf.size() == 0) {
2431               gsf.resize(numPoints);
2432               for(int k = 0; k < numPoints; k++) {
2433                 double value[1256][3];
2434                 e->getGradShapeFunctions(localCoord[3 * k],
2435                                          localCoord[3 * k + 1],
2436                                          localCoord[3 * k + 2], value);
2437                 gsf[k].resize(e->getNumShapeFunctions());
2438                 for(std::size_t l = 0; l < e->getNumShapeFunctions(); l++) {
2439                   gsf[k][l][0] = value[l][0];
2440                   gsf[k][l][1] = value[l][1];
2441                   gsf[k][l][2] = value[l][2];
2442                 }
2443               }
2444             }
2445             for(int k = 0; k < numPoints; k++) {
2446               determinants[idx] = e->getJacobian(gsf[k], &jac[0]);
2447               idx++;
2448             }
2449           }
2450           o++;
2451         }
2452       }
2453     }
2454     else if(!haveDeterminants && haveJacobians && !havePoints) {
2455       std::vector<std::vector<SVector3> > gsf;
2456       size_t o = 0;
2457       size_t idx = begin * numPoints;
2458       for(std::size_t i = 0; i < entities.size(); i++) {
2459         GEntity *ge = entities[i];
2460         for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType);
2461             j++) {
2462           if(o >= begin && o < end) {
2463             MElement *e = ge->getMeshElementByType(familyType, j);
2464             if(gsf.size() == 0) {
2465               gsf.resize(numPoints);
2466               for(int k = 0; k < numPoints; k++) {
2467                 double value[1256][3];
2468                 e->getGradShapeFunctions(localCoord[3 * k],
2469                                          localCoord[3 * k + 1],
2470                                          localCoord[3 * k + 2], value);
2471                 gsf[k].resize(e->getNumShapeFunctions());
2472                 for(std::size_t l = 0; l < e->getNumShapeFunctions(); l++) {
2473                   gsf[k][l][0] = value[l][0];
2474                   gsf[k][l][1] = value[l][1];
2475                   gsf[k][l][2] = value[l][2];
2476                 }
2477               }
2478             }
2479             for(int k = 0; k < numPoints; k++) {
2480               e->getJacobian(gsf[k], &jacobians[idx * 9]);
2481               idx++;
2482             }
2483           }
2484           o++;
2485         }
2486       }
2487     }
2488     else {
2489       Msg::Error("The case with 'haveDeterminants = %s', `haveJacobians = %s` "
2490                  "and 'havePoints = %s' is not yet implemented",
2491                  (haveDeterminants ? "true" : "false"),
2492                  (haveJacobians ? "true" : "false"),
2493                  (havePoints ? "true" : "false"));
2494       return;
2495     }
2496     // Add other combinaisons if necessary
2497   }
2498 }
2499 
preallocateJacobians(const int elementType,const int numPoints,const bool allocateJacobians,const bool allocateDeterminants,const bool allocateCoord,std::vector<double> & jacobians,std::vector<double> & determinants,std::vector<double> & coord,const int tag)2500 GMSH_API void gmsh::model::mesh::preallocateJacobians(
2501   const int elementType, const int numPoints, const bool allocateJacobians,
2502   const bool allocateDeterminants, const bool allocateCoord,
2503   std::vector<double> &jacobians, std::vector<double> &determinants,
2504   std::vector<double> &coord, const int tag)
2505 {
2506   if(!_checkInit()) return;
2507   int dim = ElementType::getDimension(elementType);
2508   BasisFactory::getNodalBasis(elementType);
2509   std::map<int, std::vector<GEntity *> > typeEnt;
2510   _getEntitiesForElementTypes(dim, tag, typeEnt);
2511   const std::vector<GEntity *> &entities(typeEnt[elementType]);
2512   int familyType = ElementType::getParentType(elementType);
2513   std::size_t numElements = 0;
2514   for(std::size_t i = 0; i < entities.size(); i++)
2515     numElements += entities[i]->getNumMeshElementsByType(familyType);
2516   if(!numElements) return;
2517   if(allocateJacobians) {
2518     jacobians.clear();
2519     jacobians.resize(9 * numElements * numPoints);
2520   }
2521   if(allocateDeterminants) {
2522     determinants.clear();
2523     determinants.resize(numElements * numPoints);
2524   }
2525   if(allocateCoord) {
2526     coord.clear();
2527     coord.resize(3 * numElements * numPoints);
2528   }
2529 }
2530 
getJacobian(const std::size_t elementTag,const std::vector<double> & localCoord,std::vector<double> & jacobians,std::vector<double> & determinants,std::vector<double> & coord)2531 GMSH_API void gmsh::model::mesh::getJacobian(
2532   const std::size_t elementTag, const std::vector<double> &localCoord,
2533   std::vector<double> &jacobians, std::vector<double> &determinants,
2534   std::vector<double> &coord)
2535 {
2536   if(!_checkInit()) return;
2537   MElement *e = GModel::current()->getMeshElementByTag(elementTag);
2538   if(!e) {
2539     Msg::Error("Unknown element %d", elementTag);
2540     return;
2541   }
2542   int numPoints = localCoord.size() / 3;
2543   if(!numPoints) {
2544     Msg::Warning("No evaluation points in getJacobian");
2545     return;
2546   }
2547   std::vector<std::vector<SVector3> > gsf;
2548   gsf.resize(numPoints);
2549   jacobians.resize(9 * numPoints);
2550   determinants.resize(numPoints);
2551   coord.resize(3 * numPoints);
2552   for(int k = 0; k < numPoints; k++) {
2553     double value[1256][3];
2554     e->getGradShapeFunctions(localCoord[3 * k], localCoord[3 * k + 1],
2555                              localCoord[3 * k + 2], value);
2556     gsf[k].resize(e->getNumShapeFunctions());
2557     for(std::size_t l = 0; l < e->getNumShapeFunctions(); l++) {
2558       gsf[k][l][0] = value[l][0];
2559       gsf[k][l][1] = value[l][1];
2560       gsf[k][l][2] = value[l][2];
2561     }
2562   }
2563   for(int k = 0; k < numPoints; k++) {
2564     e->pnt(localCoord[3 * k], localCoord[3 * k + 1], localCoord[3 * k + 2],
2565            &coord[3 * k]);
2566     determinants[k] = e->getJacobian(gsf[k], &jacobians[9 * k]);
2567   }
2568 }
2569 
getBasisFunctions(const int elementType,const std::vector<double> & localCoord,const std::string & functionSpaceType,int & numComponents,std::vector<double> & basisFunctions,int & numOrientations,const std::vector<int> & wantedOrientations)2570 GMSH_API void gmsh::model::mesh::getBasisFunctions(
2571   const int elementType, const std::vector<double> &localCoord,
2572   const std::string &functionSpaceType, int &numComponents,
2573   std::vector<double> &basisFunctions, int &numOrientations,
2574   const std::vector<int> &wantedOrientations)
2575 {
2576   if(!_checkInit()) return;
2577   numComponents = 0;
2578   basisFunctions.clear();
2579   std::string fsName = "";
2580   int fsOrder = 0;
2581   if(!_getFunctionSpaceInfo(functionSpaceType, fsName, fsOrder,
2582                             numComponents)) {
2583     Msg::Error("Unknown function space type '%s'", functionSpaceType.c_str());
2584     return;
2585   }
2586 
2587   const std::size_t numberOfGaussPoints = localCoord.size() / 3;
2588   const int familyType = ElementType::getParentType(elementType);
2589 
2590   if(fsName == "Lagrange" || fsName == "GradLagrange") { // Lagrange type
2591     // Check if there is no error in wantedOrientations
2592     if(wantedOrientations.size() != 0) {
2593       if(wantedOrientations.size() > 1) {
2594         Msg::Error("Asking for more orientation that there exist");
2595         return;
2596       }
2597 
2598       if(wantedOrientations[0] != 0) {
2599         Msg::Error(
2600           "Orientation %i does not exist for function stace named '%s' on %s",
2601           wantedOrientations[0], fsName.c_str(),
2602           ElementType::nameOfParentType(familyType, true).c_str());
2603         return;
2604       }
2605     }
2606 
2607     const nodalBasis *basis = nullptr;
2608     if(numComponents) {
2609       if(fsOrder == -1) { // isoparametric
2610         basis = BasisFactory::getNodalBasis(elementType);
2611       }
2612       else {
2613         int newType = ElementType::getType(familyType, fsOrder, false);
2614         basis = BasisFactory::getNodalBasis(newType);
2615       }
2616     }
2617     if(basis) {
2618       const std::size_t n = basis->getNumShapeFunctions();
2619       basisFunctions.resize(n * numComponents * numberOfGaussPoints, 0.);
2620       double s[1256], ds[1256][3];
2621       for(std::size_t i = 0; i < numberOfGaussPoints; i++) {
2622         double u = localCoord[i * 3];
2623         double v = localCoord[i * 3 + 1];
2624         double w = localCoord[i * 3 + 2];
2625         switch(numComponents) {
2626         case 1:
2627           basis->f(u, v, w, s);
2628           for(std::size_t j = 0; j < n; j++) basisFunctions[n * i + j] = s[j];
2629           break;
2630         case 3:
2631           basis->df(u, v, w, ds);
2632           for(std::size_t j = 0; j < n; j++) {
2633             basisFunctions[n * 3 * i + 3 * j] = ds[j][0];
2634             basisFunctions[n * 3 * i + 3 * j + 1] = ds[j][1];
2635             basisFunctions[n * 3 * i + 3 * j + 2] = ds[j][2];
2636           }
2637           break;
2638         }
2639       }
2640     }
2641     numOrientations = 1;
2642   }
2643   else { // Hierarchical type
2644     HierarchicalBasis *basis(nullptr);
2645     if(fsName == "H1Legendre" || fsName == "GradH1Legendre") {
2646       switch(familyType) {
2647       case TYPE_HEX: {
2648         basis = new HierarchicalBasisH1Brick(fsOrder);
2649       } break;
2650       case TYPE_PRI: {
2651         basis = new HierarchicalBasisH1Pri(fsOrder);
2652       } break;
2653       case TYPE_TET: {
2654         basis = new HierarchicalBasisH1Tetra(fsOrder);
2655       } break;
2656       case TYPE_QUA: {
2657         basis = new HierarchicalBasisH1Quad(fsOrder);
2658       } break;
2659       case TYPE_TRI: {
2660         basis = new HierarchicalBasisH1Tria(fsOrder);
2661       } break;
2662       case TYPE_LIN: {
2663         basis = new HierarchicalBasisH1Line(fsOrder);
2664       } break;
2665       case TYPE_PNT: {
2666         basis = new HierarchicalBasisH1Point();
2667       } break;
2668       default:
2669         Msg::Error("Unknown familyType %i for basis function type %s",
2670                    familyType, fsName.c_str());
2671         return;
2672       }
2673     }
2674     else if(fsName == "HcurlLegendre" || fsName == "CurlHcurlLegendre") {
2675       switch(familyType) {
2676       case TYPE_QUA: {
2677         basis = new HierarchicalBasisHcurlQuad(fsOrder);
2678       } break;
2679       case TYPE_HEX: {
2680         basis = new HierarchicalBasisHcurlBrick(fsOrder);
2681       } break;
2682       case TYPE_TRI: {
2683         basis = new HierarchicalBasisHcurlTria(fsOrder);
2684       } break;
2685       case TYPE_TET: {
2686         basis = new HierarchicalBasisHcurlTetra(fsOrder);
2687       } break;
2688       case TYPE_PRI: {
2689         basis = new HierarchicalBasisHcurlPri(fsOrder);
2690       } break;
2691       case TYPE_LIN: {
2692         basis = new HierarchicalBasisHcurlLine(fsOrder);
2693       } break;
2694       default:
2695         Msg::Error("Unknown familyType %i for basis function type %s",
2696                    familyType, fsName.c_str());
2697         return;
2698       }
2699     }
2700     else {
2701       Msg::Error("Unknown function space named '%s'", fsName.c_str());
2702       return;
2703     }
2704 
2705     const std::size_t vSize = basis->getnVertexFunction();
2706     const std::size_t bSize = basis->getnBubbleFunction();
2707     const std::size_t eSize = basis->getnEdgeFunction();
2708     const std::size_t fSize =
2709       basis->getnTriFaceFunction() + basis->getnQuadFaceFunction();
2710     const std::size_t maxOrientation = basis->getNumberOfOrientations();
2711     numOrientations = maxOrientation;
2712     const std::size_t numFunctionsPerElement = vSize + bSize + eSize + fSize;
2713     const unsigned int numVertices =
2714       ElementType::getNumVertices(ElementType::getType(familyType, 1, false));
2715 
2716     basisFunctions.resize(
2717       (wantedOrientations.size() == 0 ? maxOrientation :
2718                                         wantedOrientations.size()) *
2719       numberOfGaussPoints * numFunctionsPerElement * numComponents);
2720 
2721     // Check if there is no error in wantedOrientations
2722     if(wantedOrientations.size() != 0) {
2723       if(wantedOrientations.size() > maxOrientation) {
2724         Msg::Error("Asking for more orientation that there exist");
2725         return;
2726       }
2727       for(unsigned int i = 0; i < wantedOrientations.size(); ++i) {
2728         if(wantedOrientations[i] >= static_cast<int>(maxOrientation) ||
2729            wantedOrientations[i] < 0) {
2730           Msg::Error("Orientation %i does not exist for function stace named "
2731                      "'%s' on %s",
2732                      wantedOrientations[i], fsName.c_str(),
2733                      ElementType::nameOfParentType(familyType, true).c_str());
2734           return;
2735         }
2736       }
2737       std::vector<int> sortedWantedOrientations = wantedOrientations;
2738       std::sort(sortedWantedOrientations.begin(),
2739                 sortedWantedOrientations.end());
2740       int previousInt = sortedWantedOrientations[0];
2741       for(unsigned int i = 1; i < sortedWantedOrientations.size(); ++i) {
2742         if(previousInt == sortedWantedOrientations[i]) {
2743           Msg::Error("Duplicate wanted orientation found");
2744           return;
2745         }
2746         previousInt = sortedWantedOrientations[i];
2747       }
2748     }
2749 
2750     std::vector<MVertex *> vertices(numVertices);
2751     for(unsigned int i = 0; i < numVertices; ++i) {
2752       vertices[i] = new MVertex(0., 0., 0., nullptr, i + 1);
2753     }
2754     MElement *element = nullptr;
2755     switch(familyType) {
2756     case TYPE_HEX: {
2757       element = new MHexahedron(vertices);
2758     } break;
2759     case TYPE_PRI: {
2760       element = new MPrism(vertices);
2761     } break;
2762     case TYPE_TET: {
2763       element = new MTetrahedron(vertices);
2764     } break;
2765     case TYPE_QUA: {
2766       element = new MQuadrangle(vertices);
2767     } break;
2768     case TYPE_TRI: {
2769       element = new MTriangle(vertices);
2770     } break;
2771     case TYPE_LIN: {
2772       element = new MLine(vertices);
2773     } break;
2774     case TYPE_PNT: {
2775       element = new MPoint(vertices);
2776     } break;
2777     default:
2778       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
2779                  fsName.c_str());
2780       return;
2781     }
2782 
2783     switch(numComponents) {
2784     case 1: {
2785       std::vector<std::vector<double> > vTable(
2786         numberOfGaussPoints,
2787         std::vector<double>(vSize)); // Vertex functions of one element
2788       std::vector<std::vector<double> > bTable(
2789         numberOfGaussPoints,
2790         std::vector<double>(bSize)); // bubble functions of one element
2791       std::vector<std::vector<double> > fTable(
2792         numberOfGaussPoints,
2793         std::vector<double>(fSize)); // face functions of one element
2794       std::vector<std::vector<double> > eTable(
2795         numberOfGaussPoints,
2796         std::vector<double>(eSize)); // edge functions of one element
2797 
2798       for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2799         const double u = localCoord[3 * q];
2800         const double v = localCoord[3 * q + 1];
2801         const double w = localCoord[3 * q + 2];
2802 
2803         basis->generateBasis(u, v, w, vTable[q], eTable[q], fTable[q],
2804                              bTable[q]);
2805       }
2806       // compute only one time the value of the edge basis functions for
2807       // each possible orientations
2808       std::vector<std::vector<double> > eTableNegativeFlag(eTable);
2809       if(eSize != 0) {
2810         for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2811           basis->orientEdgeFunctionsForNegativeFlag(eTableNegativeFlag[q]);
2812         }
2813       }
2814 
2815       // compute only one time the value of the face basis functions for
2816       // each possible orientations
2817       std::vector<std::vector<double> > quadFaceFunctionsAllOrientations(
2818         numberOfGaussPoints,
2819         std::vector<double>(basis->getnQuadFaceFunction() * 8, 0));
2820       std::vector<std::vector<double> > triFaceFunctionsAllOrientations(
2821         numberOfGaussPoints,
2822         std::vector<double>(basis->getnTriFaceFunction() * 6, 0));
2823       if(fSize != 0) {
2824         for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2825           const double u = localCoord[3 * q];
2826           const double v = localCoord[3 * q + 1];
2827           const double w = localCoord[3 * q + 2];
2828 
2829           basis->addAllOrientedFaceFunctions(
2830             u, v, w, fTable[q], quadFaceFunctionsAllOrientations[q],
2831             triFaceFunctionsAllOrientations[q]);
2832         }
2833       }
2834 
2835       std::vector<std::vector<double> > eTableCopy(
2836         numberOfGaussPoints,
2837         std::vector<double>(eSize, 0)); // use eTableCopy to orient the edges
2838       std::vector<std::vector<double> > fTableCopy(
2839         numberOfGaussPoints,
2840         std::vector<double>(fSize, 0)); // use fTableCopy to orient the faces
2841 
2842       unsigned int iOrientationIndex = 0;
2843       for(unsigned int iOrientation = 0; iOrientation < maxOrientation;
2844           ++iOrientation) {
2845         if(wantedOrientations.size() != 0) {
2846           auto it = std::find(wantedOrientations.begin(),
2847                               wantedOrientations.end(), iOrientation);
2848           if(it != wantedOrientations.end()) {
2849             iOrientationIndex = &(*it) - &wantedOrientations[0];
2850           }
2851           else {
2852             MVertexPtrLessThan comp;
2853             std::next_permutation(vertices.begin(), vertices.end(), comp);
2854             for(unsigned int i = 0; i < numVertices; ++i) {
2855               element->setVertex(i, vertices[i]);
2856             }
2857             continue;
2858           }
2859         }
2860         else {
2861           iOrientationIndex = iOrientation;
2862         }
2863 
2864         if(eSize != 0) {
2865           for(int iEdge = 0; iEdge < basis->getNumEdge(); ++iEdge) {
2866             MEdge edge = element->getEdge(iEdge);
2867             MEdge edgeSolin = element->getEdgeSolin(iEdge);
2868             const int orientationFlag =
2869               (edge.getMinVertex() != edgeSolin.getVertex(0)) ? -1 : 1;
2870             for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2871               basis->orientEdge(orientationFlag, iEdge, eTableCopy[q],
2872                                 eTable[q], eTableNegativeFlag[q]);
2873             }
2874           }
2875         }
2876 
2877         if(fSize != 0) {
2878           for(int iFace = 0;
2879               iFace < basis->getNumTriFace() + basis->getNumQuadFace();
2880               ++iFace) {
2881             MFace face = element->getFaceSolin(iFace);
2882             std::vector<int> faceOrientationFlag(3);
2883             face.getOrientationFlagForFace(faceOrientationFlag);
2884             for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2885               basis->orientFace(faceOrientationFlag[0], faceOrientationFlag[1],
2886                                 faceOrientationFlag[2], iFace,
2887                                 quadFaceFunctionsAllOrientations[q],
2888                                 triFaceFunctionsAllOrientations[q],
2889                                 fTableCopy[q]);
2890             }
2891           }
2892         }
2893 
2894         const std::size_t offsetOrientation =
2895           iOrientationIndex * numberOfGaussPoints * numFunctionsPerElement;
2896         for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2897           const std::size_t offsetGP = q * numFunctionsPerElement;
2898 
2899           for(unsigned int i = 0; i < vSize; ++i) {
2900             basisFunctions[offsetOrientation + offsetGP + i] = vTable[q][i];
2901           }
2902           unsigned int offset = vSize;
2903           for(unsigned int i = 0; i < eSize; ++i) {
2904             basisFunctions[offsetOrientation + offsetGP + offset + i] =
2905               eTableCopy[q][i];
2906           }
2907           offset += eSize;
2908           for(unsigned int i = 0; i < fSize; ++i) {
2909             basisFunctions[offsetOrientation + offsetGP + offset + i] =
2910               fTableCopy[q][i];
2911           }
2912           offset += fSize;
2913           for(unsigned int i = 0; i < bSize; ++i) {
2914             basisFunctions[offsetOrientation + offsetGP + offset + i] =
2915               bTable[q][i];
2916           }
2917         }
2918 
2919         MVertexPtrLessThan comp;
2920         std::next_permutation(vertices.begin(), vertices.end(), comp);
2921         for(unsigned int i = 0; i < numVertices; ++i) {
2922           element->setVertex(i, vertices[i]);
2923         }
2924       }
2925       break;
2926     }
2927     case 3: {
2928       std::vector<std::vector<std::vector<double> > > vTable(
2929         numberOfGaussPoints,
2930         std::vector<std::vector<double> >(
2931           vSize,
2932           std::vector<double>(3, 0.))); // Vertex functions of one element
2933       std::vector<std::vector<std::vector<double> > > bTable(
2934         numberOfGaussPoints,
2935         std::vector<std::vector<double> >(
2936           bSize,
2937           std::vector<double>(3, 0.))); // bubble functions of one element
2938       std::vector<std::vector<std::vector<double> > > fTable(
2939         numberOfGaussPoints,
2940         std::vector<std::vector<double> >(
2941           fSize, std::vector<double>(3, 0.))); // face functions of one element
2942       std::vector<std::vector<std::vector<double> > > eTable(
2943         numberOfGaussPoints,
2944         std::vector<std::vector<double> >(
2945           eSize, std::vector<double>(3, 0.))); // edge functions of one element
2946 
2947       for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2948         const double u = localCoord[3 * q];
2949         const double v = localCoord[3 * q + 1];
2950         const double w = localCoord[3 * q + 2];
2951 
2952         basis->generateBasis(u, v, w, vTable[q], eTable[q], fTable[q],
2953                              bTable[q], fsName);
2954       }
2955       // compute only one time the value of the edge basis functions for
2956       // each possible orientations
2957       std::vector<std::vector<std::vector<double> > > eTableNegativeFlag(
2958         eTable);
2959       if(eSize != 0) {
2960         for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2961           basis->orientEdgeFunctionsForNegativeFlag(eTableNegativeFlag[q]);
2962         }
2963       }
2964 
2965       // compute only one time the value of the face basis functions for
2966       // each possible orientations
2967       std::vector<std::vector<std::vector<double> > >
2968         quadFaceFunctionsAllOrientations(
2969           numberOfGaussPoints,
2970           std::vector<std::vector<double> >(basis->getnQuadFaceFunction() * 8,
2971                                             std::vector<double>(3, 0.)));
2972       std::vector<std::vector<std::vector<double> > >
2973         triFaceFunctionsAllOrientations(
2974           numberOfGaussPoints,
2975           std::vector<std::vector<double> >(basis->getnTriFaceFunction() * 6,
2976                                             std::vector<double>(3, 0.)));
2977       if(fSize != 0) {
2978         for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
2979           const double u = localCoord[3 * q];
2980           const double v = localCoord[3 * q + 1];
2981           const double w = localCoord[3 * q + 2];
2982 
2983           basis->addAllOrientedFaceFunctions(
2984             u, v, w, fTable[q], quadFaceFunctionsAllOrientations[q],
2985             triFaceFunctionsAllOrientations[q], fsName);
2986         }
2987       }
2988 
2989       std::vector<std::vector<std::vector<double> > > eTableCopy(
2990         numberOfGaussPoints,
2991         std::vector<std::vector<double> >(
2992           eSize,
2993           std::vector<double>(3, 0.))); // use eTableCopy to orient the edges
2994       std::vector<std::vector<std::vector<double> > > fTableCopy(
2995         numberOfGaussPoints,
2996         std::vector<std::vector<double> >(
2997           fSize,
2998           std::vector<double>(3, 0.))); // use fTableCopy to orient the faces
2999 
3000       unsigned int iOrientationIndex = 0;
3001       for(unsigned int iOrientation = 0; iOrientation < maxOrientation;
3002           ++iOrientation) {
3003         if(wantedOrientations.size() != 0) {
3004           auto it = std::find(wantedOrientations.begin(),
3005                               wantedOrientations.end(), iOrientation);
3006           if(it != wantedOrientations.end()) {
3007             iOrientationIndex = &(*it) - &wantedOrientations[0];
3008           }
3009           else {
3010             MVertexPtrLessThan comp;
3011             std::next_permutation(vertices.begin(), vertices.end(), comp);
3012             for(unsigned int i = 0; i < numVertices; ++i) {
3013               element->setVertex(i, vertices[i]);
3014             }
3015             continue;
3016           }
3017         }
3018         else {
3019           iOrientationIndex = iOrientation;
3020         }
3021 
3022         if(eSize != 0) {
3023           for(int iEdge = 0; iEdge < basis->getNumEdge(); ++iEdge) {
3024             MEdge edge = element->getEdge(iEdge);
3025             MEdge edgeSolin = element->getEdgeSolin(iEdge);
3026             const int orientationFlag =
3027               (edge.getMinVertex() != edgeSolin.getVertex(0) ? -1 : 1);
3028             for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
3029               basis->orientEdge(orientationFlag, iEdge, eTableCopy[q],
3030                                 eTable[q], eTableNegativeFlag[q]);
3031             }
3032           }
3033         }
3034 
3035         if(fSize != 0) {
3036           for(int iFace = 0;
3037               iFace < basis->getNumTriFace() + basis->getNumQuadFace();
3038               ++iFace) {
3039             MFace face = element->getFaceSolin(iFace);
3040             std::vector<int> faceOrientationFlag(3);
3041             face.getOrientationFlagForFace(faceOrientationFlag);
3042             for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
3043               basis->orientFace(faceOrientationFlag[0], faceOrientationFlag[1],
3044                                 faceOrientationFlag[2], iFace,
3045                                 quadFaceFunctionsAllOrientations[q],
3046                                 triFaceFunctionsAllOrientations[q],
3047                                 fTableCopy[q]);
3048             }
3049           }
3050         }
3051 
3052         const std::size_t offsetOrientation =
3053           iOrientationIndex * numberOfGaussPoints * numFunctionsPerElement * 3;
3054         for(unsigned int q = 0; q < numberOfGaussPoints; ++q) {
3055           const std::size_t offsetGP = q * numFunctionsPerElement * 3;
3056 
3057           for(unsigned int i = 0; i < vSize; ++i) {
3058             basisFunctions[offsetOrientation + offsetGP + 3 * i] =
3059               vTable[q][i][0];
3060             basisFunctions[offsetOrientation + offsetGP + 3 * i + 1] =
3061               vTable[q][i][1];
3062             basisFunctions[offsetOrientation + offsetGP + 3 * i + 2] =
3063               vTable[q][i][2];
3064           }
3065           unsigned int offset = 3 * vSize;
3066           for(unsigned int i = 0; i < eSize; ++i) {
3067             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i] =
3068               eTableCopy[q][i][0];
3069             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i + 1] =
3070               eTableCopy[q][i][1];
3071             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i + 2] =
3072               eTableCopy[q][i][2];
3073           }
3074           offset += 3 * eSize;
3075           for(unsigned int i = 0; i < fSize; ++i) {
3076             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i] =
3077               fTableCopy[q][i][0];
3078             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i + 1] =
3079               fTableCopy[q][i][1];
3080             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i + 2] =
3081               fTableCopy[q][i][2];
3082           }
3083           offset += 3 * fSize;
3084           for(unsigned int i = 0; i < bSize; ++i) {
3085             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i] =
3086               bTable[q][i][0];
3087             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i + 1] =
3088               bTable[q][i][1];
3089             basisFunctions[offsetOrientation + offsetGP + offset + 3 * i + 2] =
3090               bTable[q][i][2];
3091           }
3092         }
3093 
3094         MVertexPtrLessThan comp;
3095         std::next_permutation(vertices.begin(), vertices.end(), comp);
3096         for(unsigned int i = 0; i < numVertices; ++i) {
3097           element->setVertex(i, vertices[i]);
3098         }
3099       }
3100       break;
3101     }
3102     }
3103 
3104     for(unsigned int i = 0; i < numVertices; ++i) { delete vertices[i]; }
3105     delete element;
3106     delete basis;
3107   }
3108 
3109   return;
3110 }
3111 
getBasisFunctionsOrientation(const int elementType,const std::string & functionSpaceType,std::vector<int> & basisFunctionsOrientation,const int tag,const std::size_t task,const std::size_t numTasks)3112 GMSH_API void gmsh::model::mesh::getBasisFunctionsOrientation(
3113   const int elementType, const std::string &functionSpaceType,
3114   std::vector<int> &basisFunctionsOrientation, const int tag,
3115   const std::size_t task, const std::size_t numTasks)
3116 {
3117   if(!_checkInit()) return;
3118 
3119   if(!basisFunctionsOrientation.size()) {
3120     if(numTasks > 1) {
3121       Msg::Warning(
3122         "basisFunctionsOrientation should be preallocated if numTasks > 1");
3123     }
3124     preallocateBasisFunctionsOrientation(
3125       elementType, basisFunctionsOrientation, tag);
3126   }
3127 
3128   const int familyType = ElementType::getParentType(elementType);
3129 
3130   int basisOrder = 0;
3131   std::string fsName = "";
3132   int numComponents = 0;
3133   if(!_getFunctionSpaceInfo(functionSpaceType, fsName, basisOrder,
3134                             numComponents)) {
3135     Msg::Error("Unknown function space type '%s'", functionSpaceType.c_str());
3136     return;
3137   }
3138 
3139   const int dim = ElementType::getDimension(elementType);
3140   std::map<int, std::vector<GEntity *> > typeEnt;
3141   _getEntitiesForElementTypes(dim, tag, typeEnt);
3142   const std::vector<GEntity *> &entities(typeEnt[elementType]);
3143 
3144   std::size_t numElements = 0;
3145   for(std::size_t i = 0; i < entities.size(); i++) {
3146     const GEntity *ge = entities[i];
3147     numElements += ge->getNumMeshElementsByType(familyType);
3148   }
3149 
3150   if(numElements != basisFunctionsOrientation.size()) {
3151     Msg::Error("Wrong size of 'basisFunctionsOrientation' vector (%i != %i)",
3152                numElements, basisFunctionsOrientation.size());
3153     return;
3154   }
3155 
3156   if(fsName == "Lagrange" || fsName == "GradLagrange") { // Lagrange type
3157     const std::size_t begin = task * numElements / numTasks;
3158     const std::size_t end = (task + 1) * numElements / numTasks;
3159     for(std::size_t iElement = begin; iElement < end; ++iElement) {
3160       basisFunctionsOrientation[iElement] = 0;
3161     }
3162   }
3163   else { // Hierarchical type
3164     const unsigned int numVertices =
3165       ElementType::getNumVertices(ElementType::getType(familyType, 1, false));
3166     std::vector<MVertex *> vertices(numVertices);
3167     std::vector<unsigned int> verticesOrder(numVertices);
3168     const std::size_t factorial[8] = {1, 1, 2, 6, 24, 120, 720, 5040};
3169 
3170     std::size_t entityOffset = 0;
3171 
3172     for(std::size_t iEntity = 0; iEntity < entities.size(); ++iEntity) {
3173       const GEntity *ge = entities[iEntity];
3174       std::size_t localNumElements = ge->getNumMeshElementsByType(familyType);
3175 
3176       const std::size_t begin = task * localNumElements / numTasks;
3177       const std::size_t end = (task + 1) * localNumElements / numTasks;
3178 
3179       for(std::size_t iElement = begin; iElement < end; ++iElement) {
3180         MElement *e = ge->getMeshElementByType(familyType, iElement);
3181         for(std::size_t i = 0; i < numVertices; ++i) {
3182           vertices[i] = e->getVertex(i);
3183         }
3184 
3185         for(std::size_t i = 0; i < numVertices; ++i) {
3186           std::size_t max = 0;
3187           std::size_t maxPos = 0;
3188           for(std::size_t j = 0; j < numVertices; ++j) {
3189             if(vertices[j] != nullptr) {
3190               if(max < vertices[j]->getNum()) {
3191                 max = vertices[j]->getNum();
3192                 maxPos = j;
3193               }
3194             }
3195           }
3196           vertices[maxPos] = nullptr;
3197           verticesOrder[maxPos] = numVertices - i - 1;
3198         }
3199 
3200         std::size_t elementOrientation = 0;
3201         for(std::size_t i = 0; i < numVertices; ++i) {
3202           elementOrientation +=
3203             verticesOrder[i] * factorial[numVertices - i - 1];
3204           for(std::size_t j = i + 1; j < numVertices; ++j) {
3205             if(verticesOrder[j] > verticesOrder[i]) --verticesOrder[j];
3206           }
3207         }
3208 
3209         basisFunctionsOrientation[entityOffset + iElement] =
3210           (int)elementOrientation;
3211       }
3212 
3213       entityOffset += localNumElements;
3214     }
3215   }
3216 
3217   return;
3218 }
3219 
getBasisFunctionsOrientationForElement(const std::size_t elementTag,const std::string & functionSpaceType,int & basisFunctionsOrientation)3220 GMSH_API void gmsh::model::mesh::getBasisFunctionsOrientationForElement(
3221   const std::size_t elementTag, const std::string &functionSpaceType,
3222   int &basisFunctionsOrientation)
3223 {
3224   if(!_checkInit()) return;
3225 
3226   MElement *e = GModel::current()->getMeshElementByTag(elementTag);
3227   int elementType = e->getTypeForMSH();
3228   int familyType = ElementType::getParentType(elementType);
3229 
3230   int basisOrder = 0;
3231   std::string fsName = "";
3232   int numComponents = 0;
3233   if(!_getFunctionSpaceInfo(functionSpaceType, fsName, basisOrder,
3234                             numComponents)) {
3235     Msg::Error("Unknown function space type '%s'", functionSpaceType.c_str());
3236     return;
3237   }
3238 
3239   if(fsName == "Lagrange" || fsName == "GradLagrange") { // Lagrange type
3240     basisFunctionsOrientation = 0;
3241   }
3242   else { // Hierarchical type
3243     const unsigned int numVertices =
3244       ElementType::getNumVertices(ElementType::getType(familyType, 1, false));
3245     std::vector<MVertex *> vertices(numVertices);
3246     std::vector<unsigned int> verticesOrder(numVertices);
3247     const std::size_t factorial[8] = {1, 1, 2, 6, 24, 120, 720, 5040};
3248 
3249     for(std::size_t i = 0; i < numVertices; ++i) {
3250       vertices[i] = e->getVertex(i);
3251     }
3252 
3253     for(std::size_t i = 0; i < numVertices; ++i) {
3254       std::size_t max = 0;
3255       std::size_t maxPos = 0;
3256       for(std::size_t j = 0; j < numVertices; ++j) {
3257         if(vertices[j] != nullptr) {
3258           if(max < vertices[j]->getNum()) {
3259             max = vertices[j]->getNum();
3260             maxPos = j;
3261           }
3262         }
3263       }
3264       vertices[maxPos] = nullptr;
3265       verticesOrder[maxPos] = numVertices - i - 1;
3266     }
3267 
3268     basisFunctionsOrientation = 0;
3269     for(std::size_t i = 0; i < numVertices; ++i) {
3270       basisFunctionsOrientation +=
3271         verticesOrder[i] * factorial[numVertices - i - 1];
3272       for(std::size_t j = i + 1; j < numVertices; ++j) {
3273         if(verticesOrder[j] > verticesOrder[i]) --verticesOrder[j];
3274       }
3275     }
3276   }
3277 
3278   return;
3279 }
3280 
3281 GMSH_API int
getNumberOfOrientations(const int elementType,const std::string & functionSpaceType)3282 gmsh::model::mesh::getNumberOfOrientations(const int elementType,
3283                                            const std::string &functionSpaceType)
3284 {
3285   if(!_checkInit()) return -1;
3286 
3287   int basisOrder = 0;
3288   std::string fsName = "";
3289   int numComponents = 0;
3290   if(!_getFunctionSpaceInfo(functionSpaceType, fsName, basisOrder,
3291                             numComponents)) {
3292     Msg::Error("Unknown function space type '%s'", functionSpaceType.c_str());
3293     return 0;
3294   }
3295 
3296   if(fsName == "Lagrange" || fsName == "GradLagrange") { // Lagrange type
3297     return 1;
3298   }
3299   else { // Hierarchical type
3300     const int familyType = ElementType::getParentType(elementType);
3301     const unsigned int numVertices =
3302       ElementType::getNumVertices(ElementType::getType(familyType, 1, false));
3303     const std::size_t factorial[8] = {1, 1, 2, 6, 24, 120, 720, 5040};
3304     return factorial[numVertices];
3305   }
3306 
3307   return 0;
3308 }
3309 
3310 GMSH_API void
preallocateBasisFunctionsOrientation(const int elementType,std::vector<int> & basisFunctionsOrientation,const int tag)3311 gmsh::model::mesh::preallocateBasisFunctionsOrientation(
3312   const int elementType, std::vector<int> &basisFunctionsOrientation,
3313   const int tag)
3314 {
3315   if(!_checkInit()) return;
3316 
3317   const int dim = ElementType::getDimension(elementType);
3318   std::map<int, std::vector<GEntity *> > typeEnt;
3319   _getEntitiesForElementTypes(dim, tag, typeEnt);
3320   const std::vector<GEntity *> &entities(typeEnt[elementType]);
3321 
3322   const int familyType = ElementType::getParentType(elementType);
3323 
3324   std::size_t numElements = 0;
3325   for(std::size_t i = 0; i < entities.size(); i++) {
3326     const GEntity *ge = entities[i];
3327     numElements += ge->getNumMeshElementsByType(familyType);
3328   }
3329   if(!numElements) return;
3330   basisFunctionsOrientation.resize(numElements);
3331 }
3332 
3333 GMSH_API void
getEdges(const std::vector<std::size_t> & nodeTags,std::vector<std::size_t> & edgeTags,std::vector<int> & edgeOrientations)3334 gmsh::model::mesh::getEdges(const std::vector<std::size_t> &nodeTags,
3335                             std::vector<std::size_t> &edgeTags,
3336                             std::vector<int> &edgeOrientations)
3337 {
3338   edgeTags.clear();
3339   edgeOrientations.clear();
3340   std::size_t numEdges = nodeTags.size() / 2;
3341   if(!numEdges) return;
3342   edgeTags.resize(numEdges);
3343   edgeOrientations.resize(numEdges);
3344   for(std::size_t i = 0; i < numEdges; i++) {
3345     std::size_t n0 = nodeTags[2 * i];
3346     std::size_t n1 = nodeTags[2 * i + 1];
3347     MVertex *v0 = GModel::current()->getMeshVertexByTag(n0);
3348     MVertex *v1 = GModel::current()->getMeshVertexByTag(n1);
3349     if(v0 && v1) {
3350       MEdge edge;
3351       edgeTags[i] = GModel::current()->getMEdge(v0, v1, edge);
3352       if(edge.getMinVertex() == v0 && edge.getMaxVertex() == v1)
3353         edgeOrientations[i] = 1;
3354       else if(edge.getMaxVertex() == v0 && edge.getMinVertex() == v1)
3355         edgeOrientations[i] = -1;
3356       else
3357         edgeOrientations[i] = 0;
3358     }
3359     else {
3360       Msg::Error("Unknown mesh node %d or %d", n0, n1);
3361     }
3362   }
3363 }
3364 
getFaces(const int faceType,const std::vector<std::size_t> & nodeTags,std::vector<std::size_t> & faceTags,std::vector<int> & orientations)3365 GMSH_API void gmsh::model::mesh::getFaces(
3366   const int faceType, const std::vector<std::size_t> &nodeTags,
3367   std::vector<std::size_t> &faceTags, std::vector<int> &orientations)
3368 {
3369   faceTags.clear();
3370   orientations.clear();
3371   if(faceType != 3 && faceType != 4) {
3372     Msg::Error("Unknown face type (should be 3 or 4)");
3373     return;
3374   }
3375   std::size_t numFaces = nodeTags.size() / faceType;
3376   if(!numFaces) return;
3377   faceTags.resize(numFaces);
3378   orientations.resize(numFaces, 0); // TODO
3379   for(std::size_t i = 0; i < numFaces; i++) {
3380     std::size_t n0 = nodeTags[faceType * i];
3381     std::size_t n1 = nodeTags[faceType * i + 1];
3382     std::size_t n2 = nodeTags[faceType * i + 2];
3383     std::size_t n3 = (faceType == 4) ? nodeTags[faceType * i + 3] : 0;
3384     MVertex *v0 = GModel::current()->getMeshVertexByTag(n0);
3385     MVertex *v1 = GModel::current()->getMeshVertexByTag(n1);
3386     MVertex *v2 = GModel::current()->getMeshVertexByTag(n2);
3387     MVertex *v3 =
3388       (faceType == 4) ? GModel::current()->getMeshVertexByTag(n3) : nullptr;
3389     if(v0 && v1 && v2) {
3390       MFace face;
3391       faceTags[i] = GModel::current()->getMFace(v0, v1, v2, v3, face);
3392     }
3393     else {
3394       Msg::Error("Unknown mesh node %d, %d or %d", n0, n1, n2);
3395     }
3396   }
3397 }
3398 
createEdges(const vectorpair & dimTags)3399 GMSH_API void gmsh::model::mesh::createEdges(const vectorpair &dimTags)
3400 {
3401   if(!_checkInit()) return;
3402   std::vector<GEntity *> entities;
3403   _getEntities(dimTags, entities);
3404   for(std::size_t i = 0; i < entities.size(); i++) {
3405     GEntity *ge = entities[i];
3406     for(std::size_t j = 0; j < ge->getNumMeshElements(); j++) {
3407       MElement *e = ge->getMeshElement(j);
3408       for(int k = 0; k < e->getNumEdges(); k++) {
3409         MEdge edge = e->getEdge(k);
3410         GModel::current()->addMEdge(edge);
3411       }
3412     }
3413   }
3414 }
3415 
createFaces(const vectorpair & dimTags)3416 GMSH_API void gmsh::model::mesh::createFaces(const vectorpair &dimTags)
3417 {
3418   if(!_checkInit()) return;
3419   std::vector<GEntity *> entities;
3420   _getEntities(dimTags, entities);
3421   for(std::size_t i = 0; i < entities.size(); i++) {
3422     GEntity *ge = entities[i];
3423     for(std::size_t j = 0; j < ge->getNumMeshElements(); j++) {
3424       MElement *e = ge->getMeshElement(j);
3425       for(int k = 0; k < e->getNumFaces(); k++) {
3426         MFace face = e->getFace(k);
3427         GModel::current()->addMFace(face);
3428       }
3429     }
3430   }
3431 }
3432 
getAllEdges(std::vector<std::size_t> & edgeTags,std::vector<std::size_t> & edgeNodes)3433 GMSH_API void gmsh::model::mesh::getAllEdges(std::vector<std::size_t> &edgeTags,
3434                                              std::vector<std::size_t> &edgeNodes)
3435 {
3436   if(!_checkInit()) return;
3437   edgeTags.clear();
3438   edgeNodes.clear();
3439   GModel *m = GModel::current();
3440   for(auto it = m->firstMEdge(); it != m->lastMEdge(); ++it) {
3441     edgeTags.push_back(it->second);
3442     edgeNodes.push_back(it->first.getVertex(0)->getNum());
3443     edgeNodes.push_back(it->first.getVertex(1)->getNum());
3444   }
3445 }
3446 
getAllFaces(const int faceType,std::vector<std::size_t> & faceTags,std::vector<std::size_t> & faceNodes)3447 GMSH_API void gmsh::model::mesh::getAllFaces(const int faceType,
3448                                              std::vector<std::size_t> &faceTags,
3449                                              std::vector<std::size_t> &faceNodes)
3450 {
3451   if(!_checkInit()) return;
3452   if(faceType != 3 && faceType != 4) {
3453     Msg::Error("Unknown face type (should be 3 or 4)");
3454     return;
3455   }
3456   faceTags.clear();
3457   faceNodes.clear();
3458   GModel *m = GModel::current();
3459   for(auto it = m->firstMFace(); it != m->lastMFace(); ++it) {
3460     if(faceType == (int)it->first.getNumVertices()) {
3461       faceTags.push_back(it->second);
3462       for(int j = 0; j < faceType; j++)
3463         faceNodes.push_back(it->first.getVertex(j)->getNum());
3464     }
3465   }
3466 }
3467 
addEdges(const std::vector<std::size_t> & edgeTags,const std::vector<std::size_t> & edgeNodes)3468 GMSH_API void gmsh::model::mesh::addEdges(const std::vector<std::size_t> &edgeTags,
3469                                           const std::vector<std::size_t> &edgeNodes)
3470 {
3471   if(!_checkInit()) return;
3472   if(edgeTags.size() * 2 != edgeNodes.size()) {
3473     Msg::Error("Wrong number of edge nodes");
3474     return;
3475   }
3476   GModel *m = GModel::current();
3477   for(std::size_t i = 0; i < edgeTags.size(); i++) {
3478     MVertex *v[2];
3479     for(int j = 0; j < 2; j++) {
3480       v[j] = m->getMeshVertexByTag(edgeNodes[2 * i + j]);
3481       if(!v[j]) {
3482         Msg::Error("Unknown mesh node %lu", edgeNodes[2 * i + j]);
3483         return;
3484       }
3485     }
3486     MEdge e(v[0], v[1]);
3487     m->addMEdge(e, edgeTags[i]);
3488   }
3489 }
3490 
addFaces(const int faceType,const std::vector<std::size_t> & faceTags,const std::vector<std::size_t> & faceNodes)3491 GMSH_API void gmsh::model::mesh::addFaces(const int faceType,
3492                                           const std::vector<std::size_t> &faceTags,
3493                                           const std::vector<std::size_t> &faceNodes)
3494 {
3495   if(!_checkInit()) return;
3496   if(faceType != 3 && faceType != 4) {
3497     Msg::Error("Unknown face type (should be 3 or 4)");
3498     return;
3499   }
3500   if(faceTags.size() * faceType != faceNodes.size()) {
3501     Msg::Error("Wrong number of face nodes");
3502     return;
3503   }
3504   GModel *m = GModel::current();
3505   for(std::size_t i = 0; i < faceTags.size(); i++) {
3506     MVertex *v[4] = {nullptr, nullptr, nullptr, nullptr};
3507     for(int j = 0; j < faceType; j++) {
3508       v[j] = m->getMeshVertexByTag(faceNodes[faceType * i + j]);
3509       if(!v[j]) {
3510         Msg::Error("Unknown mesh node %lu", faceNodes[faceType * i + j]);
3511         return;
3512       }
3513     }
3514     MFace f(v[0], v[1], v[2], v[3]);
3515     m->addMFace(f, faceTags[i]);
3516   }
3517 }
3518 
getKeys(const int elementType,const std::string & functionSpaceType,std::vector<int> & typeKeys,std::vector<std::size_t> & entityKeys,std::vector<double> & coord,const int tag,const bool returnCoord)3519 GMSH_API void gmsh::model::mesh::getKeys(
3520   const int elementType, const std::string &functionSpaceType,
3521   std::vector<int> &typeKeys, std::vector<std::size_t> &entityKeys,
3522   std::vector<double> &coord, const int tag, const bool returnCoord)
3523 {
3524   if(!_checkInit()) return;
3525   coord.clear();
3526   typeKeys.clear();
3527   entityKeys.clear();
3528   int order = 0;
3529   int numComponents = 0;
3530   std::string fsName = "";
3531   if(!_getFunctionSpaceInfo(functionSpaceType, fsName, order, numComponents)) {
3532     Msg::Error("Unknown function space type '%s'", functionSpaceType.c_str());
3533     return;
3534   }
3535   int dim = ElementType::getDimension(elementType);
3536   std::map<int, std::vector<GEntity *> > typeEnt;
3537   _getEntitiesForElementTypes(dim, tag, typeEnt);
3538   const std::vector<GEntity *> &entities(typeEnt[elementType]);
3539   int familyType = ElementType::getParentType(elementType);
3540 
3541   HierarchicalBasis *basis(nullptr);
3542   if(fsName == "H1Legendre" || fsName == "GradH1Legendre") {
3543     switch(familyType) {
3544     case TYPE_HEX: {
3545       basis = new HierarchicalBasisH1Brick(order);
3546     } break;
3547     case TYPE_PRI: {
3548       basis = new HierarchicalBasisH1Pri(order);
3549     } break;
3550     case TYPE_TET: {
3551       basis = new HierarchicalBasisH1Tetra(order);
3552     } break;
3553     case TYPE_QUA: {
3554       basis = new HierarchicalBasisH1Quad(order);
3555     } break;
3556     case TYPE_TRI: {
3557       basis = new HierarchicalBasisH1Tria(order);
3558     } break;
3559     case TYPE_LIN: {
3560       basis = new HierarchicalBasisH1Line(order);
3561     } break;
3562     case TYPE_PNT: {
3563       basis = new HierarchicalBasisH1Point();
3564     } break;
3565     default:
3566       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
3567                  fsName.c_str());
3568       return;
3569     }
3570   }
3571   else if(fsName == "HcurlLegendre" || fsName == "CurlHcurlLegendre") {
3572     switch(familyType) {
3573     case TYPE_QUA: {
3574       basis = new HierarchicalBasisHcurlQuad(order);
3575     } break;
3576     case TYPE_HEX: {
3577       basis = new HierarchicalBasisHcurlBrick(order);
3578     } break;
3579     case TYPE_TRI: {
3580       basis = new HierarchicalBasisHcurlTria(order);
3581     } break;
3582     case TYPE_TET: {
3583       basis = new HierarchicalBasisHcurlTetra(order);
3584     } break;
3585     case TYPE_PRI: {
3586       basis = new HierarchicalBasisHcurlPri(order);
3587     } break;
3588     case TYPE_LIN: {
3589       basis = new HierarchicalBasisHcurlLine(order);
3590     } break;
3591     default:
3592       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
3593                  fsName.c_str());
3594       return;
3595     }
3596   }
3597   else if(fsName == "IsoParametric" || fsName == "Lagrange" ||
3598           fsName == "GradIsoParametric" || fsName == "GradLagrange") {
3599     const nodalBasis *nodalB(nullptr);
3600     if(order == -1) { // isoparametric
3601       nodalB = BasisFactory::getNodalBasis(elementType);
3602     }
3603     else {
3604       int familyType = ElementType::getParentType(elementType);
3605       int newType = ElementType::getType(familyType, order, false);
3606       nodalB = BasisFactory::getNodalBasis(newType);
3607     }
3608 
3609     for(std::size_t i = 0; i < entities.size(); ++i) {
3610       GEntity *ge = entities[i];
3611       std::size_t numElementsInEntitie =
3612         ge->getNumMeshElementsByType(familyType);
3613       if(returnCoord) {
3614         coord.reserve(coord.size() + numElementsInEntitie *
3615                                        nodalB->getNumShapeFunctions() * 3);
3616       }
3617       typeKeys.reserve(typeKeys.size() +
3618                        numElementsInEntitie * nodalB->getNumShapeFunctions());
3619       entityKeys.reserve(entityKeys.size() +
3620                          numElementsInEntitie * nodalB->getNumShapeFunctions());
3621 
3622       for(std::size_t j = 0; j < numElementsInEntitie; ++j) {
3623         MElement *e = ge->getMeshElementByType(familyType, j);
3624         for(size_t k = 0; k < e->getNumVertices(); ++k) {
3625           typeKeys.push_back(0);
3626           entityKeys.push_back(e->getVertex(k)->getNum());
3627           if(returnCoord) {
3628             coord.push_back(e->getVertex(k)->x());
3629             coord.push_back(e->getVertex(k)->y());
3630             coord.push_back(e->getVertex(k)->z());
3631           }
3632         }
3633       }
3634     }
3635     return;
3636   }
3637   else {
3638     Msg::Error("Unknown function space named '%s'", fsName.c_str());
3639     return;
3640   }
3641 
3642   int vSize = basis->getnVertexFunction();
3643   int bSize = basis->getnBubbleFunction();
3644   int eSize = basis->getnEdgeFunction();
3645   int quadFSize = basis->getnQuadFaceFunction();
3646   int triFSize = basis->getnTriFaceFunction();
3647   int fSize = quadFSize + triFSize;
3648   int numDofsPerElement = vSize + bSize + eSize + fSize;
3649   int numberQuadFaces = basis->getNumQuadFace();
3650   int numberTriFaces = basis->getNumTriFace();
3651   int numTriFaceFunction = 0;
3652   if(basis->getNumTriFace() != 0) {
3653     numTriFaceFunction =
3654       triFSize /
3655       basis->getNumTriFace(); // number of Tri face functions for one face
3656   }
3657   int numQuadFaceFunction = 0;
3658   if(basis->getNumQuadFace() != 0) {
3659     numQuadFaceFunction =
3660       quadFSize /
3661       basis->getNumQuadFace(); // number of Tri face functions for one face
3662   }
3663   int numEdgeFunction = 0;
3664   if(basis->getNumEdge() != 0) {
3665     numEdgeFunction =
3666       eSize / basis->getNumEdge(); // number of edge functions for one edge
3667   }
3668   int const1 = numEdgeFunction + 1;
3669   int const2 = const1 + numQuadFaceFunction;
3670   int const3 = const1 + numTriFaceFunction;
3671   int const4 = bSize + std::max(const3, const2);
3672   delete basis;
3673 
3674   for(std::size_t i = 0; i < entities.size(); i++) {
3675     GEntity *ge = entities[i];
3676     std::size_t numElementsInEntitie = ge->getNumMeshElementsByType(familyType);
3677     if(returnCoord) {
3678       coord.reserve(coord.size() +
3679                     numElementsInEntitie * numDofsPerElement * 3);
3680     }
3681     typeKeys.reserve(typeKeys.size() +
3682                      numElementsInEntitie * numDofsPerElement);
3683     entityKeys.reserve(entityKeys.size() +
3684                        numElementsInEntitie * numDofsPerElement);
3685 
3686     for(std::size_t j = 0; j < numElementsInEntitie; j++) {
3687       MElement *e = ge->getMeshElementByType(familyType, j);
3688       // vertices
3689       for(int k = 0; k < vSize; k++) {
3690         typeKeys.push_back(0);
3691         entityKeys.push_back(e->getVertex(k)->getNum());
3692         if(returnCoord) {
3693           coord.push_back(e->getVertex(k)->x());
3694           coord.push_back(e->getVertex(k)->y());
3695           coord.push_back(e->getVertex(k)->z());
3696         }
3697       }
3698       // edges
3699       if(eSize > 0) {
3700         for(int jj = 0; jj < e->getNumEdges(); jj++) {
3701           MEdge edge = e->getEdge(jj);
3702           double coordEdge[3];
3703           if(returnCoord) {
3704             MVertex *v1 = edge.getVertex(0);
3705             MVertex *v2 = edge.getVertex(1);
3706 
3707             coordEdge[0] = 0.5 * (v1->x() + v2->x());
3708             coordEdge[1] = 0.5 * (v1->y() + v2->y());
3709             coordEdge[2] = 0.5 * (v1->z() + v2->z());
3710           }
3711           std::size_t edgeGlobalIndice = GModel::current()->addMEdge(edge);
3712           for(int k = 1; k < const1; k++) {
3713             typeKeys.push_back(k);
3714             entityKeys.push_back(edgeGlobalIndice);
3715             if(returnCoord) {
3716               coord.push_back(coordEdge[0]);
3717               coord.push_back(coordEdge[1]);
3718               coord.push_back(coordEdge[2]);
3719             }
3720           }
3721         }
3722       }
3723       // faces
3724       if(fSize > 0) {
3725         for(int jj = 0; jj < numberQuadFaces + numberTriFaces; jj++) {
3726           // Number the faces
3727           MFace face = e->getFaceSolin(jj);
3728           double coordFace[3] = {0., 0., 0.};
3729           if(returnCoord) {
3730             for(std::size_t indexV = 0; indexV < face.getNumVertices();
3731                 ++indexV) {
3732               coordFace[0] += face.getVertex(indexV)->x();
3733               coordFace[1] += face.getVertex(indexV)->y();
3734               coordFace[2] += face.getVertex(indexV)->z();
3735             }
3736             coordFace[0] /= face.getNumVertices();
3737             coordFace[1] /= face.getNumVertices();
3738             coordFace[2] /= face.getNumVertices();
3739           }
3740           std::size_t faceGlobalIndice = GModel::current()->addMFace(face);
3741           int it2 = const2;
3742           if(jj >= numberQuadFaces) { it2 = const3; }
3743           for(int k = const1; k < it2; k++) {
3744             typeKeys.push_back(k);
3745             entityKeys.push_back(faceGlobalIndice);
3746             if(returnCoord) {
3747               coord.push_back(coordFace[0]);
3748               coord.push_back(coordFace[1]);
3749               coord.push_back(coordFace[2]);
3750             }
3751           }
3752         }
3753       }
3754       // volumes
3755       if(bSize > 0) {
3756         double bubbleCenterCoord[3] = {0., 0., 0.};
3757         if(returnCoord) {
3758           for(unsigned int indexV = 0; indexV < e->getNumVertices(); ++indexV) {
3759             bubbleCenterCoord[0] += e->getVertex(indexV)->x();
3760             bubbleCenterCoord[1] += e->getVertex(indexV)->y();
3761             bubbleCenterCoord[2] += e->getVertex(indexV)->z();
3762           }
3763           bubbleCenterCoord[0] /= e->getNumVertices();
3764           bubbleCenterCoord[1] /= e->getNumVertices();
3765           bubbleCenterCoord[2] /= e->getNumVertices();
3766         }
3767         for(int k = std::max(const3, const2); k < const4; k++) {
3768           typeKeys.push_back(k);
3769           entityKeys.push_back(e->getNum());
3770           if(returnCoord) {
3771             coord.push_back(bubbleCenterCoord[0]);
3772             coord.push_back(bubbleCenterCoord[1]);
3773             coord.push_back(bubbleCenterCoord[2]);
3774           }
3775         }
3776       }
3777     }
3778   }
3779 }
3780 
getKeysForElement(const std::size_t elementTag,const std::string & functionSpaceType,std::vector<int> & typeKeys,std::vector<std::size_t> & entityKeys,std::vector<double> & coord,const bool returnCoord)3781 GMSH_API void gmsh::model::mesh::getKeysForElement(
3782   const std::size_t elementTag, const std::string &functionSpaceType,
3783   std::vector<int> &typeKeys, std::vector<std::size_t> &entityKeys,
3784   std::vector<double> &coord, const bool returnCoord)
3785 {
3786   if(!_checkInit()) return;
3787   coord.clear();
3788   typeKeys.clear();
3789   entityKeys.clear();
3790   int order = 0;
3791   int numComponents = 0;
3792   std::string fsName = "";
3793   if(!_getFunctionSpaceInfo(functionSpaceType, fsName, order, numComponents)) {
3794     Msg::Error("Unknown function space type '%s'", functionSpaceType.c_str());
3795     return;
3796   }
3797   MElement *e = GModel::current()->getMeshElementByTag(elementTag);
3798   int elementType = e->getTypeForMSH();
3799   int familyType = ElementType::getParentType(elementType);
3800 
3801   HierarchicalBasis *basis(nullptr);
3802   if(fsName == "H1Legendre" || fsName == "GradH1Legendre") {
3803     switch(familyType) {
3804     case TYPE_HEX: {
3805       basis = new HierarchicalBasisH1Brick(order);
3806     } break;
3807     case TYPE_PRI: {
3808       basis = new HierarchicalBasisH1Pri(order);
3809     } break;
3810     case TYPE_TET: {
3811       basis = new HierarchicalBasisH1Tetra(order);
3812     } break;
3813     case TYPE_QUA: {
3814       basis = new HierarchicalBasisH1Quad(order);
3815     } break;
3816     case TYPE_TRI: {
3817       basis = new HierarchicalBasisH1Tria(order);
3818     } break;
3819     case TYPE_LIN: {
3820       basis = new HierarchicalBasisH1Line(order);
3821     } break;
3822     case TYPE_PNT: {
3823       basis = new HierarchicalBasisH1Point();
3824     } break;
3825     default:
3826       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
3827                  fsName.c_str());
3828       return;
3829     }
3830   }
3831   else if(fsName == "HcurlLegendre" || fsName == "CurlHcurlLegendre") {
3832     switch(familyType) {
3833     case TYPE_QUA: {
3834       basis = new HierarchicalBasisHcurlQuad(order);
3835     } break;
3836     case TYPE_HEX: {
3837       basis = new HierarchicalBasisHcurlBrick(order);
3838     } break;
3839     case TYPE_TRI: {
3840       basis = new HierarchicalBasisHcurlTria(order);
3841     } break;
3842     case TYPE_TET: {
3843       basis = new HierarchicalBasisHcurlTetra(order);
3844     } break;
3845     case TYPE_PRI: {
3846       basis = new HierarchicalBasisHcurlPri(order);
3847     } break;
3848     case TYPE_LIN: {
3849       basis = new HierarchicalBasisHcurlLine(order);
3850     } break;
3851     default:
3852       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
3853                  fsName.c_str());
3854       return;
3855     }
3856   }
3857   else if(fsName == "IsoParametric" || fsName == "Lagrange" ||
3858           fsName == "GradIsoParametric" || fsName == "GradLagrange") {
3859     typeKeys.reserve(e->getNumVertices());
3860     entityKeys.reserve(e->getNumVertices());
3861     if(returnCoord) { coord.reserve(3 * e->getNumVertices()); }
3862     for(size_t k = 0; k < e->getNumVertices(); ++k) {
3863       typeKeys.push_back(0);
3864       entityKeys.push_back(e->getVertex(k)->getNum());
3865       if(returnCoord) {
3866         coord.push_back(e->getVertex(k)->x());
3867         coord.push_back(e->getVertex(k)->y());
3868         coord.push_back(e->getVertex(k)->z());
3869       }
3870     }
3871     return;
3872   }
3873   else {
3874     Msg::Error("Unknown function space named '%s'", fsName.c_str());
3875     return;
3876   }
3877 
3878   int vSize = basis->getnVertexFunction();
3879   int bSize = basis->getnBubbleFunction();
3880   int eSize = basis->getnEdgeFunction();
3881   int quadFSize = basis->getnQuadFaceFunction();
3882   int triFSize = basis->getnTriFaceFunction();
3883   int fSize = quadFSize + triFSize;
3884   int numberQuadFaces = basis->getNumQuadFace();
3885   int numberTriFaces = basis->getNumTriFace();
3886   int numTriFaceFunction = 0;
3887   if(basis->getNumTriFace() != 0) {
3888     numTriFaceFunction =
3889       triFSize /
3890       basis->getNumTriFace(); // number of Tri face functions for one face
3891   }
3892   int numQuadFaceFunction = 0;
3893   if(basis->getNumQuadFace() != 0) {
3894     numQuadFaceFunction =
3895       quadFSize /
3896       basis->getNumQuadFace(); // number of Tri face functions for one face
3897   }
3898   int numEdgeFunction = 0;
3899   if(basis->getNumEdge() != 0) {
3900     numEdgeFunction =
3901       eSize / basis->getNumEdge(); // number of edge functions for one edge
3902   }
3903   int const1 = numEdgeFunction + 1;
3904   int const2 = const1 + numQuadFaceFunction;
3905   int const3 = const1 + numTriFaceFunction;
3906   int const4 = bSize + std::max(const3, const2);
3907   int numDofsPerElement = vSize + bSize + eSize + fSize;
3908   delete basis;
3909 
3910   typeKeys.reserve(numDofsPerElement);
3911   entityKeys.reserve(numDofsPerElement);
3912   if(returnCoord) { coord.reserve(3 * numDofsPerElement); }
3913 
3914   // vertices
3915   for(int k = 0; k < vSize; k++) {
3916     typeKeys.push_back(0);
3917     entityKeys.push_back(e->getVertex(k)->getNum());
3918     if(returnCoord) {
3919       coord.push_back(e->getVertex(k)->x());
3920       coord.push_back(e->getVertex(k)->y());
3921       coord.push_back(e->getVertex(k)->z());
3922     }
3923   }
3924   // edges
3925   if(eSize > 0) {
3926     for(int jj = 0; jj < e->getNumEdges(); jj++) {
3927       MEdge edge = e->getEdge(jj);
3928       double coordEdge[3];
3929       if(returnCoord) {
3930         MVertex *v1 = edge.getVertex(0);
3931         MVertex *v2 = edge.getVertex(1);
3932 
3933         coordEdge[0] = 0.5 * (v1->x() + v2->x());
3934         coordEdge[1] = 0.5 * (v1->y() + v2->y());
3935         coordEdge[2] = 0.5 * (v1->z() + v2->z());
3936       }
3937       std::size_t edgeGlobalIndice = GModel::current()->addMEdge(edge);
3938       for(int k = 1; k < const1; k++) {
3939         typeKeys.push_back(k);
3940         entityKeys.push_back(edgeGlobalIndice);
3941         if(returnCoord) {
3942           coord.push_back(coordEdge[0]);
3943           coord.push_back(coordEdge[1]);
3944           coord.push_back(coordEdge[2]);
3945         }
3946       }
3947     }
3948   }
3949   // faces
3950   if(fSize > 0) {
3951     for(int jj = 0; jj < numberQuadFaces + numberTriFaces; jj++) {
3952       // Number the faces
3953       MFace face = e->getFaceSolin(jj);
3954       double coordFace[3] = {0., 0., 0.};
3955       if(returnCoord) {
3956         for(std::size_t indexV = 0; indexV < face.getNumVertices(); ++indexV) {
3957           coordFace[0] += face.getVertex(indexV)->x();
3958           coordFace[1] += face.getVertex(indexV)->y();
3959           coordFace[2] += face.getVertex(indexV)->z();
3960         }
3961         coordFace[0] /= face.getNumVertices();
3962         coordFace[1] /= face.getNumVertices();
3963         coordFace[2] /= face.getNumVertices();
3964       }
3965       std::size_t faceGlobalIndice = GModel::current()->addMFace(face);
3966       int it2 = const2;
3967       if(jj >= numberQuadFaces) { it2 = const3; }
3968       for(int k = const1; k < it2; k++) {
3969         typeKeys.push_back(k);
3970         entityKeys.push_back(faceGlobalIndice);
3971         if(returnCoord) {
3972           coord.push_back(coordFace[0]);
3973           coord.push_back(coordFace[1]);
3974           coord.push_back(coordFace[2]);
3975         }
3976       }
3977     }
3978   }
3979   // volumes
3980   if(bSize > 0) {
3981     double bubbleCenterCoord[3] = {0., 0., 0.};
3982     if(returnCoord) {
3983       for(unsigned int indexV = 0; indexV < e->getNumVertices(); ++indexV) {
3984         bubbleCenterCoord[0] += e->getVertex(indexV)->x();
3985         bubbleCenterCoord[1] += e->getVertex(indexV)->y();
3986         bubbleCenterCoord[2] += e->getVertex(indexV)->z();
3987       }
3988       bubbleCenterCoord[0] /= e->getNumVertices();
3989       bubbleCenterCoord[1] /= e->getNumVertices();
3990       bubbleCenterCoord[2] /= e->getNumVertices();
3991     }
3992     for(int k = std::max(const3, const2); k < const4; k++) {
3993       typeKeys.push_back(k);
3994       entityKeys.push_back(e->getNum());
3995       if(returnCoord) {
3996         coord.push_back(bubbleCenterCoord[0]);
3997         coord.push_back(bubbleCenterCoord[1]);
3998         coord.push_back(bubbleCenterCoord[2]);
3999       }
4000     }
4001   }
4002 }
4003 
getNumberOfKeys(const int elementType,const std::string & functionSpaceType)4004 GMSH_API int gmsh::model::mesh::getNumberOfKeys(
4005   const int elementType, const std::string &functionSpaceType)
4006 {
4007   int numberOfKeys = 0;
4008   int basisOrder = 0;
4009   std::string fsName = "";
4010   int numComponents = 0;
4011   if(!_getFunctionSpaceInfo(functionSpaceType, fsName, basisOrder,
4012                             numComponents)) {
4013     Msg::Error("Unknown function space type '%s'", functionSpaceType.c_str());
4014     return 0;
4015   }
4016   int familyType = ElementType::getParentType(elementType);
4017   if(fsName == "H1Legendre" || fsName == "GradH1Legendre") {
4018     HierarchicalBasis *basis(nullptr);
4019     switch(familyType) {
4020     case TYPE_HEX: {
4021       basis = new HierarchicalBasisH1Brick(basisOrder);
4022     } break;
4023     case TYPE_PRI: {
4024       basis = new HierarchicalBasisH1Pri(basisOrder);
4025     } break;
4026     case TYPE_TET: {
4027       basis = new HierarchicalBasisH1Tetra(basisOrder);
4028     } break;
4029     case TYPE_QUA: {
4030       basis = new HierarchicalBasisH1Quad(basisOrder);
4031     } break;
4032     case TYPE_TRI: {
4033       basis = new HierarchicalBasisH1Tria(basisOrder);
4034     } break;
4035     case TYPE_LIN: {
4036       basis = new HierarchicalBasisH1Line(basisOrder);
4037     } break;
4038     case TYPE_PNT: {
4039       basis = new HierarchicalBasisH1Point();
4040     } break;
4041     default:
4042       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
4043                  fsName.c_str());
4044       return 0;
4045     }
4046     int vSize = basis->getnVertexFunction();
4047     int bSize = basis->getnBubbleFunction();
4048     int eSize = basis->getnEdgeFunction();
4049     int quadFSize = basis->getnQuadFaceFunction();
4050     int triFSize = basis->getnTriFaceFunction();
4051     numberOfKeys = vSize + bSize + eSize + quadFSize + triFSize;
4052     delete basis;
4053   }
4054   else if(fsName == "HcurlLegendre" || fsName == "CurlHcurlLegendre") {
4055     HierarchicalBasis *basis(nullptr);
4056     switch(familyType) {
4057     case TYPE_QUA: {
4058       basis = new HierarchicalBasisHcurlQuad(basisOrder);
4059     } break;
4060     case TYPE_HEX: {
4061       basis = new HierarchicalBasisHcurlBrick(basisOrder);
4062     } break;
4063     case TYPE_TRI: {
4064       basis = new HierarchicalBasisHcurlTria(basisOrder);
4065     } break;
4066     case TYPE_TET: {
4067       basis = new HierarchicalBasisHcurlTetra(basisOrder);
4068     } break;
4069     case TYPE_PRI: {
4070       basis = new HierarchicalBasisHcurlPri(basisOrder);
4071     } break;
4072     case TYPE_LIN: {
4073       basis = new HierarchicalBasisHcurlLine(basisOrder);
4074     } break;
4075     default:
4076       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
4077                  fsName.c_str());
4078       return 0;
4079     }
4080     int vSize = basis->getnVertexFunction();
4081     int bSize = basis->getnBubbleFunction();
4082     int eSize = basis->getnEdgeFunction();
4083     int quadFSize = basis->getnQuadFaceFunction();
4084     int triFSize = basis->getnTriFaceFunction();
4085     numberOfKeys = vSize + bSize + eSize + quadFSize + triFSize;
4086     delete basis;
4087   }
4088   else if(fsName == "IsoParametric" || fsName == "Lagrange" ||
4089           fsName == "GradIsoParametric" || fsName == "GradLagrange") {
4090     const nodalBasis *basis(nullptr);
4091     if(basisOrder == -1) { // isoparametric
4092       basis = BasisFactory::getNodalBasis(elementType);
4093     }
4094     else {
4095       int familyType = ElementType::getParentType(elementType);
4096       int newType = ElementType::getType(familyType, basisOrder, false);
4097       basis = BasisFactory::getNodalBasis(newType);
4098     }
4099     numberOfKeys = basis->getNumShapeFunctions();
4100   }
4101   else {
4102     Msg::Error("Unknown function space named '%s'", fsName.c_str());
4103     return 0;
4104   }
4105 
4106   return numberOfKeys;
4107 }
4108 
getKeysInformation(const std::vector<int> & typeKeys,const std::vector<std::size_t> & entityKeys,const int elementType,const std::string & functionSpaceType,gmsh::vectorpair & infoKeys)4109 GMSH_API void gmsh::model::mesh::getKeysInformation(
4110   const std::vector<int> &typeKeys, const std::vector<std::size_t> &entityKeys,
4111   const int elementType, const std::string &functionSpaceType,
4112   gmsh::vectorpair &infoKeys)
4113 {
4114   infoKeys.clear();
4115   int basisOrder = 0;
4116   std::string fsName = "";
4117   int numComponents = 0;
4118   if(!_getFunctionSpaceInfo(functionSpaceType, fsName, basisOrder,
4119                             numComponents)) {
4120     Msg::Error("Unknown function space type '%s'", functionSpaceType.c_str());
4121     return;
4122   }
4123 
4124   if(typeKeys.size() != entityKeys.size()) {
4125     Msg::Error("The size of 'typeKeys' is different of the size of "
4126                "'entityKeys' ('%i', '%i')",
4127                typeKeys.size(), entityKeys.size());
4128     return;
4129   }
4130 
4131   HierarchicalBasis *basis(nullptr);
4132   int familyType = ElementType::getParentType(elementType);
4133   if(fsName == "H1Legendre" || fsName == "GradH1Legendre") {
4134     switch(familyType) {
4135     case TYPE_HEX: {
4136       basis = new HierarchicalBasisH1Brick(basisOrder);
4137     } break;
4138     case TYPE_PRI: {
4139       basis = new HierarchicalBasisH1Pri(basisOrder);
4140     } break;
4141     case TYPE_TET: {
4142       basis = new HierarchicalBasisH1Tetra(basisOrder);
4143     } break;
4144     case TYPE_QUA: {
4145       basis = new HierarchicalBasisH1Quad(basisOrder);
4146     } break;
4147     case TYPE_TRI: {
4148       basis = new HierarchicalBasisH1Tria(basisOrder);
4149     } break;
4150     case TYPE_LIN: {
4151       basis = new HierarchicalBasisH1Line(basisOrder);
4152     } break;
4153     case TYPE_PNT: {
4154       basis = new HierarchicalBasisH1Point();
4155     } break;
4156     default:
4157       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
4158                  fsName.c_str());
4159       return;
4160     }
4161   }
4162   else if(fsName == "HcurlLegendre" || fsName == "CurlHcurlLegendre") {
4163     switch(familyType) {
4164     case TYPE_QUA: {
4165       basis = new HierarchicalBasisHcurlQuad(basisOrder);
4166     } break;
4167     case TYPE_HEX: {
4168       basis = new HierarchicalBasisHcurlBrick(basisOrder);
4169     } break;
4170     case TYPE_TRI: {
4171       basis = new HierarchicalBasisHcurlTria(basisOrder);
4172     } break;
4173     case TYPE_TET: {
4174       basis = new HierarchicalBasisHcurlTetra(basisOrder);
4175     } break;
4176     case TYPE_PRI: {
4177       basis = new HierarchicalBasisHcurlPri(basisOrder);
4178     } break;
4179     case TYPE_LIN: {
4180       basis = new HierarchicalBasisHcurlLine(basisOrder);
4181     } break;
4182     default:
4183       Msg::Error("Unknown familyType %i for basis function type %s", familyType,
4184                  fsName.c_str());
4185       return;
4186     }
4187   }
4188   else if(fsName == "IsoParametric" || fsName == "Lagrange" ||
4189           fsName == "GradIsoParametric" || fsName == "GradLagrange") {
4190     const nodalBasis *basis(nullptr);
4191     if(basisOrder == -1) { // isoparametric
4192       basis = BasisFactory::getNodalBasis(elementType);
4193     }
4194     else {
4195       int familyType = ElementType::getParentType(elementType);
4196       int newType = ElementType::getType(familyType, basisOrder, false);
4197       basis = BasisFactory::getNodalBasis(newType);
4198     }
4199     std::size_t numberOfKeys = basis->getNumShapeFunctions();
4200     std::size_t numberOfBubble = basis->getNumBubbleShapeFunctions();
4201     int dim = ElementType::getDimension(elementType);
4202 
4203     if(numberOfBubble > numberOfKeys) {
4204       Msg::Error("Number of bubble functions greater than number of keys");
4205       return;
4206     }
4207 
4208     infoKeys.reserve(typeKeys.size());
4209     for(size_t i = 0; i < typeKeys.size() / numberOfKeys; ++i) {
4210       for(size_t j = 0; j < numberOfKeys - numberOfBubble; ++j) {
4211         infoKeys.push_back(std::make_pair(0, basisOrder));
4212       }
4213       for(size_t j = 0; j < numberOfBubble; ++j) {
4214         infoKeys.push_back(std::make_pair(dim, basisOrder));
4215       }
4216     }
4217     return;
4218   }
4219   else {
4220     Msg::Error("Unknown function space named '%s'", fsName.c_str());
4221     return;
4222   }
4223 
4224   int vSize = basis->getnVertexFunction();
4225   int bSize = basis->getnBubbleFunction();
4226   int eSize = basis->getnEdgeFunction();
4227   int quadFSize = basis->getnQuadFaceFunction();
4228   int triFSize = basis->getnTriFaceFunction();
4229   int numDofsPerElement = vSize + bSize + eSize + quadFSize + triFSize;
4230   std::vector<int> functionTypeInfo(numDofsPerElement);
4231   std::vector<int> orderInfo(numDofsPerElement);
4232   basis->getKeysInfo(functionTypeInfo, orderInfo);
4233   delete basis;
4234   std::size_t keySize = typeKeys.size();
4235   infoKeys.resize(keySize);
4236   std::size_t it = keySize / numDofsPerElement;
4237   for(std::size_t i = 0; i < it; i++) {
4238     size_t const1 = i * numDofsPerElement;
4239     for(int j = 0; j < numDofsPerElement; j++) {
4240       infoKeys[const1 + j] =
4241         std::make_pair(functionTypeInfo[j], orderInfo[j]);
4242     }
4243   }
4244 }
4245 
getBarycenters(const int elementType,const int tag,const bool fast,const bool primary,std::vector<double> & barycenters,const std::size_t task,const std::size_t numTasks)4246 GMSH_API void gmsh::model::mesh::getBarycenters(
4247   const int elementType, const int tag, const bool fast, const bool primary,
4248   std::vector<double> &barycenters, const std::size_t task,
4249   const std::size_t numTasks)
4250 {
4251   if(!_checkInit()) return;
4252   int dim = ElementType::getDimension(elementType);
4253   std::map<int, std::vector<GEntity *> > typeEnt;
4254   _getEntitiesForElementTypes(dim, tag, typeEnt);
4255   const std::vector<GEntity *> &entities(typeEnt[elementType]);
4256   int familyType = ElementType::getParentType(elementType);
4257   std::size_t numElements = 0;
4258   for(std::size_t i = 0; i < entities.size(); i++) {
4259     GEntity *ge = entities[i];
4260     numElements += ge->getNumMeshElementsByType(familyType);
4261   }
4262   if(!numTasks) {
4263     Msg::Error("Number of tasks should be > 0");
4264     return;
4265   }
4266   const size_t begin = (task * numElements) / numTasks;
4267   const size_t end = ((task + 1) * numElements) / numTasks;
4268   if(3 * end > barycenters.size()) {
4269     if(numTasks > 1)
4270       Msg::Warning("Barycenters should be preallocated if numTasks > 1");
4271     barycenters.resize(3 * numElements);
4272   }
4273   size_t o = 0;
4274   size_t idx = 3 * begin;
4275   if(fast) {
4276     for(std::size_t i = 0; i < entities.size(); i++) {
4277       GEntity *ge = entities[i];
4278       for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType);
4279           j++) {
4280         if(o >= begin && o < end) {
4281           MElement *e = ge->getMeshElementByType(familyType, j);
4282           SPoint3 p = e->fastBarycenter(primary);
4283           barycenters[idx++] = p[0];
4284           barycenters[idx++] = p[1];
4285           barycenters[idx++] = p[2];
4286         }
4287         o++;
4288       }
4289     }
4290   }
4291   else {
4292     for(std::size_t i = 0; i < entities.size(); i++) {
4293       GEntity *ge = entities[i];
4294       for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType);
4295           j++) {
4296         if(o >= begin && o < end) {
4297           MElement *e = ge->getMeshElementByType(familyType, j);
4298           SPoint3 p = e->barycenter(primary);
4299           barycenters[idx++] = p[0];
4300           barycenters[idx++] = p[1];
4301           barycenters[idx++] = p[2];
4302         }
4303         o++;
4304       }
4305     }
4306   }
4307 }
4308 
_getIntegrationInfo(const std::string & intType,std::string & intName,int & intOrder)4309 static bool _getIntegrationInfo(const std::string &intType,
4310                                 std::string &intName, int &intOrder)
4311 {
4312   if(intType.substr(0, 14) == "CompositeGauss") {
4313     intName = "CompositeGauss";
4314     intOrder = atoi(intType.substr(14).c_str());
4315     return true;
4316   }
4317   else if(intType.substr(0, 5) == "Gauss") {
4318     intName = "Gauss";
4319     intOrder = atoi(intType.substr(5).c_str());
4320     return true;
4321   }
4322   return false;
4323 }
4324 
getIntegrationPoints(const int elementType,const std::string & integrationType,std::vector<double> & localCoord,std::vector<double> & weights)4325 GMSH_API void gmsh::model::mesh::getIntegrationPoints(
4326   const int elementType, const std::string &integrationType,
4327   std::vector<double> &localCoord, std::vector<double> &weights)
4328 {
4329   if(!_checkInit()) return;
4330   localCoord.clear();
4331   weights.clear();
4332   std::string intName = "";
4333   int intOrder = 0;
4334   if(!_getIntegrationInfo(integrationType, intName, intOrder)) {
4335     Msg::Error("Unknown quadrature type '%s'", integrationType.c_str());
4336     return;
4337   }
4338   // get quadrature info
4339   int familyType = ElementType::getParentType(elementType);
4340   fullMatrix<double> pts;
4341   fullVector<double> wgs;
4342   gaussIntegration::get(familyType, intOrder, pts, wgs,
4343                         intName == "Gauss" ? false : true);
4344   if(pts.size1() != wgs.size() || pts.size2() != 3) {
4345     Msg::Error("Wrong integration point format");
4346     return;
4347   }
4348   localCoord.resize(3 * pts.size1());
4349   weights.resize(pts.size1());
4350   for(int i = 0; i < pts.size1(); i++) {
4351     localCoord[3 * i] = pts(i, 0);
4352     localCoord[3 * i + 1] = pts(i, 1);
4353     localCoord[3 * i + 2] = pts(i, 2);
4354     weights[i] = wgs(i);
4355   }
4356 }
4357 
preallocateBarycenters(const int elementType,std::vector<double> & barycenters,const int tag)4358 GMSH_API void gmsh::model::mesh::preallocateBarycenters(
4359   const int elementType, std::vector<double> &barycenters, const int tag)
4360 {
4361   if(!_checkInit()) return;
4362   int dim = ElementType::getDimension(elementType);
4363   std::map<int, std::vector<GEntity *> > typeEnt;
4364   _getEntitiesForElementTypes(dim, tag, typeEnt);
4365   const std::vector<GEntity *> &entities(typeEnt[elementType]);
4366   int familyType = ElementType::getParentType(elementType);
4367   std::size_t numElements = 0;
4368   for(std::size_t i = 0; i < entities.size(); i++)
4369     numElements += entities[i]->getNumMeshElementsByType(familyType);
4370   barycenters.clear();
4371   barycenters.resize(3 * numElements, 0);
4372 }
4373 
getElementEdgeNodes(const int elementType,std::vector<std::size_t> & nodeTags,const int tag,const bool primary,const std::size_t task,const std::size_t numTasks)4374 GMSH_API void gmsh::model::mesh::getElementEdgeNodes(
4375   const int elementType, std::vector<std::size_t> &nodeTags, const int tag,
4376   const bool primary, const std::size_t task, const std::size_t numTasks)
4377 {
4378   if(!_checkInit()) return;
4379   int dim = ElementType::getDimension(elementType);
4380   std::map<int, std::vector<GEntity *> > typeEnt;
4381   _getEntitiesForElementTypes(dim, tag, typeEnt);
4382   const std::vector<GEntity *> &entities(typeEnt[elementType]);
4383   int familyType = ElementType::getParentType(elementType);
4384   std::size_t numElements = 0;
4385   int numEdgesPerEle = 0, numNodesPerEdge = 0;
4386   for(std::size_t i = 0; i < entities.size(); i++) {
4387     GEntity *ge = entities[i];
4388     int n = ge->getNumMeshElementsByType(familyType);
4389     if(n && !numNodesPerEdge) {
4390       MElement *e = ge->getMeshElementByType(familyType, 0);
4391       numEdgesPerEle = e->getNumEdges();
4392       if(primary) { numNodesPerEdge = 2; }
4393       else {
4394         std::vector<MVertex *> v;
4395         // we could use e->getHighOrderEdge() here if we decide to remove
4396         // getEdgeVertices
4397         e->getEdgeVertices(0, v);
4398         numNodesPerEdge = v.size();
4399       }
4400     }
4401     numElements += n;
4402   }
4403   if(!numTasks) {
4404     Msg::Error("Number of tasks should be > 0");
4405     return;
4406   }
4407   const size_t begin = (task * numElements) / numTasks;
4408   const size_t end = ((task + 1) * numElements) / numTasks;
4409   if(numEdgesPerEle * numNodesPerEdge * end > nodeTags.size()) {
4410     if(numTasks > 1)
4411       Msg::Warning("Nodes should be preallocated if numTasks > 1");
4412     nodeTags.resize(numEdgesPerEle * numNodesPerEdge * numElements);
4413   }
4414   size_t o = 0;
4415   size_t idx = numEdgesPerEle * numNodesPerEdge * begin;
4416   for(std::size_t i = 0; i < entities.size(); i++) {
4417     GEntity *ge = entities[i];
4418     for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType); j++) {
4419       if(o >= begin && o < end) {
4420         MElement *e = ge->getMeshElementByType(familyType, j);
4421         for(int k = 0; k < numEdgesPerEle; k++) {
4422           std::vector<MVertex *> v;
4423           // we could use e->getHighOrderEdge() here if we decide to remove
4424           // getEdgeVertices
4425           e->getEdgeVertices(k, v);
4426           std::size_t N = primary ? 2 : v.size();
4427           for(std::size_t l = 0; l < N; l++) {
4428             nodeTags[idx++] = v[l]->getNum();
4429           }
4430         }
4431       }
4432       o++;
4433     }
4434   }
4435 }
4436 
getElementFaceNodes(const int elementType,const int faceType,std::vector<std::size_t> & nodeTags,const int tag,const bool primary,const std::size_t task,const std::size_t numTasks)4437 GMSH_API void gmsh::model::mesh::getElementFaceNodes(
4438   const int elementType, const int faceType, std::vector<std::size_t> &nodeTags,
4439   const int tag, const bool primary, const std::size_t task,
4440   const std::size_t numTasks)
4441 {
4442   if(!_checkInit()) return;
4443   int dim = ElementType::getDimension(elementType);
4444   std::map<int, std::vector<GEntity *> > typeEnt;
4445   _getEntitiesForElementTypes(dim, tag, typeEnt);
4446   const std::vector<GEntity *> &entities(typeEnt[elementType]);
4447   int familyType = ElementType::getParentType(elementType);
4448   std::size_t numElements = 0;
4449   int numFacesPerEle = 0, numNodesPerFace = 0;
4450   for(std::size_t i = 0; i < entities.size(); i++) {
4451     GEntity *ge = entities[i];
4452     int n = ge->getNumMeshElementsByType(familyType);
4453     if(n && !numNodesPerFace) {
4454       MElement *e = ge->getMeshElementByType(familyType, 0);
4455       int nf = e->getNumFaces();
4456       numFacesPerEle = 0;
4457       for(int j = 0; j < nf; j++) {
4458         MFace f = e->getFace(j);
4459         if(faceType == (int)f.getNumVertices()) numFacesPerEle++;
4460       }
4461       if(primary) { numNodesPerFace = faceType; }
4462       else {
4463         std::vector<MVertex *> v;
4464         // we could use e->getHighOrderFace() here if we decide to remove
4465         // getFaceVertices
4466         e->getFaceVertices(0, v);
4467         numNodesPerFace = v.size();
4468       }
4469     }
4470     numElements += n;
4471   }
4472   if(!numTasks) {
4473     Msg::Error("Number of tasks should be > 0");
4474     return;
4475   }
4476   const size_t begin = (task * numElements) / numTasks;
4477   const size_t end = ((task + 1) * numElements) / numTasks;
4478   if(numFacesPerEle * numNodesPerFace * end > nodeTags.size()) {
4479     if(numTasks > 1)
4480       Msg::Warning("Nodes should be preallocated if numTasks > 1");
4481     nodeTags.resize(numFacesPerEle * numNodesPerFace * numElements);
4482   }
4483   size_t o = 0;
4484   size_t idx = numFacesPerEle * numNodesPerFace * begin;
4485   for(std::size_t i = 0; i < entities.size(); i++) {
4486     GEntity *ge = entities[i];
4487     for(std::size_t j = 0; j < ge->getNumMeshElementsByType(familyType); j++) {
4488       if(o >= begin && o < end) {
4489         MElement *e = ge->getMeshElementByType(familyType, j);
4490         int nf = e->getNumFaces();
4491         for(int k = 0; k < nf; k++) {
4492           MFace f = e->getFace(k);
4493           if(faceType != (int)f.getNumVertices()) continue;
4494           std::vector<MVertex *> v;
4495           // we could use e->getHighOrderFace() here if we decide to remove
4496           // getFaceVertices
4497           e->getFaceVertices(k, v);
4498           std::size_t N = primary ? faceType : v.size();
4499           for(std::size_t l = 0; l < N; l++) {
4500             nodeTags[idx++] = v[l]->getNum();
4501           }
4502         }
4503       }
4504       o++;
4505     }
4506   }
4507 }
4508 
4509 GMSH_API void
getGhostElements(const int dim,const int tag,std::vector<std::size_t> & elementTags,std::vector<int> & partitions)4510 gmsh::model::mesh::getGhostElements(const int dim, const int tag,
4511                                     std::vector<std::size_t> &elementTags,
4512                                     std::vector<int> &partitions)
4513 {
4514   if(!_checkInit()) return;
4515   elementTags.clear();
4516   partitions.clear();
4517   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
4518   if(!ge) {
4519     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4520     return;
4521   }
4522   std::map<MElement *, int> ghostCells;
4523   if(ge->geomType() == GEntity::GhostCurve)
4524     ghostCells = static_cast<ghostEdge *>(ge)->getGhostCells();
4525   else if(ge->geomType() == GEntity::GhostSurface)
4526     ghostCells = static_cast<ghostFace *>(ge)->getGhostCells();
4527   else if(ge->geomType() == GEntity::GhostVolume)
4528     ghostCells = static_cast<ghostRegion *>(ge)->getGhostCells();
4529 
4530   for(auto it = ghostCells.begin(); it != ghostCells.end(); it++) {
4531     elementTags.push_back(it->first->getNum());
4532     partitions.push_back(it->second);
4533   }
4534 }
4535 
setSize(const vectorpair & dimTags,const double size)4536 GMSH_API void gmsh::model::mesh::setSize(const vectorpair &dimTags,
4537                                          const double size)
4538 {
4539   if(!_checkInit()) return;
4540   for(std::size_t i = 0; i < dimTags.size(); i++) {
4541     int dim = dimTags[i].first, tag = dimTags[i].second;
4542     if(dim == 0) {
4543       GVertex *gv = GModel::current()->getVertexByTag(tag);
4544       if(gv) gv->setPrescribedMeshSizeAtVertex(size);
4545     }
4546   }
4547 }
4548 
getSizes(const vectorpair & dimTags,std::vector<double> & sizes)4549 GMSH_API void gmsh::model::mesh::getSizes(const vectorpair &dimTags,
4550                                           std::vector<double> &sizes)
4551 {
4552   if(!_checkInit()) return;
4553   sizes.clear();
4554   if(dimTags.empty()) return;
4555   sizes.resize(dimTags.size(), 0.);
4556   for(std::size_t i = 0; i < dimTags.size(); i++) {
4557     int dim = dimTags[i].first, tag = dimTags[i].second;
4558     if(dim == 0) {
4559       GVertex *gv = GModel::current()->getVertexByTag(tag);
4560       if(gv) {
4561         double s = gv->prescribedMeshSizeAtVertex();
4562         if(s != MAX_LC) sizes[i] = s;
4563       }
4564     }
4565   }
4566 }
4567 
setSizeAtParametricPoints(const int dim,const int tag,const std::vector<double> & parametricCoord,const std::vector<double> & sizes)4568 GMSH_API void gmsh::model::mesh::setSizeAtParametricPoints(
4569   const int dim, const int tag, const std::vector<double> &parametricCoord,
4570   const std::vector<double> &sizes)
4571 {
4572   if(!_checkInit()) return;
4573   if(dim == 1) {
4574     GEdge *ge = GModel::current()->getEdgeByTag(tag);
4575     if(ge) ge->setMeshSizeParametric(parametricCoord, sizes);
4576   }
4577 }
4578 
setSizeCallback(std::function<double (int,int,double,double,double,double)> callback)4579 GMSH_API void gmsh::model::mesh::setSizeCallback(
4580   std::function<double(int, int, double, double, double, double)> callback)
4581 {
4582   if(!_checkInit()) return;
4583   GModel::current()->lcCallback = callback;
4584 }
4585 
removeSizeCallback()4586 GMSH_API void gmsh::model::mesh::removeSizeCallback()
4587 {
4588   if(!_checkInit()) return;
4589   GModel::current()->lcCallback = nullptr;
4590 }
4591 
4592 GMSH_API void
setTransfiniteCurve(const int tag,const int numNodes,const std::string & meshType,const double coef)4593 gmsh::model::mesh::setTransfiniteCurve(const int tag, const int numNodes,
4594                                        const std::string &meshType,
4595                                        const double coef)
4596 {
4597   if(!_checkInit()) return;
4598   // for compatibility with geo files, try both tag and -tag
4599   for(int sig = -1; sig <= 1; sig += 2) {
4600     int t = sig * tag;
4601     GEdge *ge = GModel::current()->getEdgeByTag(t);
4602     if(ge) {
4603       ge->meshAttributes.method = MESH_TRANSFINITE;
4604       ge->meshAttributes.nbPointsTransfinite = numNodes;
4605       ge->meshAttributes.typeTransfinite =
4606         (meshType == "Progression" || meshType == "Power") ? 1 :
4607         (meshType == "Bump")                               ? 2 :
4608         (meshType == "Beta")                               ? 3 :
4609                                                              1;
4610       ge->meshAttributes.coeffTransfinite = std::abs(coef);
4611       // in .geo file we use a negative tag to do this trick; it's a bad idea
4612       if(coef < 0) ge->meshAttributes.typeTransfinite *= -1;
4613     }
4614     else {
4615       if(t > 0) {
4616         Msg::Error("%s does not exist", _getEntityName(1, t).c_str());
4617         return;
4618       }
4619     }
4620   }
4621 }
4622 
4623 GMSH_API void
setTransfiniteSurface(const int tag,const std::string & arrangement,const std::vector<int> & cornerTags)4624 gmsh::model::mesh::setTransfiniteSurface(const int tag,
4625                                          const std::string &arrangement,
4626                                          const std::vector<int> &cornerTags)
4627 {
4628   if(!_checkInit()) return;
4629   GFace *gf = GModel::current()->getFaceByTag(tag);
4630   if(!gf) {
4631     Msg::Error("%s does not exist", _getEntityName(2, tag).c_str());
4632     return;
4633   }
4634   gf->meshAttributes.method = MESH_TRANSFINITE;
4635   gf->meshAttributes.transfiniteArrangement =
4636     (arrangement == "Right")          ? 1 :
4637     (arrangement == "Left")           ? -1 :
4638     (arrangement == "AlternateRight") ? 2 :
4639     (arrangement == "AlternateLeft")  ? -2 :
4640     (arrangement == "Alternate")      ? 2 :
4641                                         -1;
4642   if(cornerTags.empty() || cornerTags.size() == 3 || cornerTags.size() == 4) {
4643     for(std::size_t j = 0; j < cornerTags.size(); j++) {
4644       GVertex *gv = GModel::current()->getVertexByTag(cornerTags[j]);
4645       if(gv) gf->meshAttributes.corners.push_back(gv);
4646     }
4647   }
4648 }
4649 
4650 GMSH_API void
setTransfiniteVolume(const int tag,const std::vector<int> & cornerTags)4651 gmsh::model::mesh::setTransfiniteVolume(const int tag,
4652                                         const std::vector<int> &cornerTags)
4653 {
4654   if(!_checkInit()) return;
4655   GRegion *gr = GModel::current()->getRegionByTag(tag);
4656   if(!gr) {
4657     Msg::Error("%s does not exist", _getEntityName(3, tag).c_str());
4658     return;
4659   }
4660   gr->meshAttributes.method = MESH_TRANSFINITE;
4661   if(cornerTags.empty() || cornerTags.size() == 6 || cornerTags.size() == 8) {
4662     for(std::size_t i = 0; i < cornerTags.size(); i++) {
4663       GVertex *gv = GModel::current()->getVertexByTag(cornerTags[i]);
4664       if(gv) gr->meshAttributes.corners.push_back(gv);
4665     }
4666   }
4667 }
4668 
_eulerCharacteristic(GRegion * gr)4669 int _eulerCharacteristic(GRegion *gr)
4670 {
4671   std::set<GVertex *> vertices;
4672   std::set<GEdge *> edges;
4673   for(std::size_t _i = 0; _i < gr->faces().size(); ++_i) {
4674     GFace *gf = gr->faces()[_i];
4675     for(std::size_t j = 0; j < gf->edges().size(); ++j) {
4676       GEdge *ge = gf->edges()[j];
4677       edges.insert(ge);
4678       vertices.insert(ge->getBeginVertex());
4679       vertices.insert(ge->getEndVertex());
4680     }
4681   }
4682   int X = int(vertices.size()) - int(edges.size()) + int(gr->faces().size());
4683   return X;
4684 }
4685 
setTransfiniteAutomatic(const vectorpair & dimTags,const double cornerAngle,const bool recombine)4686 GMSH_API void gmsh::model::mesh::setTransfiniteAutomatic(
4687   const vectorpair &dimTags, const double cornerAngle, const bool recombine)
4688 {
4689 #if defined(HAVE_MESH)
4690   if(!_checkInit()) return;
4691   Msg::Debug("setTransfiniteAutomatic() with cornerAngle=%.3f, recombine=%i",
4692              cornerAngle, int(recombine));
4693 
4694   // Collect all quad 4-sided faces (from given faces and volumes)
4695   std::set<GFace *> faces;
4696   if(dimTags.size() == 0) { // Empty dimTag => all faces
4697     std::vector<GEntity *> entities;
4698     GModel::current()->getEntities(entities, 2);
4699     for(std::size_t i = 0; i < entities.size(); i++) {
4700       GFace *gf = static_cast<GFace *>(entities[i]);
4701       if(gf->edges().size() == 4) { faces.insert(gf); }
4702     }
4703   }
4704   else {
4705     for(std::size_t i = 0; i < dimTags.size(); ++i) {
4706       if(dimTags[i].first == 2) {
4707         int tag = dimTags[i].second;
4708         GFace *gf = GModel::current()->getFaceByTag(tag);
4709         if(!gf) {
4710           Msg::Error("%s does not exist", _getEntityName(2, tag).c_str());
4711           return;
4712         }
4713         if(gf->edges().size() == 4) { faces.insert(gf); }
4714       }
4715       else if(dimTags[i].first == 3) {
4716         int tag = dimTags[i].second;
4717         GRegion *gr = GModel::current()->getRegionByTag(tag);
4718         if(!gr) {
4719           Msg::Error("%s does not exist", _getEntityName(3, tag).c_str());
4720           return;
4721         }
4722         for(GFace *gf : gr->faces()) {
4723           if(gf->edges().size() == 4) { faces.insert(gf); }
4724         }
4725       }
4726     }
4727   }
4728 
4729   // Build the chords, compute the averaged number of points on each chord,
4730   // assign the transfinite attributes
4731   bool okf = MeshSetTransfiniteFacesAutomatic(faces, cornerAngle, recombine);
4732   if(!okf) {
4733     Msg::Error("failed to automatically set transfinite faces");
4734     return;
4735   }
4736 
4737   // Collect the 6-sided volumes with Euler characteristic equal to 2 (ie ball)
4738   std::set<GRegion *> regions;
4739   if(dimTags.size() == 0) { // Empty dimTag => all faces
4740     std::vector<GEntity *> entities;
4741     GModel::current()->getEntities(entities, 3);
4742     for(std::size_t i = 0; i < entities.size(); i++) {
4743       GRegion *gr = static_cast<GRegion *>(entities[i]);
4744       if(gr->faces().size() == 6 && _eulerCharacteristic(gr) == 2) {
4745         regions.insert(gr);
4746       }
4747     }
4748   }
4749   else {
4750     for(std::size_t i = 0; i < dimTags.size(); ++i) {
4751       if(dimTags[i].first == 3) {
4752         int tag = dimTags[i].second;
4753         GRegion *gr = GModel::current()->getRegionByTag(tag);
4754         if(!gr) {
4755           Msg::Error("%s does not exist", _getEntityName(3, tag).c_str());
4756           return;
4757         }
4758         if(gr->faces().size() == 6 && _eulerCharacteristic(gr) == 2) {
4759           regions.insert(gr);
4760         }
4761       }
4762     }
4763   }
4764 
4765   std::size_t nr = 0;
4766   for(GRegion *gr : regions) {
4767     bool transfinite = true;
4768     for(GFace *gf : gr->faces()) {
4769       if(gf->meshAttributes.method != MESH_TRANSFINITE) {
4770         transfinite = false;
4771         break;
4772       }
4773       if(transfinite) {
4774         gr->meshAttributes.method = MESH_TRANSFINITE;
4775         nr += 1;
4776       }
4777     }
4778   }
4779   if(nr > 0)
4780     Msg::Debug("transfinite automatic: transfinite set on %li volumes", nr);
4781 #else
4782   Msg::Error("setTransfiniteAutomatic requires the mesh module");
4783 #endif
4784 }
4785 
setRecombine(const int dim,const int tag)4786 GMSH_API void gmsh::model::mesh::setRecombine(const int dim, const int tag)
4787 {
4788   if(!_checkInit()) return;
4789   if(dim == 2) {
4790     GFace *gf = GModel::current()->getFaceByTag(tag);
4791     if(!gf) {
4792       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4793       return;
4794     }
4795     gf->meshAttributes.recombine = 1;
4796     gf->meshAttributes.recombineAngle = 45.;
4797   }
4798 }
4799 
setSmoothing(const int dim,const int tag,const int val)4800 GMSH_API void gmsh::model::mesh::setSmoothing(const int dim, const int tag,
4801                                               const int val)
4802 {
4803   if(!_checkInit()) return;
4804   if(dim == 2) {
4805     GFace *gf = GModel::current()->getFaceByTag(tag);
4806     if(!gf) {
4807       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4808       return;
4809     }
4810     gf->meshAttributes.transfiniteSmoothing = val;
4811   }
4812 }
4813 
setReverse(const int dim,const int tag,const bool val)4814 GMSH_API void gmsh::model::mesh::setReverse(const int dim, const int tag,
4815                                             const bool val)
4816 {
4817   if(!_checkInit()) return;
4818   if(dim == 1) {
4819     GEdge *ge = GModel::current()->getEdgeByTag(tag);
4820     if(!ge) {
4821       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4822       return;
4823     }
4824     ge->meshAttributes.reverseMesh = val;
4825   }
4826   else if(dim == 2) {
4827     GFace *gf = GModel::current()->getFaceByTag(tag);
4828     if(!gf) {
4829       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4830       return;
4831     }
4832     gf->meshAttributes.reverseMesh = val;
4833   }
4834 }
4835 
setAlgorithm(const int dim,const int tag,const int val)4836 GMSH_API void gmsh::model::mesh::setAlgorithm(const int dim, const int tag,
4837                                               const int val)
4838 {
4839   if(!_checkInit()) return;
4840   if(dim == 2) {
4841     GFace *gf = GModel::current()->getFaceByTag(tag);
4842     if(!gf) {
4843       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4844       return;
4845     }
4846     gf->meshAttributes.algorithm = val;
4847   }
4848 }
4849 
setSizeFromBoundary(const int dim,const int tag,const int val)4850 GMSH_API void gmsh::model::mesh::setSizeFromBoundary(const int dim,
4851                                                      const int tag,
4852                                                      const int val)
4853 {
4854   if(!_checkInit()) return;
4855   if(dim == 2) {
4856     GFace *gf = GModel::current()->getFaceByTag(tag);
4857     if(!gf) {
4858       Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4859       return;
4860     }
4861     gf->meshAttributes.meshSizeFromBoundary = val;
4862   }
4863 }
4864 
setCompound(const int dim,const std::vector<int> & tags)4865 GMSH_API void gmsh::model::mesh::setCompound(const int dim,
4866                                              const std::vector<int> &tags)
4867 {
4868   if(!_checkInit()) return;
4869   std::vector<GEntity *> ents;
4870   for(std::size_t i = 0; i < tags.size(); i++) {
4871     GEntity *ent = GModel::current()->getEntityByTag(dim, tags[i]);
4872     if(ent) { ents.push_back(ent); }
4873     else {
4874       Msg::Error("%s does not exist", _getEntityName(dim, tags[i]).c_str());
4875     }
4876   }
4877   for(std::size_t i = 0; i < ents.size(); i++) { ents[i]->compound = ents; }
4878 }
4879 
setOutwardOrientation(const int tag)4880 GMSH_API void gmsh::model::mesh::setOutwardOrientation(const int tag)
4881 {
4882   if(!_checkInit()) return;
4883   GRegion *gr = GModel::current()->getRegionByTag(tag);
4884   if(!gr) {
4885     Msg::Error("%s does not exist", _getEntityName(3, tag).c_str());
4886     return;
4887   }
4888   gr->setOutwardOrientationMeshConstraint();
4889 }
4890 
removeConstraints(const vectorpair & dimTags)4891 GMSH_API void gmsh::model::mesh::removeConstraints(const vectorpair &dimTags)
4892 {
4893   if(!_checkInit()) return;
4894   std::vector<GEntity *> entities;
4895   _getEntities(dimTags, entities);
4896   for(std::size_t i = 0; i < entities.size(); i++)
4897     entities[i]->resetMeshAttributes();
4898 }
4899 
embed(const int dim,const std::vector<int> & tags,const int inDim,const int inTag)4900 GMSH_API void gmsh::model::mesh::embed(const int dim,
4901                                        const std::vector<int> &tags,
4902                                        const int inDim, const int inTag)
4903 {
4904   if(!_checkInit()) return;
4905   if(inDim == 2) {
4906     GFace *gf = GModel::current()->getFaceByTag(inTag);
4907     if(!gf) {
4908       Msg::Error("%s does not exist", _getEntityName(2, inTag).c_str());
4909       return;
4910     }
4911     for(std::size_t i = 0; i < tags.size(); i++) {
4912       if(dim == 0) {
4913         GVertex *gv = GModel::current()->getVertexByTag(tags[i]);
4914         if(!gv) {
4915           Msg::Error("%s does not exist", _getEntityName(0, tags[i]).c_str());
4916           return;
4917         }
4918         gf->addEmbeddedVertex(gv);
4919       }
4920       else if(dim == 1) {
4921         GEdge *ge = GModel::current()->getEdgeByTag(tags[i]);
4922         if(!ge) {
4923           Msg::Error("%s does not exist", _getEntityName(1, tags[i]).c_str());
4924           return;
4925         }
4926         gf->addEmbeddedEdge(ge);
4927       }
4928     }
4929   }
4930   else if(inDim == 3) {
4931     GRegion *gr = GModel::current()->getRegionByTag(inTag);
4932     if(!gr) {
4933       Msg::Error("%s does not exist", _getEntityName(3, inTag).c_str());
4934       return;
4935     }
4936     for(std::size_t i = 0; i < tags.size(); i++) {
4937       if(dim == 0) {
4938         GVertex *gv = GModel::current()->getVertexByTag(tags[i]);
4939         if(!gv) {
4940           Msg::Error("%s does not exist", _getEntityName(0, tags[i]).c_str());
4941           return;
4942         }
4943         gr->addEmbeddedVertex(gv);
4944       }
4945       else if(dim == 1) {
4946         GEdge *ge = GModel::current()->getEdgeByTag(tags[i]);
4947         if(!ge) {
4948           Msg::Error("%s does not exist", _getEntityName(1, tags[i]).c_str());
4949           return;
4950         }
4951         gr->addEmbeddedEdge(ge);
4952       }
4953       else if(dim == 2) {
4954         GFace *gf = GModel::current()->getFaceByTag(tags[i]);
4955         if(!gf) {
4956           Msg::Error("%s does not exist", _getEntityName(2, tags[i]).c_str());
4957           return;
4958         }
4959         gr->addEmbeddedFace(gf);
4960       }
4961     }
4962   }
4963 }
4964 
removeEmbedded(const vectorpair & dimTags,const int rdim)4965 GMSH_API void gmsh::model::mesh::removeEmbedded(const vectorpair &dimTags,
4966                                                 const int rdim)
4967 {
4968   if(!_checkInit()) return;
4969   for(std::size_t i = 0; i < dimTags.size(); i++) {
4970     int dim = dimTags[i].first, tag = dimTags[i].second;
4971     if(dim == 2) {
4972       GFace *gf = GModel::current()->getFaceByTag(tag);
4973       if(!gf) {
4974         Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4975         return;
4976       }
4977       if(rdim < 0 || rdim == 1) gf->embeddedEdges().clear();
4978       if(rdim < 0 || rdim == 0) gf->embeddedVertices().clear();
4979     }
4980     else if(dimTags[i].first == 3) {
4981       GRegion *gr = GModel::current()->getRegionByTag(tag);
4982       if(!gr) {
4983         Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
4984         return;
4985       }
4986       if(rdim < 0 || rdim == 2) gr->embeddedFaces().clear();
4987       if(rdim < 0 || rdim == 1) gr->embeddedEdges().clear();
4988       if(rdim < 0 || rdim == 0) gr->embeddedVertices().clear();
4989     }
4990   }
4991 }
4992 
getEmbedded(const int dim,const int tag,vectorpair & dimTags)4993 GMSH_API void gmsh::model::mesh::getEmbedded(const int dim, const int tag,
4994                                              vectorpair &dimTags)
4995 {
4996   if(!_checkInit()) return;
4997   dimTags.clear();
4998   if(dim == 2) {
4999     GFace *gf = GModel::current()->getFaceByTag(tag);
5000     if(!gf) {
5001       Msg::Error("%s does not exist", _getEntityName(2, tag).c_str());
5002       return;
5003     }
5004     for(auto v : gf->embeddedVertices())
5005       dimTags.push_back(std::make_pair(v->dim(), v->tag()));
5006     for(auto e : gf->embeddedEdges())
5007       dimTags.push_back(std::make_pair(e->dim(), e->tag()));
5008   }
5009   else if(dim == 3) {
5010     GRegion *gr = GModel::current()->getRegionByTag(tag);
5011     if(!gr) {
5012       Msg::Error("%s does not exist", _getEntityName(3, tag).c_str());
5013       return;
5014     }
5015     for(auto v : gr->embeddedVertices())
5016       dimTags.push_back(std::make_pair(v->dim(), v->tag()));
5017     for(auto e : gr->embeddedEdges())
5018       dimTags.push_back(std::make_pair(e->dim(), e->tag()));
5019     for(auto f : gr->embeddedFaces())
5020       dimTags.push_back(std::make_pair(f->dim(), f->tag()));
5021   }
5022 }
5023 
5024 GMSH_API void
reorderElements(const int elementType,const int tag,const std::vector<std::size_t> & ordering)5025 gmsh::model::mesh::reorderElements(const int elementType, const int tag,
5026                                    const std::vector<std::size_t> &ordering)
5027 {
5028   if(!_checkInit()) return;
5029   int dim = ElementType::getDimension(elementType);
5030   std::map<int, std::vector<GEntity *> > typeEnt;
5031   _getEntitiesForElementTypes(dim, tag, typeEnt);
5032   const std::vector<GEntity *> &entities(typeEnt[elementType]);
5033   if(entities.empty()) {
5034     Msg::Error("No elements to reorder");
5035     return;
5036   }
5037   for(std::size_t i = 0; i < entities.size(); i++) {
5038     if(!entities[i]->reorder(elementType, ordering)) {
5039       Msg::Error("Could not reorder elements");
5040       return;
5041     }
5042   }
5043 }
5044 
renumberNodes()5045 GMSH_API void gmsh::model::mesh::renumberNodes()
5046 {
5047   if(!_checkInit()) return;
5048   GModel::current()->renumberMeshVertices();
5049 }
5050 
renumberElements()5051 GMSH_API void gmsh::model::mesh::renumberElements()
5052 {
5053   if(!_checkInit()) return;
5054   GModel::current()->renumberMeshElements();
5055 }
5056 
5057 GMSH_API void
setPeriodic(const int dim,const std::vector<int> & tags,const std::vector<int> & tagsMaster,const std::vector<double> & affineTransform)5058 gmsh::model::mesh::setPeriodic(const int dim, const std::vector<int> &tags,
5059                                const std::vector<int> &tagsMaster,
5060                                const std::vector<double> &affineTransform)
5061 {
5062   if(!_checkInit()) return;
5063   if(tags.size() != tagsMaster.size()) {
5064     Msg::Error("Incompatible number of tags and master tags for periodic mesh");
5065     return;
5066   }
5067   if(affineTransform.size() != 16) {
5068     Msg::Error("Wrong number of elements in affine transformation (%d != 16)",
5069                (int)affineTransform.size());
5070     return;
5071   }
5072   for(std::size_t i = 0; i < tags.size(); i++) {
5073     if(dim == 1) {
5074       GEdge *target = GModel::current()->getEdgeByTag(tags[i]);
5075       if(!target) {
5076         Msg::Error("%s does not exist", _getEntityName(dim, tags[i]).c_str());
5077         return;
5078       }
5079       GEdge *source = GModel::current()->getEdgeByTag(tagsMaster[i]);
5080       if(!source) {
5081         Msg::Error("%s does not exist",
5082                    _getEntityName(dim, tagsMaster[i]).c_str());
5083         return;
5084       }
5085       target->setMeshMaster(source, affineTransform);
5086     }
5087     else if(dim == 2) {
5088       GFace *target = GModel::current()->getFaceByTag(tags[i]);
5089       if(!target) {
5090         Msg::Error("%s does not exist", _getEntityName(dim, tags[i]).c_str());
5091         return;
5092       }
5093       GFace *source = GModel::current()->getFaceByTag(tagsMaster[i]);
5094       if(!source) {
5095         Msg::Error("%s does not exist",
5096                    _getEntityName(dim, tagsMaster[i]).c_str());
5097         return;
5098       }
5099       target->setMeshMaster(source, affineTransform);
5100     }
5101   }
5102 }
5103 
5104 GMSH_API void
getPeriodic(const int dim,const std::vector<int> & tags,std::vector<int> & tagsMaster)5105 gmsh::model::mesh::getPeriodic(const int dim, const std::vector<int> &tags,
5106                                std::vector<int> &tagsMaster)
5107 {
5108   if(!_checkInit()) return;
5109   tagsMaster.clear();
5110   tagsMaster.reserve(tags.size());
5111   for(auto i : tags) {
5112     GEntity *ge = GModel::current()->getEntityByTag(dim, i);
5113     if(!ge) {
5114       Msg::Error("%s does not exist", _getEntityName(dim, i).c_str());
5115       return;
5116     }
5117     tagsMaster.push_back(ge->getMeshMaster()->tag());
5118   }
5119 }
5120 
getPeriodicNodes(const int dim,const int tag,int & tagMaster,std::vector<std::size_t> & nodeTags,std::vector<std::size_t> & nodeTagsMaster,std::vector<double> & affineTransform,const bool includeHighOrderNodes)5121 GMSH_API void gmsh::model::mesh::getPeriodicNodes(
5122   const int dim, const int tag, int &tagMaster,
5123   std::vector<std::size_t> &nodeTags, std::vector<std::size_t> &nodeTagsMaster,
5124   std::vector<double> &affineTransform, const bool includeHighOrderNodes)
5125 {
5126   if(!_checkInit()) return;
5127   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
5128   if(!ge) {
5129     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
5130     return;
5131   }
5132   if(ge->getMeshMaster() != ge) {
5133     tagMaster = ge->getMeshMaster()->tag();
5134     for(auto it = ge->correspondingVertices.begin();
5135         it != ge->correspondingVertices.end(); ++it) {
5136       nodeTags.push_back(it->first->getNum());
5137       nodeTagsMaster.push_back(it->second->getNum());
5138     }
5139     if(includeHighOrderNodes) {
5140       for(auto it = ge->correspondingHighOrderVertices.begin();
5141           it != ge->correspondingHighOrderVertices.end(); ++it) {
5142         nodeTags.push_back(it->first->getNum());
5143         nodeTagsMaster.push_back(it->second->getNum());
5144       }
5145     }
5146     affineTransform = ge->affineTransform;
5147   }
5148   else {
5149     tagMaster = tag;
5150     nodeTags.clear();
5151     nodeTagsMaster.clear();
5152     affineTransform.clear();
5153   }
5154 }
5155 
getPeriodicKeys(const int elementType,const std::string & functionSpaceType,const int tag,int & tagMaster,std::vector<int> & typeKeys,std::vector<int> & typeKeysMaster,std::vector<std::size_t> & entityKeys,std::vector<std::size_t> & entityKeysMaster,std::vector<double> & coord,std::vector<double> & coordMaster,const bool returnCoord)5156 GMSH_API void gmsh::model::mesh::getPeriodicKeys(
5157   const int elementType, const std::string &functionSpaceType,
5158   const int tag, int &tagMaster,
5159   std::vector<int> &typeKeys, std::vector<int> &typeKeysMaster,
5160   std::vector<std::size_t> &entityKeys, std::vector<std::size_t> &entityKeysMaster,
5161   std::vector<double> &coord, std::vector<double> &coordMaster,
5162   const bool returnCoord)
5163 {
5164   if(!_checkInit()) return;
5165   int dim = ElementType::getDimension(elementType);
5166   GEntity *ge = GModel::current()->getEntityByTag(dim, tag);
5167   if(!ge) {
5168     Msg::Error("%s does not exist", _getEntityName(dim, tag).c_str());
5169     return;
5170   }
5171   if(ge->getMeshMaster() == ge) { // not periodic
5172     tagMaster = tag;
5173     typeKeys.clear();
5174     typeKeysMaster.clear();
5175     entityKeys.clear();
5176     entityKeysMaster.clear();
5177     return;
5178   }
5179 
5180   tagMaster = ge->getMeshMaster()->tag();
5181   getKeys(elementType, functionSpaceType,
5182                      typeKeys, entityKeys, coord, tag, returnCoord);
5183   typeKeysMaster = typeKeys;
5184   entityKeysMaster = entityKeys;
5185   coordMaster = coord;
5186 
5187   if(functionSpaceType == "IsoParametric" ||
5188      functionSpaceType == "Lagrange") {
5189 #pragma omp parallel for
5190     for(std::size_t i = 0; i < entityKeys.size(); i++) {
5191       MVertex v(0., 0., 0., nullptr, entityKeys[i]);
5192       auto mv = ge->correspondingVertices.find(&v);
5193       if(mv != ge->correspondingVertices.end()) {
5194         entityKeysMaster[i] = mv->second->getNum();
5195         if(returnCoord) {
5196           coord[3 * i] = mv->second->x();
5197           coord[3 * i + 1] = mv->second->y();
5198           coord[3 * i + 2] = mv->second->z();
5199         }
5200       }
5201       else {
5202         auto mv2 = ge->correspondingHighOrderVertices.find(&v);
5203         if(mv2 != ge->correspondingHighOrderVertices.end()) {
5204           entityKeysMaster[i] = mv2->second->getNum();
5205           if(returnCoord) {
5206             coord[3 * i] = mv2->second->x();
5207             coord[3 * i + 1] = mv2->second->y();
5208             coord[3 * i + 2] = mv2->second->z();
5209           }
5210         }
5211         else{
5212           Msg::Warning("Unknown master node corresponding to node %d",
5213                        entityKeys[i]);
5214         }
5215       }
5216     }
5217   }
5218   else{
5219     Msg::Error("Periodic key generation currently only available for "
5220                "\"IsoParametric\" and \"Lagrange\" function spaces");
5221   }
5222 }
5223 
removeDuplicateNodes()5224 GMSH_API void gmsh::model::mesh::removeDuplicateNodes()
5225 {
5226   if(!_checkInit()) return;
5227   GModel::current()->removeDuplicateMeshVertices(
5228     CTX::instance()->geom.tolerance);
5229   CTX::instance()->mesh.changed = ENT_ALL;
5230 }
5231 
classifySurfaces(const double angle,const bool boundary,const bool forReparametrization,const double curveAngle,const bool exportDiscrete)5232 GMSH_API void gmsh::model::mesh::classifySurfaces(
5233   const double angle, const bool boundary, const bool forReparametrization,
5234   const double curveAngle, const bool exportDiscrete)
5235 {
5236   if(!_checkInit()) return;
5237   GModel::current()->classifySurfaces(angle, boundary, forReparametrization,
5238                                       curveAngle);
5239   if(exportDiscrete) {
5240     // Warning: this clears GEO_Internals!
5241     GModel::current()->exportDiscreteGEOInternals();
5242   }
5243 }
5244 
createGeometry(const vectorpair & dimTags)5245 GMSH_API void gmsh::model::mesh::createGeometry(const vectorpair &dimTags)
5246 {
5247   if(!_checkInit()) return;
5248   GModel::current()->createGeometryOfDiscreteEntities(dimTags);
5249 }
5250 
createTopology(const bool makeSimplyConnected,const bool exportDiscrete)5251 GMSH_API void gmsh::model::mesh::createTopology(const bool makeSimplyConnected,
5252                                                 const bool exportDiscrete)
5253 {
5254   if(!_checkInit()) return;
5255 
5256   if(makeSimplyConnected) {
5257     GModel::current()->makeDiscreteRegionsSimplyConnected();
5258     GModel::current()->makeDiscreteFacesSimplyConnected();
5259   }
5260   GModel::current()->createTopologyFromMesh();
5261   if(exportDiscrete) {
5262     // Warning: this clears GEO_Internals!
5263     GModel::current()->exportDiscreteGEOInternals();
5264   }
5265 }
5266 
5267 GMSH_API void
computeHomology(const std::vector<int> & domainTags,const std::vector<int> & subdomainTags,const std::vector<int> & dims)5268 gmsh::model::mesh::computeHomology(const std::vector<int> &domainTags,
5269                                    const std::vector<int> &subdomainTags,
5270                                    const std::vector<int> &dims)
5271 {
5272   if(!_checkInit()) return;
5273   GModel::current()->addHomologyRequest("Homology", domainTags, subdomainTags,
5274                                         dims);
5275 }
5276 
5277 GMSH_API void
computeCohomology(const std::vector<int> & domainTags,const std::vector<int> & subdomainTags,const std::vector<int> & dims)5278 gmsh::model::mesh::computeCohomology(const std::vector<int> &domainTags,
5279                                      const std::vector<int> &subdomainTags,
5280                                      const std::vector<int> &dims)
5281 {
5282   if(!_checkInit()) return;
5283   GModel::current()->addHomologyRequest("Cohomology", domainTags, subdomainTags,
5284                                         dims);
5285 }
5286 
triangulate(const std::vector<double> & coord,std::vector<std::size_t> & tri)5287 GMSH_API void gmsh::model::mesh::triangulate(const std::vector<double> &coord,
5288                                              std::vector<std::size_t> &tri)
5289 {
5290   if(!_checkInit()) return;
5291   if(coord.size() % 2) {
5292     Msg::Error("Number of 2D coordinates should be even");
5293     return;
5294   }
5295 #if defined(HAVE_MESH)
5296   SBoundingBox3d bbox;
5297   for(std::size_t i = 0; i < coord.size(); i += 2)
5298     bbox += SPoint3(coord[i], coord[i + 1], 0.);
5299   double lc = 10. * norm(SVector3(bbox.max(), bbox.min()));
5300   std::vector<MVertex *> verts(coord.size() / 2);
5301   std::size_t j = 0;
5302   for(std::size_t i = 0; i < coord.size(); i += 2) {
5303     double XX = 1.e-12 * lc * (double)rand() / (double)RAND_MAX;
5304     double YY = 1.e-12 * lc * (double)rand() / (double)RAND_MAX;
5305     MVertex *v = new MVertex(coord[i] + XX, coord[i + 1] + YY, 0.);
5306     v->setIndex(j);
5307     verts[j++] = v;
5308   }
5309   std::vector<MTriangle *> tris;
5310   delaunayMeshIn2D(verts, tris);
5311   tri.resize(3 * tris.size());
5312   for(std::size_t i = 0; i < tris.size(); i++) {
5313     MTriangle *t = tris[i];
5314     for(std::size_t j = 0; j < 3; j++)
5315       tri[3 * i + j] = t->getVertex(j)->getIndex() + 1; // start at 1
5316   }
5317   for(std::size_t i = 0; i < verts.size(); i++) delete verts[i];
5318   for(std::size_t i = 0; i < tris.size(); i++) delete tris[i];
5319 #else
5320   Msg::Error("triangulate requires the mesh module");
5321 #endif
5322 }
5323 
5324 GMSH_API void
tetrahedralize(const std::vector<double> & coord,std::vector<std::size_t> & tetra)5325 gmsh::model::mesh::tetrahedralize(const std::vector<double> &coord,
5326                                   std::vector<std::size_t> &tetra)
5327 {
5328   if(!_checkInit()) return;
5329   if(coord.size() % 3) {
5330     Msg::Error("Number of coordinates should be a multiple of 3");
5331     return;
5332   }
5333 #if defined(HAVE_MESH)
5334   std::vector<MVertex *> verts(coord.size() / 3);
5335   std::size_t j = 0;
5336   for(std::size_t i = 0; i < coord.size(); i += 3) {
5337     MVertex *v = new MVertex(coord[i], coord[i + 1], coord[i + 2]);
5338     v->setIndex(j);
5339     verts[j++] = v;
5340   }
5341   std::vector<MTetrahedron *> tets;
5342   if(CTX::instance()->mesh.algo3d == ALGO_3D_HXT)
5343     delaunayMeshIn3DHxt(verts, tets);
5344   else
5345     delaunayMeshIn3D(verts, tets, true);
5346   tetra.resize(4 * tets.size());
5347   for(std::size_t i = 0; i < tets.size(); i++) {
5348     MTetrahedron *t = tets[i];
5349     for(std::size_t j = 0; j < 4; j++)
5350       tetra[4 * i + j] = t->getVertex(j)->getIndex() + 1; // start at 1
5351   }
5352   for(std::size_t i = 0; i < verts.size(); i++) delete verts[i];
5353   for(std::size_t i = 0; i < tets.size(); i++) delete tets[i];
5354 #else
5355   Msg::Error("tetrahedralize requires the mesh module");
5356 #endif
5357 }
5358 
5359 // gmsh::model::mesh::field
5360 
add(const std::string & fieldType,const int tag)5361 GMSH_API int gmsh::model::mesh::field::add(const std::string &fieldType,
5362                                            const int tag)
5363 {
5364   if(!_checkInit()) return -1;
5365   int outTag = tag;
5366 #if defined(HAVE_MESH)
5367   if(outTag < 0) { outTag = GModel::current()->getFields()->newId(); }
5368   if(!GModel::current()->getFields()->newField(outTag, fieldType)) {
5369     Msg::Error("Cannot add Field %i of type '%s'", outTag, fieldType.c_str());
5370     return -1;
5371   }
5372 #if defined(HAVE_FLTK)
5373   if(FlGui::available()) FlGui::instance()->updateFields();
5374 #endif
5375 #else
5376   Msg::Error("Fields require the mesh module");
5377 #endif
5378   return outTag;
5379 }
5380 
remove(const int tag)5381 GMSH_API void gmsh::model::mesh::field::remove(const int tag)
5382 {
5383   if(!_checkInit()) return;
5384 #if defined(HAVE_MESH)
5385   GModel::current()->getFields()->deleteField(tag);
5386 #if defined(HAVE_FLTK)
5387   if(FlGui::available()) FlGui::instance()->updateFields();
5388 #endif
5389 #else
5390   Msg::Error("Fields require the mesh module");
5391 #endif
5392 }
5393 
list(std::vector<int> & tags)5394 GMSH_API void gmsh::model::mesh::field::list(std::vector<int> &tags)
5395 {
5396   if(!_checkInit()) return;
5397   tags.clear();
5398 #if defined(HAVE_MESH)
5399   FieldManager &fields = *GModel::current()->getFields();
5400   for(auto it = fields.begin(); it != fields.end(); it++) {
5401     tags.push_back(it->first);
5402   }
5403 #else
5404   Msg::Error("Fields require the mesh module");
5405 #endif
5406 }
5407 
getType(const int tag,std::string & fieldType)5408 GMSH_API void gmsh::model::mesh::field::getType(const int tag,
5409                                                 std::string &fieldType)
5410 {
5411   if(!_checkInit()) return;
5412 #if defined(HAVE_MESH)
5413   Field *field = GModel::current()->getFields()->get(tag);
5414   if(!field) {
5415     Msg::Error("Unknown field %i", tag);
5416     return;
5417   }
5418   fieldType = field->getName();
5419 #else
5420   Msg::Error("Fields require the mesh module");
5421 #endif
5422 }
5423 
5424 #if defined(HAVE_MESH)
_getFieldOption(const int tag,const std::string & option)5425 static FieldOption *_getFieldOption(const int tag, const std::string &option)
5426 {
5427   Field *field = GModel::current()->getFields()->get(tag);
5428   if(!field) {
5429     Msg::Error("Unknown field %i", tag);
5430     return nullptr;
5431   }
5432   FieldOption *o = field->options[option];
5433   if(!o) {
5434     Msg::Error("Unknown option '%s' in field %i of type '%s'", option.c_str(),
5435                tag, field->getName());
5436     return nullptr;
5437   }
5438   return o;
5439 }
5440 #endif
5441 
setNumber(const int tag,const std::string & option,const double value)5442 GMSH_API void gmsh::model::mesh::field::setNumber(const int tag,
5443                                                   const std::string &option,
5444                                                   const double value)
5445 {
5446   if(!_checkInit()) return;
5447 #if defined(HAVE_MESH)
5448   FieldOption *o = _getFieldOption(tag, option);
5449   if(!o) return;
5450   o->numericalValue(value);
5451 #else
5452   Msg::Error("Fields require the mesh module");
5453 #endif
5454 }
5455 
getNumber(const int tag,const std::string & option,double & value)5456 GMSH_API void gmsh::model::mesh::field::getNumber(const int tag,
5457                                                   const std::string &option,
5458                                                   double &value)
5459 {
5460   if(!_checkInit()) return;
5461 #if defined(HAVE_MESH)
5462   FieldOption *o = _getFieldOption(tag, option);
5463   if(!o) { return; }
5464   value = o->numericalValue();
5465 #else
5466   Msg::Error("Fields require the mesh module");
5467 #endif
5468 }
5469 
setString(const int tag,const std::string & option,const std::string & value)5470 GMSH_API void gmsh::model::mesh::field::setString(const int tag,
5471                                                   const std::string &option,
5472                                                   const std::string &value)
5473 {
5474   if(!_checkInit()) return;
5475 #if defined(HAVE_MESH)
5476   FieldOption *o = _getFieldOption(tag, option);
5477   if(!o) return;
5478   o->string(value);
5479 #else
5480   Msg::Error("Fields require the mesh module");
5481 #endif
5482 }
5483 
getString(const int tag,const std::string & option,std::string & value)5484 GMSH_API void gmsh::model::mesh::field::getString(const int tag,
5485                                                   const std::string &option,
5486                                                   std::string &value)
5487 {
5488   if(!_checkInit()) return;
5489 #if defined(HAVE_MESH)
5490   FieldOption *o = _getFieldOption(tag, option);
5491   if(!o) { return; }
5492   value = o->string();
5493 #else
5494   Msg::Error("Fields require the mesh module");
5495 #endif
5496 }
5497 
5498 GMSH_API void
setNumbers(const int tag,const std::string & option,const std::vector<double> & value)5499 gmsh::model::mesh::field::setNumbers(const int tag, const std::string &option,
5500                                      const std::vector<double> &value)
5501 {
5502   if(!_checkInit()) return;
5503 #if defined(HAVE_MESH)
5504   FieldOption *o = _getFieldOption(tag, option);
5505   if(!o) return;
5506   if(o->getType() == FIELD_OPTION_LIST) {
5507     std::list<int> vl;
5508     for(std::size_t i = 0; i < value.size(); i++) vl.push_back((int)value[i]);
5509     o->list(vl);
5510   }
5511   else {
5512     std::list<double> vl;
5513     for(std::size_t i = 0; i < value.size(); i++) vl.push_back(value[i]);
5514     o->listdouble(vl);
5515   }
5516 #else
5517   Msg::Error("Fields require the mesh module");
5518 #endif
5519 }
5520 
5521 GMSH_API void
getNumbers(const int tag,const std::string & option,std::vector<double> & value)5522 gmsh::model::mesh::field::getNumbers(const int tag, const std::string &option,
5523                                      std::vector<double> &value)
5524 {
5525   if(!_checkInit()) return;
5526 #if defined(HAVE_MESH)
5527   FieldOption *o = _getFieldOption(tag, option);
5528   if(!o) { return; }
5529   if(o->getType() == FIELD_OPTION_LIST) {
5530     std::list<int> vl = o->list();
5531     for(auto i : vl) value.push_back(i);
5532   }
5533   else {
5534     std::list<double> vl = o->listdouble();
5535     for(auto d : vl) value.push_back(d);
5536   }
5537 #else
5538   Msg::Error("Fields require the mesh module");
5539 #endif
5540 }
5541 
setAsBackgroundMesh(const int tag)5542 GMSH_API void gmsh::model::mesh::field::setAsBackgroundMesh(const int tag)
5543 {
5544   if(!_checkInit()) return;
5545 #if defined(HAVE_MESH)
5546   GModel::current()->getFields()->setBackgroundFieldId(tag);
5547 #else
5548   Msg::Error("Fields require the mesh module");
5549 #endif
5550 }
5551 
setAsBoundaryLayer(const int tag)5552 GMSH_API void gmsh::model::mesh::field::setAsBoundaryLayer(const int tag)
5553 {
5554   if(!_checkInit()) return;
5555 #if defined(HAVE_MESH)
5556   GModel::current()->getFields()->addBoundaryLayerFieldId(tag);
5557 #else
5558   Msg::Error("Fields require the mesh module");
5559 #endif
5560 }
5561 
5562 // gmsh::model::geo
5563 
addPoint(const double x,const double y,const double z,const double meshSize,const int tag)5564 GMSH_API int gmsh::model::geo::addPoint(const double x, const double y,
5565                                         const double z, const double meshSize,
5566                                         const int tag)
5567 {
5568   if(!_checkInit()) return -1;
5569   int outTag = tag;
5570   double xx = CTX::instance()->geom.scalingFactor * x;
5571   double yy = CTX::instance()->geom.scalingFactor * y;
5572   double zz = CTX::instance()->geom.scalingFactor * z;
5573   double lc = CTX::instance()->geom.scalingFactor * meshSize;
5574   GModel::current()->getGEOInternals()->addVertex(outTag, xx, yy, zz, lc);
5575   return outTag;
5576 }
5577 
addLine(const int startTag,const int endTag,const int tag)5578 GMSH_API int gmsh::model::geo::addLine(const int startTag, const int endTag,
5579                                        const int tag)
5580 {
5581   if(!_checkInit()) return -1;
5582   int outTag = tag;
5583   GModel::current()->getGEOInternals()->addLine(outTag, startTag, endTag);
5584   return outTag;
5585 }
5586 
addCircleArc(const int startTag,const int centerTag,const int endTag,const int tag,const double nx,const double ny,const double nz)5587 GMSH_API int gmsh::model::geo::addCircleArc(const int startTag,
5588                                             const int centerTag,
5589                                             const int endTag, const int tag,
5590                                             const double nx, const double ny,
5591                                             const double nz)
5592 {
5593   if(!_checkInit()) return -1;
5594   int outTag = tag;
5595   GModel::current()->getGEOInternals()->addCircleArc(
5596     outTag, startTag, centerTag, endTag, nx, ny, nz);
5597   return outTag;
5598 }
5599 
addEllipseArc(const int startTag,const int centerTag,const int majorTag,const int endTag,const int tag,const double nx,const double ny,const double nz)5600 GMSH_API int gmsh::model::geo::addEllipseArc(
5601   const int startTag, const int centerTag, const int majorTag, const int endTag,
5602   const int tag, const double nx, const double ny, const double nz)
5603 {
5604   if(!_checkInit()) return -1;
5605   int outTag = tag;
5606   GModel::current()->getGEOInternals()->addEllipseArc(
5607     outTag, startTag, centerTag, majorTag, endTag, nx, ny, nz);
5608   return outTag;
5609 }
5610 
addSpline(const std::vector<int> & pointTags,const int tag)5611 GMSH_API int gmsh::model::geo::addSpline(const std::vector<int> &pointTags,
5612                                          const int tag)
5613 {
5614   if(!_checkInit()) return -1;
5615   int outTag = tag;
5616   GModel::current()->getGEOInternals()->addSpline(outTag, pointTags);
5617   return outTag;
5618 }
5619 
addBSpline(const std::vector<int> & pointTags,const int tag)5620 GMSH_API int gmsh::model::geo::addBSpline(const std::vector<int> &pointTags,
5621                                           const int tag)
5622 {
5623   if(!_checkInit()) return -1;
5624   int outTag = tag;
5625   GModel::current()->getGEOInternals()->addBSpline(outTag, pointTags);
5626   return outTag;
5627 }
5628 
addBezier(const std::vector<int> & pointTags,const int tag)5629 GMSH_API int gmsh::model::geo::addBezier(const std::vector<int> &pointTags,
5630                                          const int tag)
5631 {
5632   if(!_checkInit()) return -1;
5633   int outTag = tag;
5634   GModel::current()->getGEOInternals()->addBezier(outTag, pointTags);
5635   return outTag;
5636 }
5637 
addPolyline(const std::vector<int> & pointTags,const int tag)5638 GMSH_API int gmsh::model::geo::addPolyline(const std::vector<int> &pointTags,
5639                                            const int tag)
5640 {
5641   if(!_checkInit()) return -1;
5642   int outTag = tag;
5643   GModel::current()->getGEOInternals()->addLine(outTag, pointTags);
5644   return outTag;
5645 }
5646 
5647 GMSH_API int
addCompoundSpline(const std::vector<int> & curveTags,const int numIntervals,const int tag)5648 gmsh::model::geo::addCompoundSpline(const std::vector<int> &curveTags,
5649                                     const int numIntervals, const int tag)
5650 {
5651   if(!_checkInit()) return -1;
5652   int outTag = tag;
5653   GModel::current()->getGEOInternals()->addCompoundSpline(outTag, curveTags,
5654                                                           numIntervals);
5655   return outTag;
5656 }
5657 
5658 GMSH_API int
addCompoundBSpline(const std::vector<int> & curveTags,const int numIntervals,const int tag)5659 gmsh::model::geo::addCompoundBSpline(const std::vector<int> &curveTags,
5660                                      const int numIntervals, const int tag)
5661 {
5662   if(!_checkInit()) return -1;
5663   int outTag = tag;
5664   GModel::current()->getGEOInternals()->addCompoundBSpline(outTag, curveTags,
5665                                                            numIntervals);
5666   return outTag;
5667 }
5668 
addCurveLoop(const std::vector<int> & curveTags,const int tag,const bool reorient)5669 GMSH_API int gmsh::model::geo::addCurveLoop(const std::vector<int> &curveTags,
5670                                             const int tag, const bool reorient)
5671 {
5672   if(!_checkInit()) return -1;
5673   int outTag = tag;
5674   GModel::current()->getGEOInternals()->addCurveLoop(outTag, curveTags,
5675                                                      reorient);
5676   return outTag;
5677 }
5678 
addCurveLoops(const std::vector<int> & curveTags,std::vector<int> & tags)5679 GMSH_API void gmsh::model::geo::addCurveLoops(const std::vector<int> &curveTags,
5680                                               std::vector<int> &tags)
5681 {
5682   if(!_checkInit()) return;
5683   GModel::current()->getGEOInternals()->addCurveLoops(curveTags, tags);
5684 }
5685 
addPlaneSurface(const std::vector<int> & wireTags,const int tag)5686 GMSH_API int gmsh::model::geo::addPlaneSurface(const std::vector<int> &wireTags,
5687                                                const int tag)
5688 {
5689   if(!_checkInit()) return -1;
5690   int outTag = tag;
5691   GModel::current()->getGEOInternals()->addPlaneSurface(outTag, wireTags);
5692   return outTag;
5693 }
5694 
5695 GMSH_API int
addSurfaceFilling(const std::vector<int> & wireTags,const int tag,const int sphereCenterTag)5696 gmsh::model::geo::addSurfaceFilling(const std::vector<int> &wireTags,
5697                                     const int tag, const int sphereCenterTag)
5698 {
5699   if(!_checkInit()) return -1;
5700   int outTag = tag;
5701   GModel::current()->getGEOInternals()->addSurfaceFilling(outTag, wireTags,
5702                                                           sphereCenterTag);
5703   return outTag;
5704 }
5705 
5706 GMSH_API int
addSurfaceLoop(const std::vector<int> & surfaceTags,const int tag)5707 gmsh::model::geo::addSurfaceLoop(const std::vector<int> &surfaceTags,
5708                                  const int tag)
5709 {
5710   if(!_checkInit()) return -1;
5711   int outTag = tag;
5712   GModel::current()->getGEOInternals()->addSurfaceLoop(outTag, surfaceTags);
5713   return outTag;
5714 }
5715 
addVolume(const std::vector<int> & shellTags,const int tag)5716 GMSH_API int gmsh::model::geo::addVolume(const std::vector<int> &shellTags,
5717                                          const int tag)
5718 {
5719   if(!_checkInit()) return -1;
5720   int outTag = tag;
5721   GModel::current()->getGEOInternals()->addVolume(outTag, shellTags);
5722   return outTag;
5723 }
5724 
_getExtrudeParams(const std::vector<int> & numElements,const std::vector<double> & heights,const bool recombine)5725 static ExtrudeParams *_getExtrudeParams(const std::vector<int> &numElements,
5726                                         const std::vector<double> &heights,
5727                                         const bool recombine)
5728 {
5729   ExtrudeParams *e = nullptr;
5730   if(numElements.size()) {
5731     e = new ExtrudeParams();
5732     e->mesh.ExtrudeMesh = true;
5733     e->mesh.NbElmLayer = numElements;
5734     e->mesh.hLayer = heights;
5735     if(e->mesh.hLayer.empty()) {
5736       e->mesh.NbLayer = numElements.size();
5737       for(int i = 0; i < e->mesh.NbLayer; i++) {
5738         e->mesh.hLayer.push_back((i + 1.) / e->mesh.NbLayer);
5739       }
5740     }
5741     else {
5742       e->mesh.NbLayer = heights.size();
5743     }
5744     e->mesh.Recombine = recombine;
5745   }
5746   return e;
5747 }
5748 
extrude(const vectorpair & dimTags,const double dx,const double dy,const double dz,vectorpair & outDimTags,const std::vector<int> & numElements,const std::vector<double> & heights,const bool recombine)5749 GMSH_API void gmsh::model::geo::extrude(const vectorpair &dimTags,
5750                                         const double dx, const double dy,
5751                                         const double dz, vectorpair &outDimTags,
5752                                         const std::vector<int> &numElements,
5753                                         const std::vector<double> &heights,
5754                                         const bool recombine)
5755 {
5756   if(!_checkInit()) return;
5757   outDimTags.clear();
5758   ExtrudeParams *e = _getExtrudeParams(numElements, heights, recombine);
5759   GModel::current()->getGEOInternals()->extrude(
5760     dimTags, dx, dy, dz, outDimTags, e);
5761   if(e) delete e;
5762 }
5763 
revolve(const vectorpair & dimTags,const double x,const double y,const double z,const double ax,const double ay,const double az,const double angle,vectorpair & outDimTags,const std::vector<int> & numElements,const std::vector<double> & heights,const bool recombine)5764 GMSH_API void gmsh::model::geo::revolve(
5765   const vectorpair &dimTags, const double x, const double y, const double z,
5766   const double ax, const double ay, const double az, const double angle,
5767   vectorpair &outDimTags, const std::vector<int> &numElements,
5768   const std::vector<double> &heights, const bool recombine)
5769 {
5770   if(!_checkInit()) return;
5771   outDimTags.clear();
5772   ExtrudeParams *e = _getExtrudeParams(numElements, heights, recombine);
5773   GModel::current()->getGEOInternals()->revolve(
5774     dimTags, x, y, z, ax, ay, az, angle, outDimTags, e);
5775   if(e) delete e;
5776 }
5777 
twist(const vectorpair & dimTags,const double x,const double y,const double z,const double dx,const double dy,const double dz,const double ax,const double ay,const double az,const double angle,vectorpair & outDimTags,const std::vector<int> & numElements,const std::vector<double> & heights,const bool recombine)5778 GMSH_API void gmsh::model::geo::twist(
5779   const vectorpair &dimTags, const double x, const double y, const double z,
5780   const double dx, const double dy, const double dz, const double ax,
5781   const double ay, const double az, const double angle, vectorpair &outDimTags,
5782   const std::vector<int> &numElements, const std::vector<double> &heights,
5783   const bool recombine)
5784 {
5785   _checkInit();
5786   outDimTags.clear();
5787   ExtrudeParams *e = _getExtrudeParams(numElements, heights, recombine);
5788   GModel::current()->getGEOInternals()->twist(
5789     dimTags, x, y, z, dx, dy, dz, ax, ay, az, angle, outDimTags, e);
5790   if(e) delete e;
5791 }
5792 
extrudeBoundaryLayer(const vectorpair & dimTags,vectorpair & outDimTags,const std::vector<int> & numElements,const std::vector<double> & heights,const bool recombine,const bool second,const int viewIndex)5793 GMSH_API void gmsh::model::geo::extrudeBoundaryLayer(
5794   const vectorpair &dimTags, vectorpair &outDimTags,
5795   const std::vector<int> &numElements, const std::vector<double> &heights,
5796   const bool recombine, const bool second, const int viewIndex)
5797 {
5798   if(!_checkInit()) return;
5799   outDimTags.clear();
5800   ExtrudeParams *e = _getExtrudeParams(numElements, heights, recombine);
5801   if(!e) {
5802     Msg::Error("Element layers are required for boundary layer extrusion");
5803     return;
5804   }
5805   e->mesh.BoundaryLayerIndex = second ? 1 : 0;
5806   e->mesh.ViewIndex = viewIndex;
5807   GModel::current()->getGEOInternals()->boundaryLayer(dimTags, outDimTags, e);
5808   delete e;
5809 }
5810 
translate(const vectorpair & dimTags,const double dx,const double dy,const double dz)5811 GMSH_API void gmsh::model::geo::translate(const vectorpair &dimTags,
5812                                           const double dx, const double dy,
5813                                           const double dz)
5814 {
5815   if(!_checkInit()) return;
5816   GModel::current()->getGEOInternals()->translate(dimTags, dx, dy, dz);
5817 }
5818 
rotate(const vectorpair & dimTags,const double x,const double y,const double z,const double ax,const double ay,const double az,const double angle)5819 GMSH_API void gmsh::model::geo::rotate(const vectorpair &dimTags,
5820                                        const double x, const double y,
5821                                        const double z, const double ax,
5822                                        const double ay, const double az,
5823                                        const double angle)
5824 {
5825   if(!_checkInit()) return;
5826   GModel::current()->getGEOInternals()->rotate(dimTags, x, y, z, ax, ay, az,
5827                                                angle);
5828 }
5829 
dilate(const vectorpair & dimTags,const double x,const double y,const double z,const double a,const double b,const double c)5830 GMSH_API void gmsh::model::geo::dilate(const vectorpair &dimTags,
5831                                        const double x, const double y,
5832                                        const double z, const double a,
5833                                        const double b, const double c)
5834 {
5835   if(!_checkInit()) return;
5836   GModel::current()->getGEOInternals()->dilate(dimTags, x, y, z, a, b, c);
5837 }
5838 
mirror(const vectorpair & dimTags,const double a,const double b,const double c,const double d)5839 GMSH_API void gmsh::model::geo::mirror(const vectorpair &dimTags,
5840                                        const double a, const double b,
5841                                        const double c, const double d)
5842 {
5843   if(!_checkInit()) return;
5844   GModel::current()->getGEOInternals()->symmetry(dimTags, a, b, c, d);
5845 }
5846 
5847 // will be deprecated
symmetrize(const vectorpair & dimTags,const double a,const double b,const double c,const double d)5848 GMSH_API void gmsh::model::geo::symmetrize(const vectorpair &dimTags,
5849                                            const double a, const double b,
5850                                            const double c, const double d)
5851 {
5852   gmsh::model::geo::mirror(dimTags, a, b, c, d);
5853 }
5854 
copy(const vectorpair & dimTags,vectorpair & outDimTags)5855 GMSH_API void gmsh::model::geo::copy(const vectorpair &dimTags,
5856                                      vectorpair &outDimTags)
5857 {
5858   if(!_checkInit()) return;
5859   outDimTags.clear();
5860   GModel::current()->getGEOInternals()->copy(dimTags, outDimTags);
5861 }
5862 
remove(const vectorpair & dimTags,const bool recursive)5863 GMSH_API void gmsh::model::geo::remove(const vectorpair &dimTags,
5864                                        const bool recursive)
5865 {
5866   if(!_checkInit()) return;
5867   GModel::current()->getGEOInternals()->remove(dimTags, recursive);
5868 }
5869 
removeAllDuplicates()5870 GMSH_API void gmsh::model::geo::removeAllDuplicates()
5871 {
5872   if(!_checkInit()) return;
5873   GModel::current()->getGEOInternals()->removeAllDuplicates();
5874 }
5875 
splitCurve(const int tag,const std::vector<int> & pointTags,std::vector<int> & curveTags)5876 GMSH_API void gmsh::model::geo::splitCurve(const int tag,
5877                                            const std::vector<int> &pointTags,
5878                                            std::vector<int> &curveTags)
5879 {
5880   if(!_checkInit()) return;
5881   GModel::current()->getGEOInternals()->splitCurve(tag, pointTags, curveTags);
5882 }
5883 
getMaxTag(const int dim)5884 GMSH_API int gmsh::model::geo::getMaxTag(const int dim)
5885 {
5886   if(!_checkInit()) return -1;
5887   return GModel::current()->getGEOInternals()->getMaxTag(dim);
5888 }
5889 
setMaxTag(const int dim,const int maxTag)5890 GMSH_API void gmsh::model::geo::setMaxTag(const int dim, const int maxTag)
5891 {
5892   if(!_checkInit()) return;
5893   GModel::current()->getGEOInternals()->setMaxTag(dim, maxTag);
5894 }
5895 
addPhysicalGroup(const int dim,const std::vector<int> & tags,const int tag)5896 GMSH_API int gmsh::model::geo::addPhysicalGroup(const int dim,
5897                                                 const std::vector<int> &tags,
5898                                                 const int tag)
5899 {
5900   if(!_checkInit()) return -1;
5901   int outTag = tag;
5902   if(outTag < 0)
5903     outTag = GModel::current()->getGEOInternals()->getMaxPhysicalTag() + 1;
5904   GModel::current()->getGEOInternals()->modifyPhysicalGroup(dim, outTag, 0,
5905                                                             tags);
5906   return outTag;
5907 }
5908 
removePhysicalGroups(const vectorpair & dimTags)5909 GMSH_API void gmsh::model::geo::removePhysicalGroups(const vectorpair &dimTags)
5910 {
5911   if(!_checkInit()) return;
5912   if(dimTags.empty()) {
5913     GModel::current()->getGEOInternals()->resetPhysicalGroups();
5914   }
5915   else {
5916     for(std::size_t i = 0; i < dimTags.size(); i++) {
5917       std::vector<int> tags; // empty to delete the group
5918       GModel::current()->getGEOInternals()->modifyPhysicalGroup(
5919         dimTags[i].first, dimTags[i].second, 2, tags);
5920     }
5921   }
5922 }
5923 
synchronize()5924 GMSH_API void gmsh::model::geo::synchronize()
5925 {
5926   if(!_checkInit()) return;
5927   GModel::current()->getGEOInternals()->synchronize(GModel::current());
5928 }
5929 
5930 // gmsh::model::geo::mesh
5931 
5932 GMSH_API void
setTransfiniteCurve(const int tag,const int nPoints,const std::string & meshType,const double coef)5933 gmsh::model::geo::mesh::setTransfiniteCurve(const int tag, const int nPoints,
5934                                             const std::string &meshType,
5935                                             const double coef)
5936 {
5937   if(!_checkInit()) return;
5938   int type = (meshType == "Progression" || meshType == "Power") ? 1 :
5939              (meshType == "Bump")                               ? 2 :
5940              (meshType == "Beta")                               ? 3 :
5941                                                                   1;
5942   double c = std::abs(coef);
5943   // in .geo file we use a negative tag to do this trick; it's a bad idea
5944   if(coef < 0) type = -type;
5945 
5946   // for compatibility with geo files, try both tag and -tag
5947   for(int sig = -1; sig <= 1; sig += 2)
5948     GModel::current()->getGEOInternals()->setTransfiniteLine(sig * tag, nPoints,
5949                                                              type, c);
5950 }
5951 
setTransfiniteSurface(const int tag,const std::string & arrangement,const std::vector<int> & cornerTags)5952 GMSH_API void gmsh::model::geo::mesh::setTransfiniteSurface(
5953   const int tag, const std::string &arrangement,
5954   const std::vector<int> &cornerTags)
5955 {
5956   if(!_checkInit()) return;
5957   int t = (arrangement == "Right")          ? 1 :
5958           (arrangement == "Left")           ? -1 :
5959           (arrangement == "AlternateRight") ? 2 :
5960           (arrangement == "AlternateLeft")  ? -2 :
5961           (arrangement == "Alternate")      ? 2 :
5962                                               -1;
5963   GModel::current()->getGEOInternals()->setTransfiniteSurface(tag, t,
5964                                                               cornerTags);
5965 }
5966 
5967 GMSH_API void
setTransfiniteVolume(const int tag,const std::vector<int> & cornerTags)5968 gmsh::model::geo::mesh::setTransfiniteVolume(const int tag,
5969                                              const std::vector<int> &cornerTags)
5970 {
5971   if(!_checkInit()) return;
5972   GModel::current()->getGEOInternals()->setTransfiniteVolume(tag, cornerTags);
5973 }
5974 
setRecombine(const int dim,const int tag,const double angle)5975 GMSH_API void gmsh::model::geo::mesh::setRecombine(const int dim, const int tag,
5976                                                    const double angle)
5977 {
5978   if(!_checkInit()) return;
5979   GModel::current()->getGEOInternals()->setRecombine(dim, tag, angle);
5980 }
5981 
setSmoothing(const int dim,const int tag,const int val)5982 GMSH_API void gmsh::model::geo::mesh::setSmoothing(const int dim, const int tag,
5983                                                    const int val)
5984 {
5985   if(!_checkInit()) return;
5986   if(dim == 2) { GModel::current()->getGEOInternals()->setSmoothing(tag, val); }
5987 }
5988 
setReverse(const int dim,const int tag,const bool val)5989 GMSH_API void gmsh::model::geo::mesh::setReverse(const int dim, const int tag,
5990                                                  const bool val)
5991 {
5992   if(!_checkInit()) return;
5993   GModel::current()->getGEOInternals()->setReverseMesh(dim, tag, val);
5994 }
5995 
setAlgorithm(const int dim,const int tag,const int val)5996 GMSH_API void gmsh::model::geo::mesh::setAlgorithm(const int dim, const int tag,
5997                                                    const int val)
5998 {
5999   if(!_checkInit()) return;
6000   GModel::current()->getGEOInternals()->setMeshAlgorithm(dim, tag, val);
6001 }
6002 
setSizeFromBoundary(const int dim,const int tag,const int val)6003 GMSH_API void gmsh::model::geo::mesh::setSizeFromBoundary(const int dim,
6004                                                           const int tag,
6005                                                           const int val)
6006 {
6007   if(!_checkInit()) return;
6008   GModel::current()->getGEOInternals()->setMeshSizeFromBoundary(dim, tag, val);
6009 }
6010 
setSize(const vectorpair & dimTags,const double size)6011 GMSH_API void gmsh::model::geo::mesh::setSize(const vectorpair &dimTags,
6012                                               const double size)
6013 {
6014   if(!_checkInit()) return;
6015   for(std::size_t i = 0; i < dimTags.size(); i++) {
6016     int dim = dimTags[i].first, tag = dimTags[i].second;
6017     GModel::current()->getGEOInternals()->setMeshSize(dim, tag, size);
6018   }
6019 }
6020 
6021 // gmsh::model::occ
6022 
_createOcc()6023 static void _createOcc()
6024 {
6025   if(!GModel::current()->getOCCInternals())
6026     GModel::current()->createOCCInternals();
6027 }
6028 
addPoint(const double x,const double y,const double z,const double meshSize,const int tag)6029 GMSH_API int gmsh::model::occ::addPoint(const double x, const double y,
6030                                         const double z, const double meshSize,
6031                                         const int tag)
6032 {
6033   if(!_checkInit()) return -1;
6034   _createOcc();
6035   int outTag = tag;
6036   GModel::current()->getOCCInternals()->addVertex(outTag, x, y, z, meshSize);
6037   return outTag;
6038 }
6039 
addLine(const int startTag,const int endTag,const int tag)6040 GMSH_API int gmsh::model::occ::addLine(const int startTag, const int endTag,
6041                                        const int tag)
6042 {
6043   if(!_checkInit()) return -1;
6044   _createOcc();
6045   int outTag = tag;
6046   GModel::current()->getOCCInternals()->addLine(outTag, startTag, endTag);
6047   return outTag;
6048 }
6049 
addCircleArc(const int startTag,const int centerTag,const int endTag,const int tag)6050 GMSH_API int gmsh::model::occ::addCircleArc(const int startTag,
6051                                             const int centerTag,
6052                                             const int endTag, const int tag)
6053 {
6054   if(!_checkInit()) return -1;
6055   _createOcc();
6056   int outTag = tag;
6057   GModel::current()->getOCCInternals()->addCircleArc(outTag, startTag,
6058                                                      centerTag, endTag);
6059   return outTag;
6060 }
6061 
addCircle(const double x,const double y,const double z,const double r,const int tag,const double angle1,const double angle2)6062 GMSH_API int gmsh::model::occ::addCircle(const double x, const double y,
6063                                          const double z, const double r,
6064                                          const int tag, const double angle1,
6065                                          const double angle2)
6066 {
6067   if(!_checkInit()) return -1;
6068   _createOcc();
6069   int outTag = tag;
6070   GModel::current()->getOCCInternals()->addCircle(outTag, x, y, z, r, angle1,
6071                                                   angle2);
6072   return outTag;
6073 }
6074 
addEllipseArc(const int startTag,const int centerTag,const int majorTag,const int endTag,const int tag)6075 GMSH_API int gmsh::model::occ::addEllipseArc(const int startTag,
6076                                              const int centerTag,
6077                                              const int majorTag,
6078                                              const int endTag, const int tag)
6079 {
6080   if(!_checkInit()) return -1;
6081   _createOcc();
6082   int outTag = tag;
6083   GModel::current()->getOCCInternals()->addEllipseArc(
6084     outTag, startTag, centerTag, majorTag, endTag);
6085   return outTag;
6086 }
6087 
addEllipse(const double x,const double y,const double z,const double r1,const double r2,const int tag,const double angle1,const double angle2)6088 GMSH_API int gmsh::model::occ::addEllipse(const double x, const double y,
6089                                           const double z, const double r1,
6090                                           const double r2, const int tag,
6091                                           const double angle1,
6092                                           const double angle2)
6093 {
6094   if(!_checkInit()) return -1;
6095   _createOcc();
6096   int outTag = tag;
6097   GModel::current()->getOCCInternals()->addEllipse(outTag, x, y, z, r1, r2,
6098                                                    angle1, angle2);
6099   return outTag;
6100 }
6101 
addSpline(const std::vector<int> & pointTags,const int tag)6102 GMSH_API int gmsh::model::occ::addSpline(const std::vector<int> &pointTags,
6103                                          const int tag)
6104 {
6105   if(!_checkInit()) return -1;
6106   _createOcc();
6107   int outTag = tag;
6108   GModel::current()->getOCCInternals()->addSpline(outTag, pointTags);
6109   return outTag;
6110 }
6111 
addBSpline(const std::vector<int> & pointTags,const int tag,const int degree,const std::vector<double> & weights,const std::vector<double> & knots,const std::vector<int> & multiplicities)6112 GMSH_API int gmsh::model::occ::addBSpline(
6113   const std::vector<int> &pointTags, const int tag, const int degree,
6114   const std::vector<double> &weights, const std::vector<double> &knots,
6115   const std::vector<int> &multiplicities)
6116 {
6117   if(!_checkInit()) return -1;
6118   _createOcc();
6119   int outTag = tag;
6120   GModel::current()->getOCCInternals()->addBSpline(
6121     outTag, pointTags, degree, weights, knots, multiplicities);
6122   return outTag;
6123 }
6124 
addBezier(const std::vector<int> & pointTags,const int tag)6125 GMSH_API int gmsh::model::occ::addBezier(const std::vector<int> &pointTags,
6126                                          const int tag)
6127 {
6128   if(!_checkInit()) return -1;
6129   _createOcc();
6130   int outTag = tag;
6131   GModel::current()->getOCCInternals()->addBezier(outTag, pointTags);
6132   return outTag;
6133 }
6134 
addWire(const std::vector<int> & curveTags,const int tag,const bool checkClosed)6135 GMSH_API int gmsh::model::occ::addWire(const std::vector<int> &curveTags,
6136                                        const int tag, const bool checkClosed)
6137 {
6138   if(!_checkInit()) return -1;
6139   _createOcc();
6140   int outTag = tag;
6141   GModel::current()->getOCCInternals()->addWire(outTag, curveTags, checkClosed);
6142   return outTag;
6143 }
6144 
addCurveLoop(const std::vector<int> & curveTags,const int tag)6145 GMSH_API int gmsh::model::occ::addCurveLoop(const std::vector<int> &curveTags,
6146                                             const int tag)
6147 {
6148   if(!_checkInit()) return -1;
6149   _createOcc();
6150   int outTag = tag;
6151   GModel::current()->getOCCInternals()->addCurveLoop(outTag, curveTags);
6152   return outTag;
6153 }
6154 
addRectangle(const double x,const double y,const double z,const double dx,const double dy,const int tag,const double roundedRadius)6155 GMSH_API int gmsh::model::occ::addRectangle(const double x, const double y,
6156                                             const double z, const double dx,
6157                                             const double dy, const int tag,
6158                                             const double roundedRadius)
6159 {
6160   if(!_checkInit()) return -1;
6161   _createOcc();
6162   int outTag = tag;
6163   GModel::current()->getOCCInternals()->addRectangle(outTag, x, y, z, dx, dy,
6164                                                      roundedRadius);
6165   return outTag;
6166 }
6167 
addDisk(const double xc,const double yc,const double zc,const double rx,const double ry,const int tag)6168 GMSH_API int gmsh::model::occ::addDisk(const double xc, const double yc,
6169                                        const double zc, const double rx,
6170                                        const double ry, const int tag)
6171 {
6172   if(!_checkInit()) return -1;
6173   _createOcc();
6174   int outTag = tag;
6175   GModel::current()->getOCCInternals()->addDisk(outTag, xc, yc, zc, rx, ry);
6176   return outTag;
6177 }
6178 
addPlaneSurface(const std::vector<int> & wireTags,const int tag)6179 GMSH_API int gmsh::model::occ::addPlaneSurface(const std::vector<int> &wireTags,
6180                                                const int tag)
6181 {
6182   if(!_checkInit()) return -1;
6183   _createOcc();
6184   int outTag = tag;
6185   GModel::current()->getOCCInternals()->addPlaneSurface(outTag, wireTags);
6186   return outTag;
6187 }
6188 
addSurfaceFilling(const int wireTag,const int tag,const std::vector<int> & pointTags,const int degree,const int numPointsOnCurves,const int numIter,const bool anisotropic,const double tol2d,const double tol3d,const double tolAng,const double tolCurv,const int maxDegree,const int maxSegments)6189 GMSH_API int gmsh::model::occ::addSurfaceFilling(
6190   const int wireTag, const int tag, const std::vector<int> &pointTags,
6191   const int degree, const int numPointsOnCurves, const int numIter,
6192   const bool anisotropic, const double tol2d, const double tol3d,
6193   const double tolAng, const double tolCurv, const int maxDegree,
6194   const int maxSegments)
6195 {
6196   if(!_checkInit()) return -1;
6197   _createOcc();
6198   int outTag = tag;
6199   std::vector<int> surf, surfCont;
6200   GModel::current()->getOCCInternals()->addSurfaceFilling(
6201     outTag, wireTag, pointTags, surf, surfCont, degree, numPointsOnCurves,
6202     numIter, anisotropic, tol2d, tol3d, tolAng, tolCurv, maxDegree,
6203     maxSegments);
6204   return outTag;
6205 }
6206 
addBSplineFilling(const int wireTag,const int tag,const std::string & type)6207 GMSH_API int gmsh::model::occ::addBSplineFilling(const int wireTag,
6208                                                  const int tag,
6209                                                  const std::string &type)
6210 {
6211   if(!_checkInit()) return -1;
6212   _createOcc();
6213   int outTag = tag;
6214   GModel::current()->getOCCInternals()->addBSplineFilling(outTag, wireTag,
6215                                                           type);
6216   return outTag;
6217 }
6218 
addBezierFilling(const int wireTag,const int tag,const std::string & type)6219 GMSH_API int gmsh::model::occ::addBezierFilling(const int wireTag,
6220                                                 const int tag,
6221                                                 const std::string &type)
6222 {
6223   if(!_checkInit()) return -1;
6224   _createOcc();
6225   int outTag = tag;
6226   GModel::current()->getOCCInternals()->addBezierFilling(outTag, wireTag, type);
6227   return outTag;
6228 }
6229 
addBSplineSurface(const std::vector<int> & pointTags,const int numPointsU,const int tag,const int degreeU,const int degreeV,const std::vector<double> & weights,const std::vector<double> & knotsU,const std::vector<double> & knotsV,const std::vector<int> & multiplicitiesU,const std::vector<int> & multiplicitiesV,const std::vector<int> & wireTags,const bool wire3D)6230 GMSH_API int gmsh::model::occ::addBSplineSurface(
6231   const std::vector<int> &pointTags, const int numPointsU, const int tag,
6232   const int degreeU, const int degreeV, const std::vector<double> &weights,
6233   const std::vector<double> &knotsU, const std::vector<double> &knotsV,
6234   const std::vector<int> &multiplicitiesU,
6235   const std::vector<int> &multiplicitiesV, const std::vector<int> &wireTags,
6236   const bool wire3D)
6237 {
6238   if(!_checkInit()) return -1;
6239   _createOcc();
6240   int outTag = tag;
6241   GModel::current()->getOCCInternals()->addBSplineSurface(
6242     outTag, pointTags, numPointsU, degreeU, degreeV, weights, knotsU, knotsV,
6243     multiplicitiesU, multiplicitiesV, wireTags, wire3D);
6244   return outTag;
6245 }
6246 
addBezierSurface(const std::vector<int> & pointTags,const int numPointsU,const int tag,const std::vector<int> & wireTags,const bool wire3D)6247 GMSH_API int gmsh::model::occ::addBezierSurface(
6248   const std::vector<int> &pointTags, const int numPointsU, const int tag,
6249   const std::vector<int> &wireTags, const bool wire3D)
6250 {
6251   if(!_checkInit()) return -1;
6252   _createOcc();
6253   int outTag = tag;
6254   GModel::current()->getOCCInternals()->addBezierSurface(
6255     outTag, pointTags, numPointsU, wireTags, wire3D);
6256   return outTag;
6257 }
6258 
6259 GMSH_API int
addTrimmedSurface(const int surfaceTag,const std::vector<int> & wireTags,const bool wire3D,const int tag)6260 gmsh::model::occ::addTrimmedSurface(const int surfaceTag,
6261                                     const std::vector<int> &wireTags,
6262                                     const bool wire3D, const int tag)
6263 {
6264   if(!_checkInit()) return -1;
6265   _createOcc();
6266   int outTag = tag;
6267   GModel::current()->getOCCInternals()->addTrimmedSurface(outTag, surfaceTag,
6268                                                           wireTags, wire3D);
6269   return outTag;
6270 }
6271 
6272 GMSH_API int
addSurfaceLoop(const std::vector<int> & surfaceTags,const int tag,const bool sewing)6273 gmsh::model::occ::addSurfaceLoop(const std::vector<int> &surfaceTags,
6274                                  const int tag, const bool sewing)
6275 {
6276   if(!_checkInit()) return -1;
6277   _createOcc();
6278   int outTag = tag;
6279   GModel::current()->getOCCInternals()->addSurfaceLoop(outTag, surfaceTags,
6280                                                        sewing);
6281   return outTag;
6282 }
6283 
addVolume(const std::vector<int> & shellTags,const int tag)6284 GMSH_API int gmsh::model::occ::addVolume(const std::vector<int> &shellTags,
6285                                          const int tag)
6286 {
6287   if(!_checkInit()) return -1;
6288   _createOcc();
6289   int outTag = tag;
6290   GModel::current()->getOCCInternals()->addVolume(outTag, shellTags);
6291   return outTag;
6292 }
6293 
addSphere(const double xc,const double yc,const double zc,const double radius,const int tag,const double angle1,const double angle2,const double angle3)6294 GMSH_API int gmsh::model::occ::addSphere(const double xc, const double yc,
6295                                          const double zc, const double radius,
6296                                          const int tag, const double angle1,
6297                                          const double angle2,
6298                                          const double angle3)
6299 {
6300   if(!_checkInit()) return -1;
6301   _createOcc();
6302   int outTag = tag;
6303   GModel::current()->getOCCInternals()->addSphere(outTag, xc, yc, zc, radius,
6304                                                   angle1, angle2, angle3);
6305   return outTag;
6306 }
6307 
addBox(const double x,const double y,const double z,const double dx,const double dy,const double dz,const int tag)6308 GMSH_API int gmsh::model::occ::addBox(const double x, const double y,
6309                                       const double z, const double dx,
6310                                       const double dy, const double dz,
6311                                       const int tag)
6312 {
6313   if(!_checkInit()) return -1;
6314   _createOcc();
6315   int outTag = tag;
6316   GModel::current()->getOCCInternals()->addBox(outTag, x, y, z, dx, dy, dz);
6317   return outTag;
6318 }
6319 
addCylinder(const double x,const double y,const double z,const double dx,const double dy,const double dz,const double r,const int tag,const double angle)6320 GMSH_API int gmsh::model::occ::addCylinder(const double x, const double y,
6321                                            const double z, const double dx,
6322                                            const double dy, const double dz,
6323                                            const double r, const int tag,
6324                                            const double angle)
6325 {
6326   if(!_checkInit()) return -1;
6327   _createOcc();
6328   int outTag = tag;
6329   GModel::current()->getOCCInternals()->addCylinder(outTag, x, y, z, dx, dy, dz,
6330                                                     r, angle);
6331   return outTag;
6332 }
6333 
addCone(const double x,const double y,const double z,const double dx,const double dy,const double dz,const double r1,const double r2,const int tag,const double angle)6334 GMSH_API int gmsh::model::occ::addCone(const double x, const double y,
6335                                        const double z, const double dx,
6336                                        const double dy, const double dz,
6337                                        const double r1, const double r2,
6338                                        const int tag, const double angle)
6339 {
6340   if(!_checkInit()) return -1;
6341   _createOcc();
6342   int outTag = tag;
6343   GModel::current()->getOCCInternals()->addCone(outTag, x, y, z, dx, dy, dz, r1,
6344                                                 r2, angle);
6345   return outTag;
6346 }
6347 
addWedge(const double x,const double y,const double z,const double dx,const double dy,const double dz,const int tag,const double ltx)6348 GMSH_API int gmsh::model::occ::addWedge(const double x, const double y,
6349                                         const double z, const double dx,
6350                                         const double dy, const double dz,
6351                                         const int tag, const double ltx)
6352 {
6353   if(!_checkInit()) return -1;
6354   _createOcc();
6355   int outTag = tag;
6356   GModel::current()->getOCCInternals()->addWedge(outTag, x, y, z, dx, dy, dz,
6357                                                  ltx);
6358   return outTag;
6359 }
6360 
addTorus(const double x,const double y,const double z,const double r1,const double r2,const int tag,const double angle)6361 GMSH_API int gmsh::model::occ::addTorus(const double x, const double y,
6362                                         const double z, const double r1,
6363                                         const double r2, const int tag,
6364                                         const double angle)
6365 {
6366   if(!_checkInit()) return -1;
6367   _createOcc();
6368   int outTag = tag;
6369   GModel::current()->getOCCInternals()->addTorus(outTag, x, y, z, r1, r2,
6370                                                  angle);
6371   return outTag;
6372 }
6373 
addThruSections(const std::vector<int> & wireTags,vectorpair & outDimTags,const int tag,const bool makeSolid,const bool makeRuled,const int maxDegree)6374 GMSH_API void gmsh::model::occ::addThruSections(
6375   const std::vector<int> &wireTags, vectorpair &outDimTags, const int tag,
6376   const bool makeSolid, const bool makeRuled, const int maxDegree)
6377 {
6378   if(!_checkInit()) return;
6379   _createOcc();
6380   outDimTags.clear();
6381   GModel::current()->getOCCInternals()->addThruSections(
6382     tag, wireTags, makeSolid, makeRuled, outDimTags, maxDegree);
6383 }
6384 
addThickSolid(const int volumeTag,const std::vector<int> & excludeSurfaceTags,const double offset,vectorpair & outDimTags,const int tag)6385 GMSH_API void gmsh::model::occ::addThickSolid(
6386   const int volumeTag, const std::vector<int> &excludeSurfaceTags,
6387   const double offset, vectorpair &outDimTags, const int tag)
6388 {
6389   if(!_checkInit()) return;
6390   _createOcc();
6391   outDimTags.clear();
6392   GModel::current()->getOCCInternals()->addThickSolid(
6393     tag, volumeTag, excludeSurfaceTags, offset, outDimTags);
6394 }
6395 
extrude(const vectorpair & dimTags,const double dx,const double dy,const double dz,vectorpair & outDimTags,const std::vector<int> & numElements,const std::vector<double> & heights,const bool recombine)6396 GMSH_API void gmsh::model::occ::extrude(const vectorpair &dimTags,
6397                                         const double dx, const double dy,
6398                                         const double dz, vectorpair &outDimTags,
6399                                         const std::vector<int> &numElements,
6400                                         const std::vector<double> &heights,
6401                                         const bool recombine)
6402 {
6403   if(!_checkInit()) return;
6404   _createOcc();
6405   outDimTags.clear();
6406   ExtrudeParams *e = _getExtrudeParams(numElements, heights, recombine);
6407   GModel::current()->getOCCInternals()->extrude(
6408     dimTags, dx, dy, dz, outDimTags, e);
6409   if(e) delete e;
6410 }
6411 
revolve(const vectorpair & dimTags,const double x,const double y,const double z,const double ax,const double ay,const double az,const double angle,vectorpair & outDimTags,const std::vector<int> & numElements,const std::vector<double> & heights,const bool recombine)6412 GMSH_API void gmsh::model::occ::revolve(
6413   const vectorpair &dimTags, const double x, const double y, const double z,
6414   const double ax, const double ay, const double az, const double angle,
6415   vectorpair &outDimTags, const std::vector<int> &numElements,
6416   const std::vector<double> &heights, const bool recombine)
6417 {
6418   if(!_checkInit()) return;
6419   _createOcc();
6420   outDimTags.clear();
6421   ExtrudeParams *e = _getExtrudeParams(numElements, heights, recombine);
6422   GModel::current()->getOCCInternals()->revolve(
6423     dimTags, x, y, z, ax, ay, az, angle, outDimTags, e);
6424   if(e) delete e;
6425 }
6426 
addPipe(const vectorpair & dimTags,const int wireTag,vectorpair & outDimTags,const std::string & trihedron)6427 GMSH_API void gmsh::model::occ::addPipe(const vectorpair &dimTags,
6428                                         const int wireTag,
6429                                         vectorpair &outDimTags,
6430                                         const std::string &trihedron)
6431 {
6432   if(!_checkInit()) return;
6433   _createOcc();
6434   outDimTags.clear();
6435   GModel::current()->getOCCInternals()->addPipe(dimTags, wireTag, outDimTags,
6436                                                 trihedron);
6437 }
6438 
fillet(const std::vector<int> & volumeTags,const std::vector<int> & curveTags,const std::vector<double> & radii,vectorpair & outDimTags,const bool removeVolume)6439 GMSH_API void gmsh::model::occ::fillet(const std::vector<int> &volumeTags,
6440                                        const std::vector<int> &curveTags,
6441                                        const std::vector<double> &radii,
6442                                        vectorpair &outDimTags,
6443                                        const bool removeVolume)
6444 {
6445   if(!_checkInit()) return;
6446   _createOcc();
6447   outDimTags.clear();
6448   GModel::current()->getOCCInternals()->fillet(volumeTags, curveTags, radii,
6449                                                outDimTags, removeVolume);
6450 }
6451 
chamfer(const std::vector<int> & volumeTags,const std::vector<int> & curveTags,const std::vector<int> & surfaceTags,const std::vector<double> & distances,vectorpair & outDimTags,const bool removeVolume)6452 GMSH_API void gmsh::model::occ::chamfer(const std::vector<int> &volumeTags,
6453                                         const std::vector<int> &curveTags,
6454                                         const std::vector<int> &surfaceTags,
6455                                         const std::vector<double> &distances,
6456                                         vectorpair &outDimTags,
6457                                         const bool removeVolume)
6458 {
6459   if(!_checkInit()) return;
6460   _createOcc();
6461   outDimTags.clear();
6462   GModel::current()->getOCCInternals()->chamfer(
6463     volumeTags, curveTags, surfaceTags, distances, outDimTags, removeVolume);
6464 }
6465 
fuse(const vectorpair & objectDimTags,const vectorpair & toolDimTags,vectorpair & outDimTags,std::vector<vectorpair> & outDimTagsMap,const int tag,const bool removeObject,const bool removeTool)6466 GMSH_API void gmsh::model::occ::fuse(const vectorpair &objectDimTags,
6467                                      const vectorpair &toolDimTags,
6468                                      vectorpair &outDimTags,
6469                                      std::vector<vectorpair> &outDimTagsMap,
6470                                      const int tag, const bool removeObject,
6471                                      const bool removeTool)
6472 {
6473   if(!_checkInit()) return;
6474   _createOcc();
6475   outDimTags.clear();
6476   outDimTagsMap.clear();
6477   GModel::current()->getOCCInternals()->booleanUnion(
6478     tag, objectDimTags, toolDimTags, outDimTags, outDimTagsMap, removeObject,
6479     removeTool);
6480 }
6481 
intersect(const vectorpair & objectDimTags,const vectorpair & toolDimTags,vectorpair & outDimTags,std::vector<vectorpair> & outDimTagsMap,const int tag,const bool removeObject,const bool removeTool)6482 GMSH_API void gmsh::model::occ::intersect(
6483   const vectorpair &objectDimTags, const vectorpair &toolDimTags,
6484   vectorpair &outDimTags, std::vector<vectorpair> &outDimTagsMap, const int tag,
6485   const bool removeObject, const bool removeTool)
6486 {
6487   if(!_checkInit()) return;
6488   _createOcc();
6489   outDimTags.clear();
6490   outDimTagsMap.clear();
6491   GModel::current()->getOCCInternals()->booleanIntersection(
6492     tag, objectDimTags, toolDimTags, outDimTags, outDimTagsMap, removeObject,
6493     removeTool);
6494 }
6495 
cut(const vectorpair & objectDimTags,const vectorpair & toolDimTags,vectorpair & outDimTags,std::vector<vectorpair> & outDimTagsMap,const int tag,const bool removeObject,const bool removeTool)6496 GMSH_API void gmsh::model::occ::cut(const vectorpair &objectDimTags,
6497                                     const vectorpair &toolDimTags,
6498                                     vectorpair &outDimTags,
6499                                     std::vector<vectorpair> &outDimTagsMap,
6500                                     const int tag, const bool removeObject,
6501                                     const bool removeTool)
6502 {
6503   if(!_checkInit()) return;
6504   _createOcc();
6505   outDimTags.clear();
6506   outDimTagsMap.clear();
6507   GModel::current()->getOCCInternals()->booleanDifference(
6508     tag, objectDimTags, toolDimTags, outDimTags, outDimTagsMap, removeObject,
6509     removeTool);
6510 }
6511 
fragment(const vectorpair & objectDimTags,const vectorpair & toolDimTags,vectorpair & outDimTags,std::vector<vectorpair> & outDimTagsMap,const int tag,const bool removeObject,const bool removeTool)6512 GMSH_API void gmsh::model::occ::fragment(const vectorpair &objectDimTags,
6513                                          const vectorpair &toolDimTags,
6514                                          vectorpair &outDimTags,
6515                                          std::vector<vectorpair> &outDimTagsMap,
6516                                          const int tag, const bool removeObject,
6517                                          const bool removeTool)
6518 {
6519   if(!_checkInit()) return;
6520   _createOcc();
6521   outDimTags.clear();
6522   outDimTagsMap.clear();
6523   GModel::current()->getOCCInternals()->booleanFragments(
6524     tag, objectDimTags, toolDimTags, outDimTags, outDimTagsMap, removeObject,
6525     removeTool);
6526 }
6527 
translate(const vectorpair & dimTags,const double dx,const double dy,const double dz)6528 GMSH_API void gmsh::model::occ::translate(const vectorpair &dimTags,
6529                                           const double dx, const double dy,
6530                                           const double dz)
6531 {
6532   if(!_checkInit()) return;
6533   _createOcc();
6534   GModel::current()->getOCCInternals()->translate(dimTags, dx, dy, dz);
6535 }
6536 
rotate(const vectorpair & dimTags,const double x,const double y,const double z,const double ax,const double ay,const double az,const double angle)6537 GMSH_API void gmsh::model::occ::rotate(const vectorpair &dimTags,
6538                                        const double x, const double y,
6539                                        const double z, const double ax,
6540                                        const double ay, const double az,
6541                                        const double angle)
6542 {
6543   if(!_checkInit()) return;
6544   _createOcc();
6545   GModel::current()->getOCCInternals()->rotate(dimTags, x, y, z, ax, ay, az,
6546                                                angle);
6547 }
6548 
dilate(const vectorpair & dimTags,const double x,const double y,const double z,const double a,const double b,const double c)6549 GMSH_API void gmsh::model::occ::dilate(const vectorpair &dimTags,
6550                                        const double x, const double y,
6551                                        const double z, const double a,
6552                                        const double b, const double c)
6553 {
6554   if(!_checkInit()) return;
6555   _createOcc();
6556   GModel::current()->getOCCInternals()->dilate(dimTags, x, y, z, a, b, c);
6557 }
6558 
mirror(const vectorpair & dimTags,const double a,const double b,const double c,const double d)6559 GMSH_API void gmsh::model::occ::mirror(const vectorpair &dimTags,
6560                                        const double a, const double b,
6561                                        const double c, const double d)
6562 {
6563   if(!_checkInit()) return;
6564   _createOcc();
6565   GModel::current()->getOCCInternals()->symmetry(dimTags, a, b, c, d);
6566 }
6567 
symmetrize(const vectorpair & dimTags,const double a,const double b,const double c,const double d)6568 GMSH_API void gmsh::model::occ::symmetrize(const vectorpair &dimTags,
6569                                            const double a, const double b,
6570                                            const double c, const double d)
6571 {
6572   gmsh::model::occ::mirror(dimTags, a, b, c, d);
6573 }
6574 
6575 GMSH_API void
affineTransform(const vectorpair & dimTags,const std::vector<double> & affineTransform)6576 gmsh::model::occ::affineTransform(const vectorpair &dimTags,
6577                                   const std::vector<double> &affineTransform)
6578 {
6579   if(!_checkInit()) return;
6580   _createOcc();
6581   GModel::current()->getOCCInternals()->affine(dimTags, affineTransform);
6582 }
6583 
copy(const vectorpair & dimTags,vectorpair & outDimTags)6584 GMSH_API void gmsh::model::occ::copy(const vectorpair &dimTags,
6585                                      vectorpair &outDimTags)
6586 {
6587   if(!_checkInit()) return;
6588   _createOcc();
6589   outDimTags.clear();
6590   GModel::current()->getOCCInternals()->copy(dimTags, outDimTags);
6591 }
6592 
remove(const vectorpair & dimTags,const bool recursive)6593 GMSH_API void gmsh::model::occ::remove(const vectorpair &dimTags,
6594                                        const bool recursive)
6595 {
6596   if(!_checkInit()) return;
6597   _createOcc();
6598   GModel::current()->getOCCInternals()->remove(dimTags, recursive);
6599 }
6600 
removeAllDuplicates()6601 GMSH_API void gmsh::model::occ::removeAllDuplicates()
6602 {
6603   if(!_checkInit()) return;
6604   _createOcc();
6605   GModel::current()->getOCCInternals()->removeAllDuplicates();
6606 }
6607 
healShapes(vectorpair & outDimTags,const vectorpair & inDimTags,const double tolerance,const bool fixDegenerated,const bool fixSmallEdges,const bool fixSmallFaces,const bool sewFaces,const bool makeSolids)6608 GMSH_API void gmsh::model::occ::healShapes(
6609   vectorpair &outDimTags, const vectorpair &inDimTags, const double tolerance,
6610   const bool fixDegenerated, const bool fixSmallEdges, const bool fixSmallFaces,
6611   const bool sewFaces, const bool makeSolids)
6612 {
6613   if(!_checkInit()) return;
6614   _createOcc();
6615   outDimTags.clear();
6616   GModel::current()->getOCCInternals()->healShapes(
6617     inDimTags, outDimTags, tolerance, fixDegenerated, fixSmallEdges,
6618     fixSmallFaces, sewFaces, makeSolids);
6619 }
6620 
importShapes(const std::string & fileName,vectorpair & outDimTags,const bool highestDimOnly,const std::string & format)6621 GMSH_API void gmsh::model::occ::importShapes(const std::string &fileName,
6622                                              vectorpair &outDimTags,
6623                                              const bool highestDimOnly,
6624                                              const std::string &format)
6625 {
6626   if(!_checkInit()) return;
6627   _createOcc();
6628   outDimTags.clear();
6629   GModel::current()->getOCCInternals()->importShapes(fileName, highestDimOnly,
6630                                                      outDimTags, format);
6631 }
6632 
importShapesNativePointer(const void * shape,vectorpair & outDimTags,const bool highestDimOnly)6633 GMSH_API void gmsh::model::occ::importShapesNativePointer(
6634   const void *shape, vectorpair &outDimTags, const bool highestDimOnly)
6635 {
6636   if(!_checkInit()) return;
6637   _createOcc();
6638   outDimTags.clear();
6639 #if defined(HAVE_OCC)
6640   GModel::current()->getOCCInternals()->importShapes(
6641     static_cast<const TopoDS_Shape *>(shape), highestDimOnly, outDimTags);
6642 #else
6643   Msg::Error("Gmsh requires OpenCASCADE to import native shape");
6644 #endif
6645 }
6646 
getEntities(vectorpair & dimTags,const int dim)6647 GMSH_API void gmsh::model::occ::getEntities(vectorpair &dimTags, const int dim)
6648 {
6649   if(!_checkInit()) return;
6650   _createOcc();
6651   GModel::current()->getOCCInternals()->getEntities(dimTags, dim);
6652 }
6653 
getEntitiesInBoundingBox(const double xmin,const double ymin,const double zmin,const double xmax,const double ymax,const double zmax,vectorpair & dimTags,const int dim)6654 GMSH_API void gmsh::model::occ::getEntitiesInBoundingBox(
6655   const double xmin, const double ymin, const double zmin, const double xmax,
6656   const double ymax, const double zmax, vectorpair &dimTags, const int dim)
6657 {
6658   if(!_checkInit()) return;
6659   _createOcc();
6660   dimTags.clear();
6661   GModel::current()->getOCCInternals()->getEntitiesInBoundingBox(
6662     xmin, ymin, zmin, xmax, ymax, zmax, dimTags, dim);
6663 }
6664 
getBoundingBox(const int dim,const int tag,double & xmin,double & ymin,double & zmin,double & xmax,double & ymax,double & zmax)6665 GMSH_API void gmsh::model::occ::getBoundingBox(const int dim, const int tag,
6666                                                double &xmin, double &ymin,
6667                                                double &zmin, double &xmax,
6668                                                double &ymax, double &zmax)
6669 {
6670   if(!_checkInit()) return;
6671   _createOcc();
6672   GModel::current()->getOCCInternals()->getBoundingBox(dim, tag, xmin, ymin,
6673                                                        zmin, xmax, ymax, zmax);
6674 }
6675 
getMass(const int dim,const int tag,double & mass)6676 GMSH_API void gmsh::model::occ::getMass(const int dim, const int tag,
6677                                         double &mass)
6678 {
6679   if(!_checkInit()) return;
6680   _createOcc();
6681   GModel::current()->getOCCInternals()->getMass(dim, tag, mass);
6682 }
6683 
getCenterOfMass(const int dim,const int tag,double & x,double & y,double & z)6684 GMSH_API void gmsh::model::occ::getCenterOfMass(const int dim, const int tag,
6685                                                 double &x, double &y, double &z)
6686 {
6687   if(!_checkInit()) return;
6688   _createOcc();
6689   GModel::current()->getOCCInternals()->getCenterOfMass(dim, tag, x, y, z);
6690 }
6691 
getMatrixOfInertia(const int dim,const int tag,std::vector<double> & m)6692 GMSH_API void gmsh::model::occ::getMatrixOfInertia(const int dim, const int tag,
6693                                                    std::vector<double> &m)
6694 {
6695   if(!_checkInit()) return;
6696   _createOcc();
6697   GModel::current()->getOCCInternals()->getMatrixOfInertia(dim, tag, m);
6698 }
6699 
getMaxTag(const int dim)6700 GMSH_API int gmsh::model::occ::getMaxTag(const int dim)
6701 {
6702   if(!_checkInit()) return -1;
6703   _createOcc();
6704   return GModel::current()->getOCCInternals()->getMaxTag(dim);
6705 }
6706 
setMaxTag(const int dim,const int maxTag)6707 GMSH_API void gmsh::model::occ::setMaxTag(const int dim, const int maxTag)
6708 {
6709   if(!_checkInit()) return;
6710   _createOcc();
6711   GModel::current()->getOCCInternals()->setMaxTag(dim, maxTag);
6712 }
6713 
synchronize()6714 GMSH_API void gmsh::model::occ::synchronize()
6715 {
6716   if(!_checkInit()) return;
6717   _createOcc();
6718   GModel::current()->getOCCInternals()->synchronize(GModel::current());
6719 }
6720 
6721 // gmsh::model::occ::mesh
6722 
setSize(const vectorpair & dimTags,const double size)6723 GMSH_API void gmsh::model::occ::mesh::setSize(const vectorpair &dimTags,
6724                                               const double size)
6725 {
6726   if(!_checkInit()) return;
6727   _createOcc();
6728   for(std::size_t i = 0; i < dimTags.size(); i++) {
6729     int dim = dimTags[i].first, tag = dimTags[i].second;
6730     GModel::current()->getOCCInternals()->setMeshSize(dim, tag, size);
6731   }
6732 }
6733 
6734 // gmsh::view
6735 
add(const std::string & name,const int tag)6736 GMSH_API int gmsh::view::add(const std::string &name, const int tag)
6737 {
6738   if(!_checkInit()) return -1;
6739 #if defined(HAVE_POST)
6740   PView *view = new PView(tag);
6741   view->getData()->setName(name);
6742 #if defined(HAVE_FLTK)
6743   if(FlGui::available()) FlGui::instance()->updateViews(true, true);
6744 #endif
6745   return view->getTag();
6746 #else
6747   Msg::Error("Views require the post-processing module");
6748   return -1;
6749 #endif
6750 }
6751 
remove(const int tag)6752 GMSH_API void gmsh::view::remove(const int tag)
6753 {
6754   if(!_checkInit()) return;
6755 #if defined(HAVE_POST)
6756   PView *view = PView::getViewByTag(tag);
6757   if(!view) {
6758     Msg::Error("Unknown view with tag %d", tag);
6759     return;
6760   }
6761   delete view;
6762 #if defined(HAVE_FLTK)
6763   if(FlGui::available()) FlGui::instance()->updateViews(true, true);
6764 #endif
6765 #else
6766   Msg::Error("Views require the post-processing module");
6767 #endif
6768 }
6769 
getIndex(const int tag)6770 GMSH_API int gmsh::view::getIndex(const int tag)
6771 {
6772   if(!_checkInit()) return -1;
6773 #if defined(HAVE_POST)
6774   PView *view = PView::getViewByTag(tag);
6775   if(!view) {
6776     Msg::Error("Unknown view with tag %d", tag);
6777     return -1;
6778   }
6779   return view->getIndex();
6780 #else
6781   Msg::Error("Views require the post-processing module");
6782   return -1;
6783 #endif
6784 }
6785 
getTags(std::vector<int> & tags)6786 GMSH_API void gmsh::view::getTags(std::vector<int> &tags)
6787 {
6788   if(!_checkInit()) return;
6789 #if defined(HAVE_POST)
6790   tags.clear();
6791   for(std::size_t i = 0; i < PView::list.size(); i++)
6792     tags.push_back(PView::list[i]->getTag());
6793 #else
6794   Msg::Error("Views require the post-processing module");
6795 #endif
6796 }
6797 
6798 template <class T>
6799 static void
_addModelData(const int tag,const int step,const std::string & modelName,const std::string & dataType,const std::vector<std::size_t> & tags,const T & data,const double time,const int numComponents,const int partition)6800 _addModelData(const int tag, const int step, const std::string &modelName,
6801               const std::string &dataType, const std::vector<std::size_t> &tags,
6802               const T &data, const double time, const int numComponents,
6803               const int partition)
6804 {
6805 #if defined(HAVE_POST)
6806   PView *view = PView::getViewByTag(tag);
6807   if(!view) {
6808     Msg::Error("Unknown view with tag %d", tag);
6809     return;
6810   }
6811   GModel *model = GModel::current();
6812   if(modelName.size()) {
6813     model = GModel::findByName(modelName);
6814     if(!model) {
6815       Msg::Error("Unknown model '%s'", modelName.c_str());
6816       return;
6817     }
6818   }
6819   PViewDataGModel::DataType type;
6820   if(dataType == "NodeData")
6821     type = PViewDataGModel::NodeData;
6822   else if(dataType == "ElementData")
6823     type = PViewDataGModel::ElementData;
6824   else if(dataType == "ElementNodeData")
6825     type = PViewDataGModel::ElementNodeData;
6826   else if(dataType == "GaussPointData")
6827     type = PViewDataGModel::GaussPointData;
6828   else if(dataType == "Beam")
6829     type = PViewDataGModel::BeamData;
6830   else {
6831     Msg::Error("Unknown type of view to add '%s'", dataType.c_str());
6832     return;
6833   }
6834 
6835   PViewDataGModel *d = dynamic_cast<PViewDataGModel *>(view->getData());
6836   bool changeType = false;
6837   if(d && d->getType() != type) {
6838     Msg::Warning("Changing type of view to '%s'", dataType.c_str());
6839     changeType = true;
6840   }
6841   if(!d || changeType) { // change view type
6842     std::string name = view->getData()->getName();
6843     delete view->getData();
6844     d = new PViewDataGModel(type);
6845     d->setName(name);
6846     d->setFileName(name + ".msh");
6847     view->setData(d);
6848   }
6849   if(!d->addData(model, tags, data, step, time, partition, numComponents)) {
6850     Msg::Error("Could not add model data");
6851     return;
6852   }
6853   if(view->getOptions()->adaptVisualizationGrid)
6854     d->initAdaptiveData(view->getOptions()->timeStep,
6855                         view->getOptions()->maxRecursionLevel,
6856                         view->getOptions()->targetError);
6857   view->setChanged(true);
6858 #else
6859   Msg::Error("Views require the post-processing module");
6860 #endif
6861 }
6862 
addModelData(const int tag,const int step,const std::string & modelName,const std::string & dataType,const std::vector<std::size_t> & tags,const std::vector<std::vector<double>> & data,const double time,const int numComponents,const int partition)6863 GMSH_API void gmsh::view::addModelData(
6864   const int tag, const int step, const std::string &modelName,
6865   const std::string &dataType, const std::vector<std::size_t> &tags,
6866   const std::vector<std::vector<double> > &data, const double time,
6867   const int numComponents, const int partition)
6868 {
6869   if(!_checkInit()) return;
6870   if(tags.size() != data.size()) {
6871     Msg::Error("Incompatible number of tags and data");
6872     return;
6873   }
6874   _addModelData(tag, step, modelName, dataType, tags, data, time, numComponents,
6875                 partition);
6876 }
6877 
addHomogeneousModelData(const int tag,const int step,const std::string & modelName,const std::string & dataType,const std::vector<std::size_t> & tags,const std::vector<double> & data,const double time,const int numComponents,const int partition)6878 GMSH_API void gmsh::view::addHomogeneousModelData(
6879   const int tag, const int step, const std::string &modelName,
6880   const std::string &dataType, const std::vector<std::size_t> &tags,
6881   const std::vector<double> &data, const double time, const int numComponents,
6882   const int partition)
6883 {
6884   if(!_checkInit()) return;
6885   _addModelData(tag, step, modelName, dataType, tags, data, time, numComponents,
6886                 partition);
6887 }
6888 
6889 #if defined(HAVE_POST)
_getModelData(const int tag,const int step,std::string & dataType,double & time,int & numComponents,int & numEnt,int & maxMult)6890 static stepData<double> *_getModelData(const int tag, const int step,
6891                                        std::string &dataType, double &time,
6892                                        int &numComponents, int &numEnt,
6893                                        int &maxMult)
6894 {
6895   if(!_checkInit()) return nullptr;
6896   PView *view = PView::getViewByTag(tag);
6897   if(!view) {
6898     Msg::Error("Unknown view with tag %d", tag);
6899     return nullptr;
6900   }
6901   PViewDataGModel *d = dynamic_cast<PViewDataGModel *>(view->getData());
6902   if(!d) {
6903     Msg::Error("View with tag %d does not contain model data", tag);
6904     return nullptr;
6905   }
6906   if(d->getType() == PViewDataGModel::NodeData)
6907     dataType = "NodeData";
6908   else if(d->getType() == PViewDataGModel::ElementData)
6909     dataType = "ElementData";
6910   else if(d->getType() == PViewDataGModel::ElementNodeData)
6911     dataType = "ElementNodeData";
6912   else if(d->getType() == PViewDataGModel::GaussPointData)
6913     dataType = "GaussPointData";
6914   else if(d->getType() == PViewDataGModel::BeamData)
6915     dataType = "Beam";
6916   else
6917     dataType = "Unknown";
6918   stepData<double> *s = d->getStepData(step);
6919   if(!s) {
6920     Msg::Error("View with tag %d does not contain model data for step %d", tag,
6921                step);
6922     return nullptr;
6923   }
6924   time = s->getTime();
6925   numComponents = s->getNumComponents();
6926   numEnt = 0;
6927   maxMult = 0;
6928   for(std::size_t i = 0; i < s->getNumData(); i++) {
6929     if(s->getData(i)) {
6930       numEnt++;
6931       maxMult = std::max(maxMult, s->getMult(i));
6932     }
6933   }
6934   return s;
6935 }
6936 #endif
6937 
getModelData(const int tag,const int step,std::string & dataType,std::vector<std::size_t> & tags,std::vector<std::vector<double>> & data,double & time,int & numComponents)6938 GMSH_API void gmsh::view::getModelData(const int tag, const int step,
6939                                        std::string &dataType,
6940                                        std::vector<std::size_t> &tags,
6941                                        std::vector<std::vector<double> > &data,
6942                                        double &time, int &numComponents)
6943 {
6944   if(!_checkInit()) return;
6945   tags.clear();
6946   data.clear();
6947 #if defined(HAVE_POST)
6948   int numEnt, maxMult;
6949   stepData<double> *s =
6950     _getModelData(tag, step, dataType, time, numComponents, numEnt, maxMult);
6951   if(!s || !numComponents || !numEnt || !maxMult) return;
6952   data.resize(numEnt);
6953   tags.resize(numEnt);
6954   std::size_t j = 0;
6955   for(std::size_t i = 0; i < s->getNumData(); i++) {
6956     double *dd = s->getData(i);
6957     if(dd) {
6958       tags[j] = i;
6959       int mult = s->getMult(i);
6960       data[j].resize(numComponents * mult);
6961       for(int k = 0; k < numComponents * mult; k++) data[j][k] = dd[k];
6962       j++;
6963     }
6964   }
6965 #else
6966   Msg::Error("Views require the post-processing module");
6967 #endif
6968 }
6969 
getHomogeneousModelData(const int tag,const int step,std::string & dataType,std::vector<std::size_t> & tags,std::vector<double> & data,double & time,int & numComponents)6970 GMSH_API void gmsh::view::getHomogeneousModelData(
6971   const int tag, const int step, std::string &dataType,
6972   std::vector<std::size_t> &tags, std::vector<double> &data, double &time,
6973   int &numComponents)
6974 {
6975   if(!_checkInit()) return;
6976   tags.clear();
6977   data.clear();
6978 #if defined(HAVE_POST)
6979   int numEnt, maxMult;
6980   stepData<double> *s =
6981     _getModelData(tag, step, dataType, time, numComponents, numEnt, maxMult);
6982   if(!s || !numComponents || !numEnt || !maxMult) return;
6983   data.resize(numEnt * numComponents * maxMult, 0.);
6984   tags.resize(numEnt);
6985   std::size_t j = 0;
6986   for(std::size_t i = 0; i < s->getNumData(); i++) {
6987     double *dd = s->getData(i);
6988     if(dd) {
6989       tags[j] = i;
6990       int mult = s->getMult(i);
6991       for(int k = 0; k < numComponents * mult; k++) {
6992         data[j * numComponents * maxMult + k] = dd[k];
6993       }
6994       j++;
6995     }
6996   }
6997 #else
6998   Msg::Error("Views require the post-processing module");
6999 #endif
7000 }
7001 
7002 // for better performance, manual C implementation of gmsh::view::getModelData
gmshViewGetModelData(const int tag,const int step,char ** dataType,size_t ** tags,size_t * tags_n,double *** data,size_t ** data_n,size_t * data_nn,double * time,int * numComponents,int * ierr)7003 GMSH_API void gmshViewGetModelData(const int tag, const int step,
7004                                    char **dataType, size_t **tags,
7005                                    size_t *tags_n, double ***data,
7006                                    size_t **data_n, size_t *data_nn,
7007                                    double *time, int *numComponents, int *ierr)
7008 {
7009   if(!_checkInit()) {
7010     if(ierr) *ierr = -1;
7011     return;
7012   }
7013 #if defined(HAVE_POST)
7014   PView *view = PView::getViewByTag(tag);
7015   if(!view) {
7016     Msg::Error("Unknown view with tag %d", tag);
7017     if(ierr) *ierr = 2;
7018     return;
7019   }
7020   PViewDataGModel *d = dynamic_cast<PViewDataGModel *>(view->getData());
7021   if(!d) {
7022     Msg::Error("View with tag %d does not contain model data", tag);
7023     return;
7024   }
7025   if(d->getType() == PViewDataGModel::NodeData)
7026     *dataType = strdup("NodeData");
7027   else if(d->getType() == PViewDataGModel::ElementData)
7028     *dataType = strdup("ElementData");
7029   else if(d->getType() == PViewDataGModel::ElementNodeData)
7030     *dataType = strdup("ElementNodeData");
7031   else if(d->getType() == PViewDataGModel::GaussPointData)
7032     *dataType = strdup("GaussPointData");
7033   else if(d->getType() == PViewDataGModel::BeamData)
7034     *dataType = strdup("Beam");
7035   else
7036     *dataType = strdup("Unknown");
7037   stepData<double> *s = d->getStepData(step);
7038   if(!s) {
7039     Msg::Error("View with tag %d does not contain model data for step %d", tag,
7040                step);
7041     if(ierr) *ierr = 2;
7042     return;
7043   }
7044   *tags_n = 0;
7045   *data_nn = 0;
7046   *time = s->getTime();
7047   *numComponents = s->getNumComponents();
7048   int numEnt = 0;
7049   for(size_t i = 0; i < s->getNumData(); i++) {
7050     if(s->getData(i)) numEnt++;
7051   }
7052   if(!numEnt) return;
7053   *tags_n = numEnt;
7054   *tags = (size_t *)Malloc(numEnt * sizeof(size_t));
7055   *data_nn = numEnt;
7056   *data_n = (size_t *)Malloc(numEnt * sizeof(size_t *));
7057   *data = (double **)Malloc(numEnt * sizeof(double *));
7058   size_t j = 0;
7059   for(size_t i = 0; i < s->getNumData(); i++) {
7060     double *dd = s->getData(i);
7061     if(dd) {
7062       (*tags)[j] = i;
7063       int mult = s->getMult(i);
7064       (*data_n)[j] = *numComponents * mult;
7065       (*data)[j] = (double *)Malloc(*numComponents * mult * sizeof(double));
7066       for(int k = 0; k < *numComponents * mult; k++) (*data)[j][k] = dd[k];
7067       j++;
7068     }
7069   }
7070   if(ierr) *ierr = 0;
7071 #else
7072   Msg::Error("Views require the post-processing module");
7073   if(ierr) *ierr = -1;
7074 #endif
7075 }
7076 
addListData(const int tag,const std::string & dataType,const int numElements,const std::vector<double> & data)7077 GMSH_API void gmsh::view::addListData(const int tag,
7078                                       const std::string &dataType,
7079                                       const int numElements,
7080                                       const std::vector<double> &data)
7081 {
7082   if(!_checkInit()) return;
7083 #if defined(HAVE_POST)
7084   PView *view = PView::getViewByTag(tag);
7085   if(!view) {
7086     Msg::Error("Unknown view with tag %d", tag);
7087     return;
7088   }
7089   PViewDataList *d = dynamic_cast<PViewDataList *>(view->getData());
7090   if(!d) { // change the view type
7091     std::string name = view->getData()->getName();
7092     delete view->getData();
7093     d = new PViewDataList();
7094     d->setName(name);
7095     d->setFileName(name + ".pos");
7096     view->setData(d);
7097   }
7098   const char *types[] = {"SP", "VP", "TP", "SL", "VL", "TL", "ST", "VT",
7099                          "TT", "SQ", "VQ", "TQ", "SS", "VS", "TS", "SH",
7100                          "VH", "TH", "SI", "VI", "TI", "SY", "VY", "TY"};
7101   for(int idxtype = 0; idxtype < 24; idxtype++) {
7102     if(dataType == types[idxtype]) {
7103       d->importList(idxtype, numElements, data, true);
7104       view->setChanged(true);
7105       return;
7106     }
7107   }
7108   Msg::Error("Unknown data type for list import");
7109 #else
7110   Msg::Error("Views require the post-processing module");
7111 #endif
7112 }
7113 
getListData(const int tag,std::vector<std::string> & dataTypes,std::vector<int> & numElements,std::vector<std::vector<double>> & data)7114 GMSH_API void gmsh::view::getListData(const int tag,
7115                                       std::vector<std::string> &dataTypes,
7116                                       std::vector<int> &numElements,
7117                                       std::vector<std::vector<double> > &data)
7118 {
7119   if(!_checkInit()) return;
7120 #if defined(HAVE_POST)
7121   PView *view = PView::getViewByTag(tag);
7122   if(!view) {
7123     Msg::Error("Unknown view with tag %d", tag);
7124     return;
7125   }
7126   PViewDataList *d = dynamic_cast<PViewDataList *>(view->getData());
7127   if(!d) {
7128     Msg::Error("View with tag %d does not contain list data", tag);
7129     return;
7130   }
7131   const char *types[] = {"SP", "VP", "TP", "SL", "VL", "TL", "ST", "VT",
7132                          "TT", "SQ", "VQ", "TQ", "SS", "VS", "TS", "SH",
7133                          "VH", "TH", "SI", "VI", "TI", "SY", "VY", "TY"};
7134   std::vector<int> N(24);
7135   std::vector<std::vector<double> *> V(24);
7136   d->getListPointers(&N[0], &V[0]);
7137   for(int idxtype = 0; idxtype < 24; idxtype++) {
7138     if(N[idxtype]) {
7139       dataTypes.push_back(types[idxtype]);
7140       numElements.push_back(N[idxtype]);
7141       data.push_back(*V[idxtype]);
7142     }
7143   }
7144 #else
7145   Msg::Error("Views require the post-processing module");
7146 #endif
7147 }
7148 
7149 #if defined(HAVE_POST)
getStringStyle(const std::vector<std::string> & style)7150 static double getStringStyle(const std::vector<std::string> &style)
7151 {
7152   if(style.empty()) return 0.;
7153   int align = 0, font = 0, fontsize = CTX::instance()->glFontSize;
7154   if(style.size() % 2) {
7155     Msg::Error("Number of string style attributes should be even");
7156   }
7157   else {
7158     for(std::size_t i = 0; i < style.size(); i += 2) {
7159       std::string key = style[i], val = style[i + 1];
7160 #if defined(HAVE_OPENGL)
7161       if(key == "Font")
7162         font = drawContext::global()->getFontIndex(val.c_str());
7163       else if(key == "FontSize")
7164         fontsize = atoi(val.c_str());
7165       else if(key == "Align")
7166         align = drawContext::global()->getFontAlign(val.c_str());
7167 #endif
7168     }
7169   }
7170   return (double)((align << 16) | (font << 8) | (fontsize));
7171 }
7172 #endif
7173 
7174 GMSH_API void
addListDataString(const int tag,const std::vector<double> & coord,const std::vector<std::string> & data,const std::vector<std::string> & style)7175 gmsh::view::addListDataString(const int tag, const std::vector<double> &coord,
7176                               const std::vector<std::string> &data,
7177                               const std::vector<std::string> &style)
7178 {
7179   if(!_checkInit()) return;
7180 #if defined(HAVE_POST)
7181   PView *view = PView::getViewByTag(tag);
7182   if(!view) {
7183     Msg::Error("Unknown view with tag %d", tag);
7184     return;
7185   }
7186   PViewDataList *d = dynamic_cast<PViewDataList *>(view->getData());
7187   if(!d) { // change the view type
7188     std::string name = view->getData()->getName();
7189     delete view->getData();
7190     d = new PViewDataList();
7191     d->setName(name);
7192     d->setFileName(name + ".pos");
7193     view->setData(d);
7194   }
7195   if(coord.size() == 3) {
7196     d->T3D.push_back(coord[0]);
7197     d->T3D.push_back(coord[1]);
7198     d->T3D.push_back(coord[2]);
7199     d->T3D.push_back(getStringStyle(style)), d->T3D.push_back(d->T3C.size());
7200     d->NbT3++;
7201     for(std::size_t i = 0; i < data.size(); i++) {
7202       for(std::size_t j = 0; j < data[i].size(); j++) {
7203         d->T3C.push_back(data[i][j]);
7204       }
7205       d->T3C.push_back('\0');
7206     }
7207   }
7208   else if(coord.size() == 2) {
7209     d->T2D.push_back(coord[0]);
7210     d->T2D.push_back(coord[1]);
7211     d->T2D.push_back(getStringStyle(style)), d->T2D.push_back(d->T2C.size());
7212     d->NbT2++;
7213     for(std::size_t i = 0; i < data.size(); i++) {
7214       for(std::size_t j = 0; j < data[i].size(); j++) {
7215         d->T2C.push_back(data[i][j]);
7216       }
7217       d->T2C.push_back('\0');
7218     }
7219   }
7220   d->finalize();
7221   view->setChanged(true);
7222 #else
7223   Msg::Error("Views require the post-processing module");
7224 #endif
7225 }
7226 
getListDataStrings(const int tag,const int dim,std::vector<double> & coord,std::vector<std::string> & data,std::vector<std::string> & style)7227 GMSH_API void gmsh::view::getListDataStrings(const int tag, const int dim,
7228                                              std::vector<double> &coord,
7229                                              std::vector<std::string> &data,
7230                                              std::vector<std::string> &style)
7231 {
7232   if(!_checkInit()) return;
7233 #if defined(HAVE_POST)
7234   PView *view = PView::getViewByTag(tag);
7235   if(!view) {
7236     Msg::Error("Unknown view with tag %d", tag);
7237     return;
7238   }
7239   PViewDataList *d = dynamic_cast<PViewDataList *>(view->getData());
7240   if(!d) {
7241     Msg::Error("View with tag %d does not contain list data", tag);
7242     return;
7243   }
7244   int nstep = d->getNumTimeSteps();
7245   if(dim == 3) {
7246     int ns = d->getNumStrings3D();
7247     for(int i = 0; i < ns; i++) {
7248       for(int j = 0; j < nstep; j++) {
7249         double x, y, z, styl;
7250         std::string s;
7251         d->getString3D(i, j, s, x, y, z, styl);
7252         if(i == 0) {
7253           coord.push_back(x);
7254           coord.push_back(y);
7255           coord.push_back(z);
7256         }
7257         data.push_back(s);
7258         // TODO convert style to strings, pad with empty strings so that all
7259         // strings return the same number of styling pairs
7260         style.push_back("");
7261       }
7262     }
7263   }
7264   else if(dim == 2) {
7265     int ns = d->getNumStrings2D();
7266     for(int i = 0; i < ns; i++) {
7267       for(int j = 0; j < nstep; j++) {
7268         double x, y, styl;
7269         std::string s;
7270         d->getString2D(i, j, s, x, y, styl);
7271         if(i == 0) {
7272           coord.push_back(x);
7273           coord.push_back(y);
7274         }
7275         data.push_back(s);
7276         // TODO convert style to strings, pad with empty strings so that all
7277         // strings return the same number of styling pairs
7278         style.push_back("");
7279       }
7280     }
7281   }
7282 #else
7283   Msg::Error("Views require the post-processing module");
7284 #endif
7285 }
7286 
setInterpolationMatrices(const int tag,const std::string & type,const int d,const std::vector<double> & coef,const std::vector<double> & exp,const int dGeo,const std::vector<double> & coefGeo,const std::vector<double> & expGeo)7287 GMSH_API void gmsh::view::setInterpolationMatrices(
7288   const int tag, const std::string &type, const int d,
7289   const std::vector<double> &coef, const std::vector<double> &exp,
7290   const int dGeo, const std::vector<double> &coefGeo,
7291   const std::vector<double> &expGeo)
7292 {
7293   if(!_checkInit()) return;
7294 #if defined(HAVE_POST)
7295   PView *view = PView::getViewByTag(tag);
7296   if(!view) {
7297     Msg::Error("Unknown view with tag %d", tag);
7298     return;
7299   }
7300   PViewData *data = view->getData();
7301   if(!data) {
7302     Msg::Error("View with tag %d does not contain any data", tag);
7303     return;
7304   }
7305 
7306   int itype = 0;
7307   if(type == "Line" || type == "line")
7308     itype = TYPE_LIN;
7309   else if(type == "Triangle" || type == "triangle")
7310     itype = TYPE_TRI;
7311   else if(type == "Quadrangle" || type == "quadrangle")
7312     itype = TYPE_QUA;
7313   else if(type == "Tetrahedron" || type == "tetrahedron")
7314     itype = TYPE_TET;
7315   else if(type == "Pyramid" || type == "pyramid")
7316     itype = TYPE_PYR;
7317   else if(type == "Prism" || type == "prism")
7318     itype = TYPE_PRI;
7319   else if(type == "Hexahedron" || type == "hexahedron")
7320     itype = TYPE_HEX;
7321   else {
7322     Msg::Error("Unknown element family type '%s'", type.c_str());
7323     return;
7324   }
7325 
7326   if(data->haveInterpolationMatrices(itype))
7327     data->deleteInterpolationMatrices(itype);
7328 
7329   if(d <= 0) return;
7330 
7331   // field interpolation coefficients and exponents
7332   if((int)coef.size() != d * d) {
7333     Msg::Error("Wrong number of coefficients (%d != %d x %d)", (int)coef.size(),
7334                d, d);
7335     return;
7336   }
7337   if((int)exp.size() != d * 3) {
7338     Msg::Error("Wrong number of exponents (%d != %d x 3)", (int)exp.size(), d);
7339     return;
7340   }
7341   fullMatrix<double> F(d, d), P(d, 3);
7342   for(int i = 0; i < d; i++) {
7343     for(int j = 0; j < d; j++) { F(i, j) = coef[d * i + j]; }
7344     for(int j = 0; j < 3; j++) { P(i, j) = exp[3 * i + j]; }
7345   }
7346 
7347   if(dGeo <= 0) {
7348     data->setInterpolationMatrices(itype, F, P);
7349     view->setChanged(true);
7350     return;
7351   }
7352 
7353   // geometry interpolation coefficients and exponents
7354   if((int)coefGeo.size() != dGeo * dGeo) {
7355     Msg::Error("Wrong number of coefficients (%d != %d x %d)",
7356                (int)coefGeo.size(), dGeo, dGeo);
7357     return;
7358   }
7359   if((int)expGeo.size() != dGeo * 3) {
7360     Msg::Error("Wrong number of exponents (%d != %d x 3)", (int)expGeo.size(),
7361                dGeo);
7362     return;
7363   }
7364   fullMatrix<double> Fg(dGeo, dGeo), Pg(dGeo, 3);
7365   for(int i = 0; i < dGeo; i++) {
7366     for(int j = 0; j < dGeo; j++) { Fg(i, j) = coefGeo[dGeo * i + j]; }
7367     for(int j = 0; j < 3; j++) { Pg(i, j) = expGeo[3 * i + j]; }
7368   }
7369   data->setInterpolationMatrices(itype, F, P, Fg, Pg);
7370   view->setChanged(true);
7371 #else
7372   Msg::Error("Views require the post-processing module");
7373 #endif
7374 }
7375 
addAlias(const int refTag,const bool copyOptions,const int tag)7376 GMSH_API int gmsh::view::addAlias(const int refTag, const bool copyOptions,
7377                                   const int tag)
7378 {
7379   if(!_checkInit()) return -1;
7380 #if defined(HAVE_POST)
7381   PView *ref = PView::getViewByTag(refTag);
7382   if(!ref) {
7383     Msg::Error("Unknown view with tag %d", refTag);
7384     return -1;
7385   }
7386   PView *view = new PView(ref, copyOptions, tag);
7387 #if defined(HAVE_FLTK)
7388   if(FlGui::available()) FlGui::instance()->updateViews(true, true);
7389 #endif
7390   return view->getTag();
7391 #else
7392   Msg::Error("Views require the post-processing module");
7393   return -1;
7394 #endif
7395 }
7396 
combine(const std::string & what,const std::string & how,const bool remove,const bool copyOptions)7397 GMSH_API void gmsh::view::combine(const std::string &what,
7398                                   const std::string &how, const bool remove,
7399                                   const bool copyOptions)
7400 {
7401   if(!_checkInit()) return;
7402 #if defined(HAVE_POST)
7403   bool time = (what == "steps") ? true : false; // "elements"
7404   int ihow = (how == "all") ? 1 : (how == "name") ? 2 : 0; // "visible"
7405   PView::combine(time, ihow, remove, copyOptions);
7406 #if defined(HAVE_FLTK)
7407   if(FlGui::available()) FlGui::instance()->updateViews(true, true);
7408 #endif
7409 #else
7410   Msg::Error("Views require the post-processing module");
7411 #endif
7412 }
7413 
probe(const int tag,const double x,const double y,const double z,std::vector<double> & value,double & distance,const int step,const int numComp,const bool gradient,const double distanceMax,const std::vector<double> & xElemCoord,const std::vector<double> & yElemCoord,const std::vector<double> & zElemCoord,const int dim)7414 GMSH_API void gmsh::view::probe(const int tag, const double x, const double y,
7415                                 const double z, std::vector<double> &value,
7416                                 double &distance, const int step,
7417                                 const int numComp, const bool gradient,
7418                                 const double distanceMax,
7419                                 const std::vector<double> &xElemCoord,
7420                                 const std::vector<double> &yElemCoord,
7421                                 const std::vector<double> &zElemCoord,
7422                                 const int dim)
7423 {
7424   if(!_checkInit()) return;
7425 #if defined(HAVE_POST)
7426   PView *view = PView::getViewByTag(tag);
7427   if(!view) {
7428     Msg::Error("Unknown view with tag %d", tag);
7429     return;
7430   }
7431   PViewData *data = view->getData();
7432   if(!data) {
7433     Msg::Error("No data in view %d", tag);
7434     return;
7435   }
7436   value.clear();
7437   std::vector<double> val(9 * data->getNumTimeSteps() * 3);
7438   int qn = 0;
7439   double *qx = nullptr, *qy = nullptr, *qz = nullptr;
7440   if(xElemCoord.size() && yElemCoord.size() && zElemCoord.size() &&
7441      xElemCoord.size() == yElemCoord.size() &&
7442      xElemCoord.size() == zElemCoord.size()) {
7443     qn = xElemCoord.size();
7444     qx = (double *)&xElemCoord[0];
7445     qy = (double *)&yElemCoord[0];
7446     qz = (double *)&zElemCoord[0];
7447   }
7448   int numSteps = (step < 0) ? data->getNumTimeSteps() : 1;
7449   int mult = gradient ? 3 : 1;
7450   int numVal = 0;
7451   distance = distanceMax;
7452   switch(numComp) {
7453   case 1:
7454     if(data->searchScalarClosest(x, y, z, distance, &val[0], step, nullptr,
7455                                  qn, qx, qy, qz, gradient, dim)) {
7456       numVal = numSteps * mult * 1;
7457     }
7458     break;
7459   case 3:
7460     if(data->searchVectorClosest(x, y, z, distance, &val[0], step, nullptr,
7461                                  qn, qx, qy, qz, gradient, dim)) {
7462       numVal = numSteps * mult * 3;
7463     }
7464     break;
7465   case 9:
7466     if(data->searchTensorClosest(x, y, z, distance, &val[0], step, nullptr,
7467                                  qn, qx, qy, qz, gradient, dim)) {
7468       numVal = numSteps * mult * 9;
7469     }
7470     break;
7471   default:
7472     if(data->searchScalarClosest(x, y, z, distance, &val[0], step, nullptr,
7473                                  qn, qx, qy, qz, gradient, dim)) {
7474       numVal = numSteps * mult * 1;
7475     }
7476     else if(data->searchVectorClosest(x, y, z, distance, &val[0], step, nullptr,
7477                                       qn, qx, qy, qz, gradient,
7478                                       dim)) {
7479       numVal = numSteps * mult * 3;
7480     }
7481     else if(data->searchTensorClosest(x, y, z, distance, &val[0], step, nullptr,
7482                                       qn, qx, qy, qz, gradient,
7483                                       dim)) {
7484       numVal = numSteps * mult * 9;
7485     }
7486     break;
7487   }
7488   for(int i = 0; i < numVal; i++) value.push_back(val[i]);
7489 #else
7490   Msg::Error("Views require the post-processing module");
7491 #endif
7492 }
7493 
write(const int tag,const std::string & fileName,const bool append)7494 GMSH_API void gmsh::view::write(const int tag, const std::string &fileName,
7495                                 const bool append)
7496 {
7497   if(!_checkInit()) return;
7498 #if defined(HAVE_POST)
7499   PView *view = PView::getViewByTag(tag);
7500   if(!view) {
7501     Msg::Error("Unknown view with tag %d", tag);
7502     return;
7503   }
7504   view->write(fileName, 10, append);
7505 #else
7506   Msg::Error("Views require the post-processing module");
7507 #endif
7508 }
7509 
setVisibilityPerWindow(const int tag,const int value,const int windowIndex)7510 GMSH_API void gmsh::view::setVisibilityPerWindow(const int tag, const int value,
7511                                                  const int windowIndex)
7512 {
7513   if(!_checkInit()) return;
7514 #if defined(HAVE_POST)
7515   PView *view = PView::getViewByTag(tag);
7516   if(!view) {
7517     Msg::Error("Unknown view with tag %d", tag);
7518     return;
7519   }
7520 #if defined(HAVE_FLTK)
7521   FlGui::instance()->setCurrentOpenglWindow(windowIndex);
7522   drawContext *ctx = FlGui::instance()->getCurrentDrawContext();
7523   if(value)
7524     ctx->show(view);
7525   else
7526     ctx->hide(view);
7527 #endif
7528 #else
7529   Msg::Error("Views require the post-processing module");
7530 #endif
7531 }
7532 
7533 // gmsh::view::option
7534 
setNumber(int tag,const std::string & name,const double value)7535 GMSH_API void gmsh::view::option::setNumber(int tag, const std::string &name,
7536                                             const double value)
7537 {
7538   if(!_checkInit()) return;
7539 #if defined(HAVE_POST)
7540   PView *view = PView::getViewByTag(tag);
7541   if(view) {
7542     if(!GmshSetOption("View", name, value, view->getIndex()))
7543       Msg::Error("Could not set option '%s' in view with tag %d",
7544                  name.c_str(), tag);
7545   }
7546   else {
7547     Msg::Error("Unknown view with tag %d", tag);
7548   }
7549 #else
7550   Msg::Error("Views require the post-processing module");
7551 #endif
7552 }
7553 
getNumber(int tag,const std::string & name,double & value)7554 GMSH_API void gmsh::view::option::getNumber(int tag, const std::string &name,
7555                                             double &value)
7556 {
7557   if(!_checkInit()) return;
7558 #if defined(HAVE_POST)
7559   PView *view = PView::getViewByTag(tag);
7560   if(view) {
7561     if(!GmshGetOption("View", name, value, view->getIndex()))
7562       Msg::Error("Could not get option '%s' in view with tag %d",
7563                  name.c_str(), tag);
7564   }
7565   else {
7566     Msg::Error("Unknown view with tag %d", tag);
7567   }
7568 #else
7569   Msg::Error("Views require the post-processing module");
7570 #endif
7571 }
7572 
setString(int tag,const std::string & name,const std::string & value)7573 GMSH_API void gmsh::view::option::setString(int tag, const std::string &name,
7574                                             const std::string &value)
7575 {
7576   if(!_checkInit()) return;
7577 #if defined(HAVE_POST)
7578   PView *view = PView::getViewByTag(tag);
7579   if(view) {
7580     if(!GmshSetOption("View", name, value, view->getIndex()))
7581       Msg::Error("Could not set option '%s' in view with tag %d",
7582                  name.c_str(), tag);
7583   }
7584   else {
7585     Msg::Error("Unknown view with tag %d", tag);
7586   }
7587 #else
7588   Msg::Error("Views require the post-processing module");
7589 #endif
7590 }
7591 
getString(int tag,const std::string & name,std::string & value)7592 GMSH_API void gmsh::view::option::getString(int tag, const std::string &name,
7593                                             std::string &value)
7594 {
7595   if(!_checkInit()) return;
7596 #if defined(HAVE_POST)
7597   PView *view = PView::getViewByTag(tag);
7598   if(view) {
7599     if(!GmshGetOption("View", name, value, view->getIndex()))
7600       Msg::Error("Could not get option '%s' in view with tag %d",
7601                  name.c_str(), tag);
7602   }
7603   else {
7604     Msg::Error("Unknown view with tag %d", tag);
7605   }
7606 #else
7607   Msg::Error("Views require the post-processing module");
7608 #endif
7609 }
7610 
setColor(int tag,const std::string & name,const int r,const int g,const int b,const int a)7611 GMSH_API void gmsh::view::option::setColor(int tag, const std::string &name,
7612                                            const int r, const int g,
7613                                            const int b, const int a)
7614 {
7615   if(!_checkInit()) return;
7616 #if defined(HAVE_POST)
7617   PView *view = PView::getViewByTag(tag);
7618   if(view) {
7619     unsigned int value = CTX::instance()->packColor(r, g, b, a);
7620     if(!GmshSetOption("View", name, value, view->getIndex()))
7621       Msg::Error("Could not set option '%s' in view with tag %d",
7622                  name.c_str(), tag);
7623   }
7624   else {
7625     Msg::Error("Unknown view with tag %d", tag);
7626   }
7627 #else
7628   Msg::Error("Views require the post-processing module");
7629 #endif
7630 }
7631 
getColor(int tag,const std::string & name,int & r,int & g,int & b,int & a)7632 GMSH_API void gmsh::view::option::getColor(int tag, const std::string &name,
7633                                            int &r, int &g, int &b, int &a)
7634 {
7635   if(!_checkInit()) return;
7636 #if defined(HAVE_POST)
7637   PView *view = PView::getViewByTag(tag);
7638   if(view) {
7639     unsigned int value;
7640     if(GmshGetOption("View", name, value, view->getIndex())) {
7641       r = CTX::instance()->unpackRed(value);
7642       g = CTX::instance()->unpackGreen(value);
7643       b = CTX::instance()->unpackBlue(value);
7644       a = CTX::instance()->unpackAlpha(value);
7645     }
7646     else {
7647       Msg::Error("Could not get option '%s' in view with tag %d",
7648                  name.c_str(), tag);
7649     }
7650   }
7651   else {
7652     Msg::Error("Unknown view with tag %d", tag);
7653   }
7654 #else
7655   Msg::Error("Views require the post-processing module");
7656 #endif
7657 }
7658 
copy(const int refTag,const int tag)7659 GMSH_API void gmsh::view::option::copy(const int refTag, const int tag)
7660 {
7661   if(!_checkInit()) return;
7662 #if defined(HAVE_POST)
7663   PView *ref = PView::getViewByTag(refTag);
7664   if(!ref) {
7665     Msg::Error("Unknown view with tag %d", refTag);
7666     return;
7667   }
7668   PView *view = PView::getViewByTag(tag);
7669   if(!view) {
7670     Msg::Error("Unknown view with tag %d", tag);
7671     return;
7672   }
7673   view->setOptions(ref->getOptions());
7674   view->setChanged(true);
7675 #if defined(HAVE_FLTK)
7676   if(FlGui::available()) FlGui::instance()->updateViews(true, true);
7677 #endif
7678 #else
7679   Msg::Error("Views require the post-processing module");
7680 #endif
7681 }
7682 
7683 // gmsh::plugin
7684 
setNumber(const std::string & name,const std::string & option,const double value)7685 GMSH_API void gmsh::plugin::setNumber(const std::string &name,
7686                                       const std::string &option,
7687                                       const double value)
7688 {
7689   if(!_checkInit()) return;
7690 #if defined(HAVE_PLUGINS)
7691   try {
7692     PluginManager::instance()->setPluginOption(name, option, value);
7693   } catch(...) {
7694     Msg::Error("Unknown plugin or plugin option");
7695   }
7696 #else
7697   Msg::Error("Views require the post-processing and plugin modules");
7698 #endif
7699 }
7700 
setString(const std::string & name,const std::string & option,const std::string & value)7701 GMSH_API void gmsh::plugin::setString(const std::string &name,
7702                                       const std::string &option,
7703                                       const std::string &value)
7704 {
7705   if(!_checkInit()) return;
7706 #if defined(HAVE_PLUGINS)
7707   try {
7708     PluginManager::instance()->setPluginOption(name, option, value);
7709   } catch(...) {
7710     Msg::Error("Unknown plugin or plugin option");
7711   }
7712 #else
7713   Msg::Error("Views require the post-processing and plugin modules");
7714 #endif
7715 }
7716 
run(const std::string & name)7717 GMSH_API int gmsh::plugin::run(const std::string &name)
7718 {
7719   if(!_checkInit()) return 0;
7720 #if defined(HAVE_PLUGINS)
7721   try {
7722     return PluginManager::instance()->action(name, "Run", nullptr);
7723   } catch(...) {
7724     Msg::Error("Unknown plugin or plugin action");
7725     return 0;
7726   }
7727 #else
7728   Msg::Error("Views require the post-processing and plugin modules");
7729   return 0;
7730 #endif
7731 }
7732 
7733 // gmsh::graphics
7734 
draw()7735 GMSH_API void gmsh::graphics::draw()
7736 {
7737 #if defined(HAVE_OPENGL)
7738   drawContext::global()->draw(false); // not rate-limited
7739 #endif
7740 }
7741 
7742 // gmsh::fltk
7743 
7744 #if defined(HAVE_FLTK)
_errorHandlerFltk(const char * fmt,...)7745 static void _errorHandlerFltk(const char *fmt, ...)
7746 {
7747   char str[5000];
7748   va_list args;
7749   va_start(args, fmt);
7750   vsnprintf(str, sizeof(str), fmt, args);
7751   va_end(args);
7752   Msg::Error("%s (FLTK internal error)", str);
7753 }
7754 
_createFltk()7755 static void _createFltk()
7756 {
7757   if(!FlGui::available())
7758     FlGui::instance(_argc, _argv, false, _errorHandlerFltk);
7759 }
7760 #endif
7761 
initialize()7762 GMSH_API void gmsh::fltk::initialize()
7763 {
7764   if(!_checkInit()) return;
7765 #if defined(HAVE_FLTK)
7766   _createFltk();
7767   FlGui::setFinishedProcessingCommandLine();
7768   FlGui::check();
7769 #else
7770   Msg::Error("Fltk not available");
7771 #endif
7772 }
7773 
isAvailable()7774 GMSH_API int gmsh::fltk::isAvailable()
7775 {
7776   if(!_checkInit()) return -1;
7777 #if defined(HAVE_FLTK)
7778   return FlGui::available() ? 1 : 0;
7779 #else
7780   return 0;
7781 #endif
7782 }
7783 
wait(const double time)7784 GMSH_API void gmsh::fltk::wait(const double time)
7785 {
7786   if(!_checkInit()) return;
7787 #if defined(HAVE_FLTK)
7788   _createFltk();
7789   if(time >= 0)
7790     FlGui::wait(time, true); // force
7791   else
7792     FlGui::wait(true); // force
7793 #else
7794   Msg::Error("Fltk not available");
7795 #endif
7796 }
7797 
lock()7798 GMSH_API void gmsh::fltk::lock()
7799 {
7800   if(!_checkInit()) return;
7801 #if defined(HAVE_FLTK)
7802   FlGui::lock();
7803 #else
7804   Msg::Error("Fltk not available");
7805 #endif
7806 }
7807 
unlock()7808 GMSH_API void gmsh::fltk::unlock()
7809 {
7810   if(!_checkInit()) return;
7811 #if defined(HAVE_FLTK)
7812   FlGui::unlock();
7813 #else
7814   Msg::Error("Fltk not available");
7815 #endif
7816 }
7817 
update()7818 GMSH_API void gmsh::fltk::update()
7819 {
7820   if(!_checkInit()) return;
7821 #if defined(HAVE_FLTK)
7822   _createFltk();
7823   FlGui::instance()->updateViews(true, true);
7824 #else
7825   Msg::Error("Fltk not available");
7826 #endif
7827 }
7828 
awake(const std::string & action)7829 GMSH_API void gmsh::fltk::awake(const std::string &action)
7830 {
7831   if(!_checkInit()) return;
7832 #if defined(HAVE_FLTK)
7833   FlGui::awake(action);
7834 #else
7835   Msg::Error("Fltk not available");
7836 #endif
7837 }
7838 
run()7839 GMSH_API void gmsh::fltk::run()
7840 {
7841   if(!_checkInit()) return;
7842 #if defined(HAVE_FLTK)
7843   _createFltk();
7844   FlGui::instance()->run(); // this calls draw() once
7845 #else
7846   Msg::Error("Fltk not available");
7847 #endif
7848 }
7849 
7850 #if defined(HAVE_FLTK)
selectionCode(char val)7851 static int selectionCode(char val)
7852 {
7853   switch(val) {
7854   case 'q': return 0; // abort
7855   case 'l': return 1; // selected
7856   case 'r': return 2; // deselected
7857   case 'u': return 3; // undone last selection
7858   case 'e': return 4; // ended selection
7859   default: return -1; // unknown code
7860   }
7861 }
7862 #endif
7863 
selectEntities(vectorpair & dimTags,const int dim)7864 GMSH_API int gmsh::fltk::selectEntities(vectorpair &dimTags, const int dim)
7865 {
7866   if(!_checkInit()) return -1;
7867   dimTags.clear();
7868 #if defined(HAVE_FLTK)
7869   _createFltk();
7870   char ret = 0;
7871   switch(dim) {
7872   case 0: ret = FlGui::instance()->selectEntity(ENT_POINT); break;
7873   case 1: ret = FlGui::instance()->selectEntity(ENT_CURVE); break;
7874   case 2: ret = FlGui::instance()->selectEntity(ENT_SURFACE); break;
7875   case 3: ret = FlGui::instance()->selectEntity(ENT_VOLUME); break;
7876   default: ret = FlGui::instance()->selectEntity(ENT_ALL); break;
7877   }
7878   if(!FlGui::available()) return 0; // GUI closed during selection
7879   for(std::size_t i = 0; i < FlGui::instance()->selectedVertices.size(); i++)
7880     dimTags.push_back(
7881       std::make_pair(0, FlGui::instance()->selectedVertices[i]->tag()));
7882   for(std::size_t i = 0; i < FlGui::instance()->selectedEdges.size(); i++)
7883     dimTags.push_back(
7884       std::make_pair(1, FlGui::instance()->selectedEdges[i]->tag()));
7885   for(std::size_t i = 0; i < FlGui::instance()->selectedFaces.size(); i++)
7886     dimTags.push_back(
7887       std::make_pair(2, FlGui::instance()->selectedFaces[i]->tag()));
7888   for(std::size_t i = 0; i < FlGui::instance()->selectedRegions.size(); i++)
7889     dimTags.push_back(
7890       std::make_pair(3, FlGui::instance()->selectedRegions[i]->tag()));
7891   return selectionCode(ret);
7892 #else
7893   return 0;
7894 #endif
7895 }
7896 
selectElements(std::vector<std::size_t> & elementTags)7897 GMSH_API int gmsh::fltk::selectElements(std::vector<std::size_t> &elementTags)
7898 {
7899   if(!_checkInit()) return -1;
7900   elementTags.clear();
7901 #if defined(HAVE_FLTK)
7902   _createFltk();
7903   int old = CTX::instance()->pickElements;
7904   CTX::instance()->pickElements = 1;
7905   CTX::instance()->mesh.changed = ENT_ALL;
7906   char ret = FlGui::instance()->selectEntity(ENT_ALL);
7907   CTX::instance()->pickElements = old;
7908   if(!FlGui::available()) return 0; // GUI closed during selection
7909   for(std::size_t i = 0; i < FlGui::instance()->selectedElements.size(); i++)
7910     elementTags.push_back(FlGui::instance()->selectedElements[i]->getNum());
7911   return selectionCode(ret);
7912 #else
7913   return 0;
7914 #endif
7915 }
7916 
selectViews(std::vector<int> & viewTags)7917 GMSH_API int gmsh::fltk::selectViews(std::vector<int> &viewTags)
7918 {
7919   if(!_checkInit()) return -1;
7920   viewTags.clear();
7921 #if defined(HAVE_FLTK)
7922   _createFltk();
7923   char ret = FlGui::instance()->selectEntity(ENT_ALL);
7924   if(!FlGui::available()) return 0; // GUI closed during selection
7925   for(std::size_t i = 0; i < FlGui::instance()->selectedViews.size(); i++)
7926     viewTags.push_back(FlGui::instance()->selectedViews[i]->getTag());
7927   return selectionCode(ret);
7928 #else
7929   return 0;
7930 #endif
7931 }
7932 
splitCurrentWindow(const std::string & how,const double ratio)7933 GMSH_API void gmsh::fltk::splitCurrentWindow(const std::string &how,
7934                                              const double ratio)
7935 {
7936   if(!_checkInit()) return;
7937 #if defined(HAVE_FLTK)
7938   _createFltk();
7939   if(how == "h")
7940     FlGui::instance()->splitCurrentOpenglWindow('h', ratio);
7941   else if(how == "v")
7942     FlGui::instance()->splitCurrentOpenglWindow('v', ratio);
7943   else if(how == "u")
7944     FlGui::instance()->splitCurrentOpenglWindow('u');
7945   else {
7946     Msg::Error("Unknown window splitting method '%s'", how.c_str());
7947   }
7948 #endif
7949 }
7950 
setCurrentWindow(const int windowIndex)7951 GMSH_API void gmsh::fltk::setCurrentWindow(const int windowIndex)
7952 {
7953   if(!_checkInit()) return;
7954 #if defined(HAVE_FLTK)
7955   _createFltk();
7956   FlGui::instance()->setCurrentOpenglWindow(windowIndex);
7957 #endif
7958 }
7959 
setStatusMessage(const std::string & message,const bool graphics)7960 GMSH_API void gmsh::fltk::setStatusMessage(const std::string &message,
7961                                            const bool graphics)
7962 {
7963   if(!_checkInit()) return;
7964 #if defined(HAVE_FLTK)
7965   _createFltk();
7966   FlGui::instance()->setStatus(message, graphics);
7967 #endif
7968 }
7969 
showContextWindow(const int dim,const int tag)7970 GMSH_API void gmsh::fltk::showContextWindow(const int dim, const int tag)
7971 {
7972   if(!_checkInit()) return;
7973 #if defined(HAVE_FLTK)
7974   _createFltk();
7975   FlGui::instance()->showOnelabContext(dim, tag);
7976 #endif
7977 }
7978 
openTreeItem(const std::string & name)7979 GMSH_API void gmsh::fltk::openTreeItem(const std::string &name)
7980 {
7981   if(!_checkInit()) return;
7982 #if defined(HAVE_FLTK)
7983   _createFltk();
7984   FlGui::instance()->openTreeItem(name);
7985 #endif
7986 }
7987 
closeTreeItem(const std::string & name)7988 GMSH_API void gmsh::fltk::closeTreeItem(const std::string &name)
7989 {
7990   if(!_checkInit()) return;
7991 #if defined(HAVE_FLTK)
7992   _createFltk();
7993   FlGui::instance()->closeTreeItem(name);
7994 #endif
7995 }
7996 
7997 // gmsh::onelab
7998 
set(const std::string & data,const std::string & format)7999 GMSH_API void gmsh::onelab::set(const std::string &data,
8000                                 const std::string &format)
8001 {
8002   if(!_checkInit()) return;
8003 #if defined(HAVE_ONELAB)
8004   if(format == "json") {
8005     if(!::onelab::server::instance()->fromJSON(data))
8006       Msg::Error("Could not parse json data '%s'", data.c_str());
8007   }
8008   else
8009     Msg::Error("Unknown data format");
8010 #else
8011   Msg::Error("ONELAB not available");
8012 #endif
8013 }
8014 
get(std::string & data,const std::string & name,const std::string & format)8015 GMSH_API void gmsh::onelab::get(std::string &data, const std::string &name,
8016                                 const std::string &format)
8017 {
8018   if(!_checkInit()) return;
8019 #if defined(HAVE_ONELAB)
8020   data.clear();
8021   if(name.empty()) {
8022     if(format == "json")
8023       ::onelab::server::instance()->toJSON(data, "Gmsh");
8024     else
8025       Msg::Error("Unknown data format");
8026   }
8027   else {
8028     std::vector< ::onelab::number> ps;
8029     ::onelab::server::instance()->get(ps, name);
8030     if(ps.size()) {
8031       if(format == "json")
8032         data = ps[0].toJSON();
8033       else
8034         data = ps[0].toChar();
8035     }
8036     else {
8037       std::vector< ::onelab::string> ps2;
8038       ::onelab::server::instance()->get(ps2, name);
8039       if(ps2.size()) {
8040         if(format == "json")
8041           data = ps2[0].toJSON();
8042         else
8043           data = ps2[0].toChar();
8044       }
8045     }
8046   }
8047 #else
8048   Msg::Error("ONELAB not available");
8049 #endif
8050 }
8051 
getNames(std::vector<std::string> & names,const std::string & search)8052 GMSH_API void gmsh::onelab::getNames(std::vector<std::string> &names,
8053                                      const std::string &search)
8054 {
8055   if(!_checkInit()) return;
8056 #if defined(HAVE_ONELAB)
8057   ::onelab::server::instance()->getParameterNames(names, search);
8058 #else
8059   Msg::Error("ONELAB not available");
8060 #endif
8061 }
8062 
setNumber(const std::string & name,const std::vector<double> & value)8063 GMSH_API void gmsh::onelab::setNumber(const std::string &name,
8064                                       const std::vector<double> &value)
8065 {
8066   if(!_checkInit()) return;
8067 #if defined(HAVE_ONELAB)
8068   ::onelab::number p(name);
8069   std::vector< ::onelab::number> ps;
8070   ::onelab::server::instance()->get(ps, name);
8071   if(ps.size()) p = ps[0];
8072   p.setValues(value);
8073   ::onelab::server::instance()->set(p);
8074 #else
8075   Msg::Error("ONELAB not available");
8076 #endif
8077 }
8078 
getNumber(const std::string & name,std::vector<double> & value)8079 GMSH_API void gmsh::onelab::getNumber(const std::string &name,
8080                                       std::vector<double> &value)
8081 {
8082   if(!_checkInit()) return;
8083 #if defined(HAVE_ONELAB)
8084   value.clear();
8085   std::vector< ::onelab::number> ps;
8086   ::onelab::server::instance()->get(ps, name);
8087   if(ps.size()) value = ps[0].getValues();
8088 #else
8089   Msg::Error("ONELAB not available");
8090 #endif
8091 }
8092 
setString(const std::string & name,const std::vector<std::string> & value)8093 GMSH_API void gmsh::onelab::setString(const std::string &name,
8094                                       const std::vector<std::string> &value)
8095 {
8096   if(!_checkInit()) return;
8097 #if defined(HAVE_ONELAB)
8098   ::onelab::string p(name);
8099   std::vector< ::onelab::string> ps;
8100   ::onelab::server::instance()->get(ps, name);
8101   if(ps.size()) p = ps[0];
8102   p.setValues(value);
8103   ::onelab::server::instance()->set(p);
8104 #else
8105   Msg::Error("ONELAB not available");
8106 #endif
8107 }
8108 
getString(const std::string & name,std::vector<std::string> & value)8109 GMSH_API void gmsh::onelab::getString(const std::string &name,
8110                                       std::vector<std::string> &value)
8111 {
8112   if(!_checkInit()) return;
8113 #if defined(HAVE_ONELAB)
8114   value.clear();
8115   std::vector< ::onelab::string> ps;
8116   ::onelab::server::instance()->get(ps, name);
8117   if(ps.size()) value = ps[0].getValues();
8118 #else
8119   Msg::Error("ONELAB not available");
8120 #endif
8121 }
8122 
clear(const std::string & name)8123 GMSH_API void gmsh::onelab::clear(const std::string &name)
8124 {
8125   if(!_checkInit()) return;
8126 #if defined(HAVE_ONELAB)
8127   ::onelab::server::instance()->clear(name);
8128 #else
8129   Msg::Error("ONELAB not available");
8130 #endif
8131 }
8132 
run(const std::string & name,const std::string & command)8133 GMSH_API void gmsh::onelab::run(const std::string &name,
8134                                 const std::string &command)
8135 {
8136   if(!_checkInit()) return;
8137 #if defined(HAVE_ONELAB)
8138   onelabUtils::runClient(name, command);
8139 #endif
8140 }
8141 
8142 // gmsh::logger
8143 
write(const std::string & message,const std::string & level)8144 GMSH_API void gmsh::logger::write(const std::string &message,
8145                                   const std::string &level)
8146 {
8147   if(!_checkInit()) return;
8148   if(level == "error")
8149     Msg::Error("%s", message.c_str());
8150   else if(level == "warning")
8151     Msg::Warning("%s", message.c_str());
8152   else
8153     Msg::Info("%s", message.c_str());
8154 }
8155 
8156 class apiMsg : public GmshMessage {
8157 private:
8158   std::vector<std::string> _log;
8159 
8160 public:
apiMsg()8161   apiMsg() {}
operator ()(std::string level,std::string message)8162   virtual void operator()(std::string level, std::string message)
8163   {
8164     _log.push_back(level + ": " + message);
8165   }
get(std::vector<std::string> & log) const8166   void get(std::vector<std::string> &log) const { log = _log; }
8167 };
8168 
start()8169 GMSH_API void gmsh::logger::start()
8170 {
8171   if(!_checkInit()) return;
8172   GmshMessage *msg = Msg::GetCallback();
8173   if(msg) { Msg::Warning("Logger already started - ignoring"); }
8174   else {
8175     msg = new apiMsg();
8176     Msg::SetCallback(msg);
8177   }
8178 }
8179 
get(std::vector<std::string> & log)8180 GMSH_API void gmsh::logger::get(std::vector<std::string> &log)
8181 {
8182   if(!_checkInit()) return;
8183   apiMsg *msg = dynamic_cast<apiMsg *>(Msg::GetCallback());
8184   if(msg) { msg->get(log); }
8185   else {
8186     log.clear();
8187   }
8188 }
8189 
stop()8190 GMSH_API void gmsh::logger::stop()
8191 {
8192   if(!_checkInit()) return;
8193   GmshMessage *msg = Msg::GetCallback();
8194   if(msg) {
8195     delete msg;
8196     Msg::SetCallback(nullptr);
8197   }
8198   else {
8199     Msg::Warning("Logger not started - ignoring");
8200   }
8201 }
8202 
getWallTime()8203 GMSH_API double gmsh::logger::getWallTime()
8204 {
8205   if(!_checkInit()) return -1;
8206   return TimeOfDay();
8207 }
8208 
getCpuTime()8209 GMSH_API double gmsh::logger::getCpuTime()
8210 {
8211   if(!_checkInit()) return -1;
8212   return Cpu();
8213 }
8214 
getLastError(std::string & error)8215 GMSH_API void gmsh::logger::getLastError(std::string &error)
8216 {
8217   if(!_checkInit()) return;
8218   error = Msg::GetLastError();
8219 }
8220