Nektar++
CADSystemCFI.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: CADSystemCFI.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: cad object methods.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include "CADSystemCFI.h"
36 #include "CADCurveCFI.h"
37 #include "CADSurfCFI.h"
38 #include "CADVertCFI.h"
39 
40 using namespace std;
41 
42 namespace Nektar
43 {
44 namespace NekMeshUtils
45 {
46 
47 std::string CADSystemCFI::key = GetEngineFactory().RegisterCreatorFunction(
48  "cfi", CADSystemCFI::create, "Uses CFI as cad engine");
49 
50 bool CADSystemCFI::LoadCAD()
51 {
52  // it is possible to get CFI to lock on to a open gui session
53  // not sure it ever will with this code
54  cfiHandel.startServer();
55  if (m_verbose)
56  {
57  cout << "cfi loaded in mode: ";
58  if (cfiHandel.info.mode == cfi::MODE_STANDALONE)
59  {
60  cout << "standalone" << endl;
61  }
62  else if (cfiHandel.info.mode == cfi::MODE_CLIENT)
63  {
64  cout << "client" << endl;
65  }
66  else if (cfiHandel.info.mode == cfi::MODE_SERVER)
67  {
68  cout << "server" << endl;
69  }
70  else if (cfiHandel.info.mode == cfi::MODE_BOTH)
71  {
72  cout << "both" << endl;
73  }
74  else if (cfiHandel.info.mode == cfi::MODE_PLUGIN)
75  {
76  cout << "plugin" << endl;
77  }
78  else
79  {
80  cout << "unknown" << endl;
81  }
82 
83  cout << "\tVersion " << cfiHandel.info.version << endl
84  << "\tfixno " << cfiHandel.info.fixno << endl
85  << "\tubid " << cfiHandel.info.ubid << endl;
86  }
87 
88  model = cfiHandel.openModelFile(m_name.c_str());
89 
90  if (model->getEntityTotal(cfi::TYPE_BODY, cfi::SUBTYPE_ALL) != 1)
91  {
92  if (m_cfiMesh)
93  {
94  if (m_verbose)
95  {
96  cout << "\tWill extract mesh and have multibodies" << endl;
97  }
98  }
99  else
100  {
101  if (m_verbose)
102  {
103  cout << "\tHas multibodies and instructions to mesh, this is "
104  "not "
105  "possible"
106  << endl;
107  }
108  abort();
109  }
110  }
111 
112  vector<cfi::Entity *> *bds =
113  model->getEntityList(cfi::TYPE_BODY, cfi::SUBTYPE_ALL);
114 
115  for (auto &i : *bds)
116  {
117  cfi::Body *b = static_cast<cfi::Body *>(i);
118  bodies.push_back(b);
119  }
120 
121  // cfi doesnt mind stupid units so this scales everything back to meters
122  // which is what nekmesh assumes its in
123  // the m_scal object is passed to all cad entities and scales any operation
124  // before running it.
125  m_scal = 1.0;
126  if (model->getUnits() == cfi::UNIT_INCHES)
127  {
128  if (m_verbose)
129  {
130  cout << "\tModel is in inches, scaling accordingly" << endl;
131  }
132  m_scal = 0.0254;
133  }
134  else if (model->getUnits() == cfi::UNIT_MILLIMETERS ||
135  model->getUnits() == cfi::UNIT_MILLIMETRES)
136  {
137  if (m_verbose)
138  {
139  cout << "\tModel is in mm, scaling accordingly" << endl;
140  }
141  m_scal = 1e-3;
142  }
143 
144  // CFI does everything by string identifers
145  // currently nekmesh cad system uses integer ids.
146  // it really should use strings but doesnt currently
147  map<string, cfi::Point *> mapOfVerts;
148  map<string, cfi::Line *> mapOfEdges;
149  map<string, cfi::Face *> mapOfFaces;
150 
151  // nothing is unique in cfi, there can list of verts that arnt used
152  // or are listed twice. This block gets all the real unique vertices in the
153  // cad by cascading down from the faces
154  // also builds a list on unique edges in the process
155 
156  for (int i = 0; i < bodies.size(); i++)
157  {
158  // check that it is not a group of bodies
159  if (bodies[i]->getTopoSubtype() == cfi::SUBTYPE_COMBINED)
160  {
161  continue;
162  }
163 
164  vector<cfi::Oriented<cfi::TopoEntity *>> *faceList =
165  bodies[i]->getChildList();
166 
167  vector<cfi::Oriented<cfi::TopoEntity *>>::iterator it, it2, it3;
168  for (it = faceList->begin(); it != faceList->end(); it++)
169  {
170  cfi::Oriented<cfi::TopoEntity *> orientatedFace = *it;
171  cfi::Face *face = static_cast<cfi::Face *>(orientatedFace.entity);
172 
173  try
174  {
175  boost::optional<cfi::Oriented<cfi::Surface *>> surf =
176  face->getTopoEmbedding();
177  }
178  catch (std::exception &e)
179  {
180  // dont want this face
181  continue;
182  }
183 
184  auto it = mapOfFaces.find(face->getName());
185  if (it == mapOfFaces.end())
186  {
187  vector<cfi::Oriented<cfi::TopoEntity *>> *edgeList =
188  face->getChildList();
189 
190  // unrolling combined edges
191  vector<cfi::Oriented<cfi::TopoEntity *>> fullEdgeList;
192  for (it2 = edgeList->begin(); it2 != edgeList->end(); it2++)
193  {
194  cfi::Line *edge = static_cast<cfi::Line *>(it2->entity);
195 
196  if (edge->getTopoSubtype() == cfi::SUBTYPE_COMBINED)
197  {
198  vector<cfi::Oriented<cfi::TopoEntity *>> *subEdgeList =
199  edge->getChildList();
200 
201  for (it3 = subEdgeList->begin();
202  it3 != subEdgeList->end(); it3++)
203  {
204  fullEdgeList.push_back(*it3);
205  }
206  }
207  else
208  {
209  fullEdgeList.push_back(*it2);
210  }
211  }
212 
213  for (it2 = fullEdgeList.begin(); it2 != fullEdgeList.end(); it2++)
214  {
215  cfi::Oriented<cfi::TopoEntity *> orientatedEdge = *it2;
216  cfi::Line *edge =
217  static_cast<cfi::Line *>(orientatedEdge.entity);
218  mapOfEdges[edge->getName()] = edge;
219 
220  vector<cfi::Oriented<cfi::TopoEntity *>> *vertList =
221  edge->getChildList();
222  for (it3 = vertList->begin(); it3 != vertList->end(); it3++)
223  {
224  cfi::Oriented<cfi::TopoEntity *> orientatedVert = *it3;
225  cfi::Point *vert =
226  static_cast<cfi::Point *>(orientatedVert.entity);
227  mapOfVerts[vert->getName()] = vert;
228  mapVertToListEdge[vert->getName()].push_back(
229  edge->getName());
230  }
231  }
232 
233  mapOfFaces[face->getName()] = face;
234  }
235  }
236  }
237 
238  // make the vertices and build a map of name to id
239  map<string, cfi::Point *>::iterator vit;
240  int i = 1; // from one to be consistent with oce
241  for (vit = mapOfVerts.begin(); vit != mapOfVerts.end(); vit++, i++)
242  {
243  AddVert(i, vit->second);
244  nameToVertId[vit->second->getName()] = i;
245  }
246 
247  // build curves
248  map<string, cfi::Line *>::iterator eit;
249  i = 1;
250  for (eit = mapOfEdges.begin(); eit != mapOfEdges.end(); eit++, i++)
251  {
252  AddCurve(i, eit->second);
253  nameToCurveId[eit->second->getName()] = i;
254  }
255 
256  // build surfaces
257  map<string, cfi::Face *>::iterator fit;
258  i = 1;
259  for (fit = mapOfFaces.begin(); fit != mapOfFaces.end(); fit++, i++)
260  {
261  nameToFaceId[fit->second->getName()] = i;
262 
263  AddSurf(i, fit->second);
264  }
265 
266  // TODO identify Degenerated faces and setdegen on vertices accordinaly
267 
268  // This checks that all edges are bound by two surfaces, sanity check.
269  if (!m_2d && !m_cfiMesh)
270  {
271  map<int, CADCurveSharedPtr>::iterator it;
272  for (it = m_curves.begin(); it != m_curves.end(); it++)
273  {
274  ASSERTL0(it->second->GetAdjSurf().size() == 2,
275  "curve is not joined to 2 surfaces");
276  }
277  }
278 
279  if (m_verbose)
280  {
281  Report();
282  }
283 
284  return true;
285 }
286 
287 void CADSystemCFI::AddVert(int i, cfi::Point *in)
288 {
290 
291  static_pointer_cast<CADVertCFI>(newVert)->Initialise(i, in, m_scal);
292 
293  m_verts[i] = newVert;
294  m_verts[i]->SetName(in->getName());
295 }
296 
297 void CADSystemCFI::AddCurve(int i, cfi::Line *in)
298 {
300  static_pointer_cast<CADCurveCFI>(newCurve)->Initialise(i, in, m_scal);
301 
302  vector<cfi::Oriented<cfi::TopoEntity *>> *vertList = in->getChildList();
303 
304  ASSERTL0(vertList->size() == 2, "should be two ends");
305 
306  vector<cfi::Oriented<cfi::TopoEntity *>>::iterator it;
307  vector<NekDouble> t;
308  for (it = vertList->begin(); it != vertList->end(); it++)
309  {
310  cfi::Oriented<cfi::TopoEntity *> orientatedVert = *it;
311  cfi::Point *vert = static_cast<cfi::Point *>(orientatedVert.entity);
312  boost::optional<cfi::Projected<double>> pj =
313  in->calcTFromXYZ(vert->getGeometry(), -1);
314  t.push_back(pj.value().parameters);
315  }
316  ASSERTL0(t[0] < t[1], "weirdness");
317 
318  vector<CADVertSharedPtr> vs;
319  vs.push_back(m_verts[nameToVertId[vertList->at(0).entity->getName()]]);
320  vs.push_back(m_verts[nameToVertId[vertList->at(1).entity->getName()]]);
321  m_curves[i] = newCurve;
322  m_curves[i]->SetVert(vs);
323  m_curves[i]->SetName(in->getName());
324  m_verts[nameToVertId[vertList->at(0).entity->getName()]]->AddAdjCurve(
325  m_curves[i]);
326  m_verts[nameToVertId[vertList->at(1).entity->getName()]]->AddAdjCurve(
327  m_curves[i]);
328 }
329 
330 void CADSystemCFI::AddSurf(int i, cfi::Face *in)
331 {
333  static_pointer_cast<CADSurfCFI>(newSurf)->Initialise(i, in, m_scal);
334 
335  vector<cfi::Oriented<cfi::TopoEntity *>> *edgeList = in->getChildList();
336 
337  // unrolling combined edges
338  vector<cfi::Oriented<cfi::TopoEntity *>> fullEdgeList;
339  vector<cfi::Oriented<cfi::TopoEntity *>>::iterator it2, it3;
340  for (it2 = edgeList->begin(); it2 != edgeList->end(); it2++)
341  {
342  cfi::Line *edge = static_cast<cfi::Line *>(it2->entity);
343 
344  if (edge->getTopoSubtype() == cfi::SUBTYPE_COMBINED)
345  {
346  vector<cfi::Oriented<cfi::TopoEntity *>> *subEdgeList =
347  edge->getChildList();
348 
349  for (it3 = subEdgeList->begin(); it3 != subEdgeList->end(); it3++)
350  {
351  fullEdgeList.push_back(*it3);
352  }
353 
354  if (it2->orientation == cfi::ORIENT_NEGATIVE)
355  {
356  reverse(fullEdgeList.begin() + fullEdgeList.size() -
357  subEdgeList->size(),
358  fullEdgeList.end());
359  }
360  }
361  else
362  {
363  fullEdgeList.push_back(*it2);
364  }
365  }
366 
367  vector<EdgeLoopSharedPtr> edgeloops;
368  int done = 0;
369  while (done != fullEdgeList.size())
370  {
372  string firstVert;
373  vector<cfi::Oriented<cfi::TopoEntity *>> *vertList =
374  fullEdgeList.at(done).entity->getChildList();
375  if (fullEdgeList.at(done).orientation == cfi::ORIENT_POSITIVE)
376  {
377  firstVert = vertList->at(0).entity->getName();
378  edgeloop->edgeo.push_back(CADOrientation::eForwards);
379  }
380  else
381  {
382  firstVert = vertList->at(1).entity->getName();
383  edgeloop->edgeo.push_back(CADOrientation::eBackwards);
384  }
385 
386  edgeloop->edges.push_back(
387  m_curves[nameToCurveId[fullEdgeList.at(done).entity->getName()]]);
388 
389  for (done++; done < fullEdgeList.size(); done++)
390  {
391  bool end = false;
392  vertList = fullEdgeList.at(done).entity->getChildList();
393  if (fullEdgeList.at(done).orientation == cfi::ORIENT_POSITIVE)
394  {
395  if (vertList->at(1).entity->getName() == firstVert)
396  {
397  end = true;
398  }
399  edgeloop->edgeo.push_back(CADOrientation::eForwards);
400  }
401  else
402  {
403  if (vertList->at(0).entity->getName() == firstVert)
404  {
405  end = true;
406  }
407  edgeloop->edgeo.push_back(CADOrientation::eBackwards);
408  }
409 
410  edgeloop->edges.push_back(
411  m_curves[nameToCurveId[fullEdgeList.at(done).entity->getName()]]);
412 
413  if (end)
414  {
415  done++;
416  break;
417  }
418  }
419  edgeloops.push_back(edgeloop);
420  }
421 
422  // TODO find if surface has reversed normal or not
423 
424  int tote = 0;
425  for (int k = 0; k < edgeloops.size(); k++)
426  {
427  tote += edgeloops[k]->edges.size();
428  }
429 
430  ASSERTL0(tote != 1, "cannot handle periodic curves");
431 
432  CADSurf::OrientateEdges(newSurf, edgeloops);
433  newSurf->SetEdges(edgeloops);
434 
435  // now the loops are orientated, tell the curves how they are
436  for (int k = 0; k < edgeloops.size(); k++)
437  {
438  for (int j = 0; j < edgeloops[k]->edges.size(); j++)
439  {
440  edgeloops[k]->edges[j]->SetAdjSurf(
441  make_pair(newSurf, edgeloops[k]->edgeo[j]));
442  }
443  }
444 
445  m_surfs[i] = newSurf;
446  m_surfs[i]->SetName(in->getName());
447 }
448 
449 Array<OneD, NekDouble> CADSystemCFI::GetBoundingBox()
450 {
451  cfi::BoundingBox box = model->calcBoundingBox();
452 
453  Array<OneD, NekDouble> ret(6);
454  ret[0] = box.xLower;
455  ret[1] = box.xUpper;
456  ret[2] = box.yLower;
457  ret[3] = box.yUpper;
458  ret[4] = box.zLower;
459  ret[5] = box.zUpper;
460 
461  return ret;
462 }
463 }
464 }
CADCurveFactory & GetCADCurveFactory()
Definition: CADSystem.cpp:59
std::shared_ptr< CADSurf > CADSurfSharedPtr
Definition: CADCurve.h:51
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
std::shared_ptr< EdgeLoop > EdgeLoopSharedPtr
Definition: CADSurf.h:65
std::shared_ptr< CADVert > CADVertSharedPtr
Definition: CADCurve.h:49
STL namespace.
struct which descibes a collection of cad edges which are a loop on the cad surface ...
Definition: CADSurf.h:57
CADVertFactory & GetCADVertFactory()
Definition: CADSystem.cpp:53
def model(self)
Definition: pycml.py:2654
CADSurfFactory & GetCADSurfFactory()
Definition: CADSystem.cpp:65
bg::model::box< point > box
Definition: BLMesh.cpp:54
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
std::shared_ptr< CADCurve > CADCurveSharedPtr
Definition: CADCurve.h:219
EngineFactory & GetEngineFactory()
Definition: CADSystem.cpp:47
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:199