1 /**
2  * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3  * storing and accessing finite element mesh data.
4  *
5  * Copyright 2004 Sandia Corporation.  Under the terms of Contract
6  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7  * retains certain rights in this software.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  */
15 #ifdef WIN32
16 #pragma warning(disable:4786)
17 #endif
18 
19 #include "CGMConfig.h"
20 #include "GeometryQueryTool.hpp"
21 #include "ModelQueryEngine.hpp"
22 #include "RefEntityName.hpp"
23 #include "GMem.hpp"
24 
25 #include "RefGroup.hpp"
26 #include "RefVolume.hpp"
27 #include "RefFace.hpp"
28 #include "RefEdge.hpp"
29 #include "RefVertex.hpp"
30 
31 #include "SenseEntity.hpp"
32 #include "Surface.hpp"
33 #include "Curve.hpp"
34 #include "Body.hpp"
35 #include "InitCGMA.hpp"
36 
37 #include "moab/Core.hpp"
38 #include "moab/Interface.hpp"
39 #include "moab/Range.hpp"
40 #include "MBTagConventions.hpp"
41 #include "moab/FileOptions.hpp"
42 
43 #include "moab/GeomTopoTool.hpp"
44 
45 #include "CubitCompat.hpp"
46 
47 #include <stdio.h>
48 #include <algorithm>
49 #include <assert.h>
50 #include <iostream>
51 
52 #include "ReadCGM.hpp"
53 #include "moab/ReadUtilIface.hpp"
54 
55 namespace moab {
56 
57 #define GF_CUBIT_FILE_TYPE    "CUBIT"
58 #define GF_STEP_FILE_TYPE     "STEP"
59 #define GF_IGES_FILE_TYPE     "IGES"
60 #define GF_OCC_BREP_FILE_TYPE "OCC"
61 #define GF_FACET_FILE_TYPE    "FACET"
62 
factory(Interface * iface)63 ReaderIface* ReadCGM::factory(Interface* iface)
64 {
65   return new ReadCGM(iface);
66 }
67 
ReadCGM(Interface * impl)68 ReadCGM::ReadCGM(Interface *impl)
69   : geom_tag(0), id_tag(0), name_tag(0), category_tag(0), faceting_tol_tag(0),
70     geometry_resabs_tag(0)
71 {
72   assert(NULL != impl);
73   mdbImpl = impl;
74   myGeomTool = new GeomTopoTool(impl);
75   impl->query_interface(readUtilIface);
76   assert(NULL != readUtilIface);
77 
78   // initialise counters
79   failed_curve_count = 0;
80   failed_surface_count = 0;
81 
82   ErrorCode rval;
83 
84   // get some tag handles
85   int negone = -1, zero = 0 /*, negonearr[] = {-1, -1, -1, -1}*/;
86   rval = mdbImpl->tag_get_handle(GEOM_DIMENSION_TAG_NAME, 1, MB_TYPE_INTEGER,
87                                  geom_tag, MB_TAG_SPARSE | MB_TAG_CREAT, &negone);
88   assert(!rval);
89   rval = mdbImpl->tag_get_handle(GLOBAL_ID_TAG_NAME, 1, MB_TYPE_INTEGER,
90                                  id_tag, MB_TAG_DENSE | MB_TAG_CREAT, &zero);
91   assert(!rval);
92   rval = mdbImpl->tag_get_handle(NAME_TAG_NAME, NAME_TAG_SIZE, MB_TYPE_OPAQUE,
93                                  name_tag, MB_TAG_SPARSE | MB_TAG_CREAT);
94   assert(!rval);
95 
96   rval = mdbImpl->tag_get_handle(CATEGORY_TAG_NAME, CATEGORY_TAG_SIZE, MB_TYPE_OPAQUE,
97                                  category_tag, MB_TAG_SPARSE | MB_TAG_CREAT);
98   assert(!rval);
99   rval = mdbImpl->tag_get_handle("FACETING_TOL", 1, MB_TYPE_DOUBLE, faceting_tol_tag,
100                                  MB_TAG_SPARSE | MB_TAG_CREAT);
101   assert(!rval);
102   rval = mdbImpl->tag_get_handle("GEOMETRY_RESABS", 1, MB_TYPE_DOUBLE,
103                                  geometry_resabs_tag, MB_TAG_SPARSE | MB_TAG_CREAT);
104   assert(!rval);
105 #ifdef NDEBUG
106   if (!rval) {}; // Line to avoid compiler warning about variable set but not used
107 #endif
108 }
109 
~ReadCGM()110 ReadCGM::~ReadCGM()
111 {
112   mdbImpl->release_interface(readUtilIface);
113   delete myGeomTool;
114 }
115 
read_tag_values(const char *,const char *,const FileOptions &,std::vector<int> &,const SubsetList *)116 ErrorCode ReadCGM::read_tag_values(const char* /* file_name */,
117                                    const char* /* tag_name */,
118                                    const FileOptions& /* opts */,
119                                    std::vector<int>& /* tag_values_out */,
120                                    const SubsetList* /* subset_list */)
121 {
122   return MB_NOT_IMPLEMENTED;
123 }
124 
125 // Sets options passed into ReadCGM::load_file
set_options(const FileOptions & opts,int & norm_tol,double & faceting_tol,double & len_tol,bool & act_att,bool & verbose_warnings,bool & fatal_on_curves)126 ErrorCode ReadCGM::set_options(const FileOptions& opts,
127                                int& norm_tol,
128                                double& faceting_tol,
129                                double& len_tol,
130                                bool& act_att,
131                                bool& verbose_warnings,
132 			       bool& fatal_on_curves)
133 {
134   ErrorCode rval;
135 
136   // Default Values
137   int DEFAULT_NORM = 5;
138   double DEFAULT_FACET_TOL = 0.001;
139   double DEFAULT_LEN_TOL = 0.0;
140   act_att = true;
141 
142   // Check for the options.
143   if (MB_SUCCESS != opts.get_int_option("FACET_NORMAL_TOLERANCE", norm_tol))
144     norm_tol = DEFAULT_NORM;
145 
146   if (MB_SUCCESS != opts.get_real_option("FACET_DISTANCE_TOLERANCE", faceting_tol))
147     faceting_tol = DEFAULT_FACET_TOL;
148 
149   if (MB_SUCCESS != opts.get_real_option("MAX_FACET_EDGE_LENGTH", len_tol))
150     len_tol = DEFAULT_LEN_TOL;
151 
152   if (MB_SUCCESS == opts.get_null_option("VERBOSE_CGM_WARNINGS"))
153     verbose_warnings = true;
154 
155   if (MB_SUCCESS == opts.get_null_option("FATAL_ON_CURVES"))
156     fatal_on_curves = true;
157 
158 
159 
160   const char* name = "CGM_ATTRIBS";
161   const char* value = "no";
162   rval = opts.match_option(name, value);
163   if (MB_SUCCESS == rval)
164     act_att = false;
165 
166   return MB_SUCCESS;
167 }
168 
create_entity_sets(std::map<RefEntity *,EntityHandle> (& entmap)[5])169 ErrorCode ReadCGM::create_entity_sets(std::map<RefEntity*, EntityHandle> (&entmap)[5])
170 {
171   ErrorCode rval;
172   const char geom_categories[][CATEGORY_TAG_SIZE] =
173               {"Vertex\0", "Curve\0", "Surface\0", "Volume\0", "Group\0"};
174   const char* const names[] = {"Vertex", "Curve", "Surface", "Volume"};
175   DLIList<RefEntity*> entlist;
176 
177   for (int dim = 0; dim < 4; dim++) {
178     entlist.clean_out();
179     GeometryQueryTool::instance()->ref_entity_list(names[dim], entlist, true);
180     entlist.reset();
181 
182     for (int i = entlist.size(); i--; ) {
183       RefEntity* ent = entlist.get_and_step();
184       EntityHandle handle;
185       // Create the new meshset
186       rval = mdbImpl->create_meshset(dim == 1 ? MESHSET_ORDERED : MESHSET_SET, handle);
187       if (MB_SUCCESS != rval)
188         return rval;
189 
190       // Map the geom reference entity to the corresponding moab meshset
191       entmap[dim][ent] = handle;
192 
193       // Create tags for the new meshset
194       rval = mdbImpl->tag_set_data(geom_tag, &handle, 1, &dim);
195       if (MB_SUCCESS != rval)
196         return rval;
197 
198       int id = ent->id();
199       rval = mdbImpl->tag_set_data(id_tag, &handle, 1, &id);
200       if (MB_SUCCESS != rval)
201         return rval;
202 
203       rval = mdbImpl->tag_set_data(category_tag, &handle, 1, &geom_categories[dim]);
204       if (MB_SUCCESS != rval)
205         return rval;
206     }
207   }
208 
209   return MB_SUCCESS;
210 }
211 
create_topology(std::map<RefEntity *,EntityHandle> (& entitymap)[5])212 ErrorCode ReadCGM::create_topology(std::map<RefEntity*, EntityHandle> (&entitymap)[5])
213 {
214   ErrorCode rval;
215   DLIList<RefEntity*> entitylist;
216   std::map<RefEntity*, EntityHandle>::iterator ci;
217 
218   for (int dim = 1; dim < 4; ++dim) {
219     for (ci = entitymap[dim].begin(); ci != entitymap[dim].end(); ++ci) {
220       entitylist.clean_out();
221       ci->first->get_child_ref_entities(entitylist);
222 
223       entitylist.reset();
224       for (int i = entitylist.size(); i--; ) {
225         RefEntity* ent = entitylist.get_and_step();
226         EntityHandle h = entitymap[dim - 1][ent];
227         rval = mdbImpl->add_parent_child(ci->second, h);
228         if (MB_SUCCESS != rval)
229           return rval;
230       }
231     }
232   }
233 
234   return MB_SUCCESS;
235 }
236 
store_surface_senses(std::map<RefEntity *,EntityHandle> & surface_map,std::map<RefEntity *,EntityHandle> & volume_map)237 ErrorCode ReadCGM::store_surface_senses(std::map<RefEntity*, EntityHandle>& surface_map,
238                                         std::map<RefEntity*, EntityHandle>& volume_map)
239 {
240   ErrorCode rval;
241   std::map<RefEntity*, EntityHandle>::iterator ci;
242 
243   for (ci = surface_map.begin(); ci != surface_map.end(); ++ci) {
244     RefFace* face = (RefFace*)(ci->first);
245     BasicTopologyEntity *forward = 0, *reverse = 0;
246     for (SenseEntity* cf = face->get_first_sense_entity_ptr();
247          cf; cf = cf->next_on_bte()) {
248       BasicTopologyEntity* vol = cf->get_parent_basic_topology_entity_ptr();
249       // Allocate vol to the proper topology entity (forward or reverse)
250       if (cf->get_sense() == CUBIT_UNKNOWN ||
251           cf->get_sense() != face->get_surface_ptr()->bridge_sense()) {
252         // Check that each surface has a sense for only one volume
253         if (reverse) {
254           std::cout << "Surface " << face->id() << " has reverse sense " <<
255                        "with multiple volume " << reverse->id() << " and " <<
256                        "volume " << vol->id() << std::endl;
257           return MB_FAILURE;
258         }
259         reverse = vol;
260       }
261       if (cf->get_sense() == CUBIT_UNKNOWN ||
262           cf->get_sense() == face->get_surface_ptr()->bridge_sense()) {
263         // Check that each surface has a sense for only one volume
264         if (forward) {
265           std::cout << "Surface " << face->id() << " has forward sense " <<
266                        "with multiple volume " << forward->id() << " and " <<
267                        "volume " << vol->id() << std::endl;
268           return MB_FAILURE;
269         }
270         forward = vol;
271       }
272     }
273 
274     if (forward) {
275       rval = myGeomTool->set_sense(ci->second, volume_map[forward], SENSE_FORWARD);
276       if (MB_SUCCESS != rval)
277         return rval;
278     }
279     if (reverse) {
280       rval = myGeomTool->set_sense(ci->second, volume_map[reverse], SENSE_REVERSE);
281       if (MB_SUCCESS != rval)
282         return rval;
283     }
284   }
285 
286   return MB_SUCCESS;
287 }
288 
store_curve_senses(std::map<RefEntity *,EntityHandle> & curve_map,std::map<RefEntity *,EntityHandle> & surface_map)289 ErrorCode ReadCGM::store_curve_senses(std::map<RefEntity*, EntityHandle>& curve_map,
290                                       std::map<RefEntity*, EntityHandle>& surface_map)
291 {
292   ErrorCode rval;
293   std::vector<EntityHandle> ents;
294   std::vector<int> senses;
295   std::map<RefEntity*, EntityHandle>::iterator ci;
296   for (ci = curve_map.begin(); ci != curve_map.end(); ++ci) {
297     RefEdge* edge = (RefEdge*)(ci->first);
298     ents.clear();
299     senses.clear();
300     for (SenseEntity* ce = edge->get_first_sense_entity_ptr();
301          ce; ce = ce->next_on_bte()) {
302       BasicTopologyEntity* fac = ce->get_parent_basic_topology_entity_ptr();
303       EntityHandle face = surface_map[fac];
304       if (ce->get_sense() == CUBIT_UNKNOWN ||
305           ce->get_sense() != edge->get_curve_ptr()->bridge_sense()) {
306         ents.push_back(face);
307         senses.push_back(SENSE_REVERSE);
308       }
309       if (ce->get_sense() == CUBIT_UNKNOWN ||
310           ce->get_sense() == edge->get_curve_ptr()->bridge_sense()) {
311         ents.push_back(face);
312         senses.push_back(SENSE_FORWARD);
313       }
314     }
315 
316     rval = myGeomTool->set_senses(ci->second, ents, senses);
317     if (MB_SUCCESS != rval)
318       return rval;
319   }
320   return MB_SUCCESS;
321 }
322 
store_groups(std::map<RefEntity *,EntityHandle> (& entitymap)[5])323 ErrorCode ReadCGM::store_groups(std::map<RefEntity*, EntityHandle> (&entitymap)[5])
324 {
325   ErrorCode rval;
326 
327   // Create entity sets for all ref groups
328   rval = create_group_entsets(entitymap[4]);
329   if (rval != MB_SUCCESS)
330     return rval;
331 
332   // Store group names and entities in the mesh
333   rval = store_group_content(entitymap);
334   if (rval != MB_SUCCESS)
335     return rval;
336 
337   return MB_SUCCESS;
338 }
339 
create_group_entsets(std::map<RefEntity *,EntityHandle> & group_map)340 ErrorCode ReadCGM::create_group_entsets(std::map<RefEntity*, EntityHandle>& group_map)
341 {
342   ErrorCode rval;
343   const char geom_categories[][CATEGORY_TAG_SIZE] =
344       {"Vertex\0", "Curve\0", "Surface\0", "Volume\0", "Group\0"};
345   DLIList<RefEntity*> entitylist;
346   // Create entity sets for all ref groups
347   std::vector<Tag> extra_name_tags;
348 #if CGM_MAJOR_VERSION > 13
349   DLIList<CubitString> name_list;
350 #else
351   DLIList<CubitString*> name_list;
352 #endif
353   entitylist.clean_out();
354   // Get all entity groups from the CGM model
355   GeometryQueryTool::instance()->ref_entity_list("group", entitylist);
356   entitylist.reset();
357   // Loop over all groups
358   for (int i = entitylist.size(); i--; ) {
359     // Take the next group
360     RefEntity* grp = entitylist.get_and_step();
361     name_list.clean_out();
362 // Get the names of all entities in this group from the solid model
363 #if CGM_MAJOR_VERSION > 13
364     RefEntityName::instance()->get_refentity_name(grp, name_list);
365 #else
366     // True argument is optional, but for large multi-names situation, it should save
367     // some cpu time
368     RefEntityName::instance()->get_refentity_name(grp, name_list, true);
369 #endif
370     if (name_list.size() == 0)
371       continue;
372     // Set pointer to first name of the group and set the first name to name1
373     name_list.reset();
374 #if  CGM_MAJOR_VERSION > 13
375     CubitString name1 = name_list.get();
376 #else
377     CubitString name1 = *name_list.get();
378 #endif
379     // Create entity handle for the group
380     EntityHandle h;
381     rval = mdbImpl->create_meshset(MESHSET_SET, h);
382     if (MB_SUCCESS != rval)
383       return rval;
384     // Set tag data for the group
385     char namebuf[NAME_TAG_SIZE];
386     memset(namebuf, '\0', NAME_TAG_SIZE);
387     strncpy(namebuf, name1.c_str(), NAME_TAG_SIZE - 1);
388     if (name1.length() >= (unsigned)NAME_TAG_SIZE)
389       std::cout << "WARNING: group name '" << name1.c_str()
390                 << "' truncated to '" << namebuf << "'" << std::endl;
391     rval = mdbImpl->tag_set_data(name_tag, &h, 1, namebuf);
392     if (MB_SUCCESS != rval)
393       return MB_FAILURE;
394 
395     int id = grp->id();
396     rval = mdbImpl->tag_set_data(id_tag, &h, 1, &id);
397     if (MB_SUCCESS != rval)
398       return MB_FAILURE;
399 
400     rval = mdbImpl->tag_set_data(category_tag, &h, 1, &geom_categories[4]);
401     if (MB_SUCCESS != rval)
402       return MB_FAILURE;
403     // Check for extra group names
404     if (name_list.size() > 1) {
405       for (int j = extra_name_tags.size(); j < name_list.size(); ++j) {
406         sprintf(namebuf, "EXTRA_%s%d", NAME_TAG_NAME, j);
407         Tag t;
408         rval = mdbImpl->tag_get_handle(namebuf, NAME_TAG_SIZE, MB_TYPE_OPAQUE, t, MB_TAG_SPARSE | MB_TAG_CREAT);
409         assert(!rval);
410         extra_name_tags.push_back(t);
411       }
412       // Add extra group names to the group handle
413       for (int j = 0; j < name_list.size(); ++j) {
414 #if  CGM_MAJOR_VERSION>13
415         name1 = name_list.get_and_step();
416 #else
417         name1 = *name_list.get_and_step();
418 #endif
419         memset(namebuf, '\0', NAME_TAG_SIZE);
420         strncpy(namebuf, name1.c_str(), NAME_TAG_SIZE - 1);
421         if (name1.length() >= (unsigned)NAME_TAG_SIZE)
422           std::cout << "WARNING: group name '" << name1.c_str()
423                     << "' truncated to '" << namebuf << "'" << std::endl;
424         rval = mdbImpl->tag_set_data(extra_name_tags[j], &h, 1, namebuf);
425         if (MB_SUCCESS != rval)
426           return MB_FAILURE;
427       }
428     }
429     // Add the group handle
430     group_map[grp] = h;
431   }
432 
433   return MB_SUCCESS;
434 }
435 
store_group_content(std::map<RefEntity *,EntityHandle> (& entitymap)[5])436 ErrorCode ReadCGM::store_group_content(std::map<RefEntity*, EntityHandle> (&entitymap)[5])
437 {
438   ErrorCode rval;
439   DLIList<RefEntity*> entlist;
440   std::map<RefEntity*, EntityHandle>::iterator ci;
441   // Store contents for each group
442   entlist.reset();
443   for (ci = entitymap[4].begin(); ci != entitymap[4].end(); ++ci) {
444     RefGroup* grp = (RefGroup*)(ci->first);
445     entlist.clean_out();
446     grp->get_child_ref_entities(entlist);
447 
448     Range entities;
449     while (entlist.size()) {
450       RefEntity* ent = entlist.pop();
451       int dim = ent->dimension();
452 
453       if (dim < 0) {
454         Body* body;
455         if (entitymap[4].find(ent) != entitymap[4].end()) {
456           // Child is another group; examine its contents
457           entities.insert(entitymap[4][ent]);
458         }
459         else if ((body = dynamic_cast<Body*>(ent)) != NULL) {
460           // Child is a CGM Body, which presumably comprises some volumes--
461           // extract volumes as if they belonged to group.
462           DLIList<RefVolume*> vols;
463           body->ref_volumes(vols);
464           for (int vi = vols.size(); vi--; ) {
465             RefVolume* vol = vols.get_and_step();
466             if (entitymap[3].find(vol) != entitymap[3].end()) {
467               entities.insert(entitymap[3][vol]);
468             }
469             else{
470               std::cerr << "Warning: CGM Body has orphan RefVolume" << std::endl;
471             }
472           }
473         }
474         else {
475           // Otherwise, warn user.
476           std::cerr << "Warning: A dim<0 entity is being ignored by ReadCGM." << std::endl;
477         }
478       }
479       else if (dim < 4) {
480         if (entitymap[dim].find(ent) != entitymap[dim].end())
481           entities.insert(entitymap[dim][ent]);
482       }
483     }
484 
485     if (!entities.empty()) {
486       rval = mdbImpl->add_entities(ci->second, entities);
487       if (MB_SUCCESS != rval)
488         return MB_FAILURE;
489     }
490   }
491 
492   return MB_SUCCESS;
493 }
494 
set_cgm_attributes(bool const act_attributes,bool const verbose)495 void ReadCGM::set_cgm_attributes(bool const act_attributes, bool const verbose)
496 {
497   if (act_attributes) {
498     CGMApp::instance()->attrib_manager()->set_all_auto_read_flags(act_attributes);
499     CGMApp::instance()->attrib_manager()->set_all_auto_actuate_flags(act_attributes);
500   }
501 
502   if (!verbose) {
503     CGMApp::instance()->attrib_manager()->silent_flag(true);
504   }
505 }
506 
create_vertices(std::map<RefEntity *,EntityHandle> & vertex_map)507 ErrorCode ReadCGM::create_vertices(std::map<RefEntity*, EntityHandle> &vertex_map)
508 {
509   ErrorCode rval;
510   std::map<RefEntity*, EntityHandle>::iterator ci;
511   for (ci = vertex_map.begin(); ci != vertex_map.end(); ++ci) {
512     CubitVector pos = dynamic_cast<RefVertex*>(ci->first)->coordinates();
513     double coords[3] = {pos.x(), pos.y(), pos.z()};
514     EntityHandle vh;
515     rval = mdbImpl->create_vertex(coords, vh);
516     if (MB_SUCCESS != rval)
517       return MB_FAILURE;
518 
519     // Add the vertex to its tagged meshset
520     rval = mdbImpl->add_entities(ci->second, &vh, 1);
521     if (MB_SUCCESS != rval)
522       return MB_FAILURE;
523 
524     // Replace the meshset handle with the vertex handle
525     // This makes adding the vertex to higher dim sets easier
526     ci->second = vh;
527   }
528 
529   return MB_SUCCESS;
530 }
531 
create_curve_facets(std::map<RefEntity *,EntityHandle> & curve_map,std::map<RefEntity *,EntityHandle> & vertex_map,int norm_tol,double faceting_tol,bool verbose_warn,bool fatal_on_curves)532 ErrorCode ReadCGM::create_curve_facets(std::map<RefEntity*, EntityHandle>& curve_map,
533                                        std::map<RefEntity*, EntityHandle>& vertex_map,
534 #if CGM_MAJOR_VERSION > 12
535                                        int norm_tol,
536 #else
537                                        int /* norm_tol */,
538 #endif
539                                        double faceting_tol,
540                                        bool verbose_warn,
541 				       bool fatal_on_curves)
542 {
543   ErrorCode rval;
544   CubitStatus s;
545   // Maximum allowable curve-endpoint proximity warnings
546   // If this integer becomes negative, then abs(curve_warnings) is the
547   // number of warnings that were suppressed.
548   int curve_warnings = 0;
549 
550   // Map iterator
551   std::map<RefEntity*, EntityHandle>::iterator ci;
552 
553   // Create geometry for all curves
554   GMem data;
555   for (ci = curve_map.begin(); ci != curve_map.end(); ++ci) {
556     // Get the start and end points of the curve in the form of a reference edge
557     RefEdge* edge = dynamic_cast<RefEdge*>(ci->first);
558     // Get the edge's curve information
559     Curve* curve = edge->get_curve_ptr();
560     // Clean out previous curve information
561     data.clean_out();
562     // Facet curve according to parameters and CGM version
563 #if CGM_MAJOR_VERSION > 12
564     s = edge->get_graphics(data, norm_tol, faceting_tol);
565 #else
566     s = edge->get_graphics(data, faceting_tol);
567 #endif
568 
569     if( s != CUBIT_SUCCESS )
570       {
571 	// if we fatal on curves
572 	if(fatal_on_curves)
573 	  {
574 	    std::cout << "Failed to facet the curve " << edge->id() << std::endl;
575 	    return MB_FAILURE;
576 	  }
577 	// otherwise record them
578 	else
579 	  {
580 	    failed_curve_count++;
581 	    failed_curves.push_back(edge->id());
582 	  }
583 	continue;
584       }
585 
586     std::vector<CubitVector> points;
587     for (int i = 0; i < data.pointListCount; ++i)
588       // Add Cubit vertext points to a list
589       points.push_back(CubitVector(data.point_list()[i].x,
590                                    data.point_list()[i].y,
591                                    data.point_list()[i].z));
592 
593     // Need to reverse data?
594     if (curve->bridge_sense() == CUBIT_REVERSED)
595       std::reverse(points.begin(), points.end());
596 
597     // Check for closed curve
598     RefVertex *start_vtx, *end_vtx;
599     start_vtx = edge->start_vertex();
600     end_vtx = edge->end_vertex();
601 
602     // Special case for point curve
603     if (points.size() < 2) {
604       if (start_vtx != end_vtx || curve->measure() > GEOMETRY_RESABS) {
605         std::cerr << "Warning: No facetting for curve " << edge->id() << std::endl;
606         continue;
607       }
608       EntityHandle h = vertex_map[start_vtx];
609       rval = mdbImpl->add_entities(ci->second, &h, 1);
610       if (MB_SUCCESS != rval)
611         return MB_FAILURE;
612       continue;
613     }
614     // Check to see if the first and last interior vertices are considered to be
615     // coincident by CUBIT
616     const bool closed = (points.front() - points.back()).length() < GEOMETRY_RESABS;
617     if (closed != (start_vtx == end_vtx)) {
618       std::cerr << "Warning: topology and geometry inconsistant for possibly closed curve "
619                 << edge->id() << std::endl;
620     }
621 
622     // Check proximity of vertices to end coordinates
623     if ((start_vtx->coordinates() - points.front()).length() > GEOMETRY_RESABS ||
624         (end_vtx->coordinates() - points.back()).length() > GEOMETRY_RESABS) {
625 
626       curve_warnings--;
627       if (curve_warnings >= 0 || verbose_warn) {
628         std::cerr << "Warning: vertices not at ends of curve " << edge->id() << std::endl;
629         if (curve_warnings == 0 && !verbose_warn) {
630           std::cerr << "         further instances of this warning will be suppressed..." << std::endl;
631         }
632       }
633     }
634     // Create interior points
635     std::vector<EntityHandle> verts, edges;
636     verts.push_back(vertex_map[start_vtx]);
637     for (size_t i = 1; i < points.size() - 1; ++i) {
638       double coords[] = {points[i].x(), points[i].y(), points[i].z()};
639       EntityHandle h;
640       // Create vertex entity
641       rval = mdbImpl->create_vertex(coords, h);
642       if (MB_SUCCESS != rval)
643         return MB_FAILURE;
644       verts.push_back(h);
645     }
646     verts.push_back(vertex_map[end_vtx]);
647 
648     // Create edges
649     for (size_t i = 0; i < verts.size() - 1; ++i) {
650       EntityHandle h;
651       rval = mdbImpl->create_element(MBEDGE, &verts[i], 2, h);
652       if (MB_SUCCESS != rval)
653         return MB_FAILURE;
654       edges.push_back(h);
655     }
656 
657     // If closed, remove duplicate
658     if (verts.front() == verts.back())
659       verts.pop_back();
660     // Add entities to the curve meshset from entitymap
661     rval = mdbImpl->add_entities(ci->second, &verts[0], verts.size());
662     if (MB_SUCCESS != rval)
663       return MB_FAILURE;
664     rval = mdbImpl->add_entities(ci->second, &edges[0], edges.size());
665     if (MB_SUCCESS != rval)
666       return MB_FAILURE;
667   }
668 
669   if (!verbose_warn && curve_warnings < 0) {
670     std::cerr << "Suppressed " << -curve_warnings
671               << " 'vertices not at ends of curve' warnings." << std::endl;
672     std::cerr << "To see all warnings, use reader param VERBOSE_CGM_WARNINGS." << std::endl;
673   }
674 
675   return MB_SUCCESS;
676 }
677 
create_surface_facets(std::map<RefEntity *,EntityHandle> & surface_map,std::map<RefEntity *,EntityHandle> & vertex_map,int norm_tol,double facet_tol,double length_tol)678 ErrorCode ReadCGM::create_surface_facets(std::map<RefEntity*, EntityHandle>& surface_map,
679                                          std::map<RefEntity*, EntityHandle>& vertex_map,
680                                          int norm_tol,
681                                          double facet_tol,
682                                          double length_tol)
683 {
684   ErrorCode rval;
685   std::map<RefEntity*, EntityHandle>::iterator ci;
686   CubitStatus s;
687 #if  ( (CGM_MAJOR_VERSION == 14 && CGM_MINOR_VERSION > 2) || CGM_MAJOR_VERSION >= 15 )
688   DLIList<TopologyEntity*> me_list;
689 #else
690   DLIList<ModelEntity*> me_list;
691 #endif
692 
693   GMem data;
694   // Create geometry for all surfaces
695   for (ci = surface_map.begin(); ci != surface_map.end(); ++ci) {
696     RefFace* face = dynamic_cast<RefFace*>(ci->first);
697 
698     data.clean_out();
699     s = face->get_graphics(data, norm_tol, facet_tol, length_tol);
700 
701     if (CUBIT_SUCCESS != s)
702       return MB_FAILURE;
703 
704     // Declare array of all vertex handles
705     std::vector<EntityHandle> verts(data.pointListCount, 0);
706 
707     // Get list of geometric vertices in surface
708     me_list.clean_out();
709     ModelQueryEngine::instance()->query_model(*face, DagType::ref_vertex_type(), me_list);
710 
711     // For each geometric vertex, find a single coincident point in facets
712     // Otherwise, print a warning
713     for (int i = me_list.size(); i--; ) {
714       // Assign geometric vertex
715       RefVertex* vtx = dynamic_cast<RefVertex*>(me_list.get_and_step());
716       CubitVector pos = vtx->coordinates();
717 
718       for (int j = 0; j < data.pointListCount; ++j) {
719         // Assign facet vertex
720         CubitVector vpos(data.point_list()[j].x,
721                          data.point_list()[j].y,
722                          data.point_list()[j].z);
723         // Check to see if they are considered coincident
724         if ((pos - vpos).length_squared() < GEOMETRY_RESABS*GEOMETRY_RESABS) {
725           // If this facet vertex has already been found coincident, print warning
726           if (verts[j])
727             std::cerr << "Warning: Coincident vertices in surface " << face->id() << std::endl;
728           // If a coincidence is found, keep track of it in the verts vector
729           verts[j] = vertex_map[vtx];
730           break;
731         }
732       }
733     }
734 
735     // Now create vertices for the remaining points in the facetting
736     for (int i = 0; i < data.pointListCount; ++i) {
737       if (verts[i]) // If a geometric vertex
738         continue;
739       double coords[] = {data.point_list()[i].x,
740                          data.point_list()[i].y,
741                          data.point_list()[i].z};
742       // Return vertex handle to verts to fill in all remaining facet
743       // vertices
744       rval = mdbImpl->create_vertex(coords, verts[i]);
745       if (MB_SUCCESS != rval)
746         return rval;
747     }
748 
749     // record the failures for information
750     if (data.fListCount == 0)
751       {
752 	failed_surface_count++;
753 	failed_surfaces.push_back(face->id());
754       }
755 
756     // Now create facets
757     Range facets;
758     std::vector<EntityHandle> corners;
759     for (int i = 0; i < data.fListCount; i += data.facet_list()[i] + 1) {
760       // Get number of facet verts
761       int* facet = data.facet_list() + i;
762       corners.resize(*facet);
763       for (int j = 1; j <= *facet; ++j) {
764         if (facet[j] >= (int)verts.size()) {
765           std::cerr << "ERROR: Invalid facet data for surface " << face->id() << std::endl;
766           return MB_FAILURE;
767         }
768         corners[j - 1] = verts[facet[j]];
769       }
770       EntityType type;
771       if (*facet == 3)
772         type = MBTRI;
773       else {
774         std::cerr << "Warning: non-triangle facet in surface " << face->id() << std::endl;
775         std::cerr << "  entity has " << *facet << " edges" << std::endl;
776         if (*facet == 4)
777           type = MBQUAD;
778         else
779           type = MBPOLYGON;
780       }
781 
782       //if (surf->bridge_sense() == CUBIT_REVERSED)
783         //std::reverse(corners.begin(), corners.end());
784 
785       EntityHandle h;
786       rval = mdbImpl->create_element(type, &corners[0], corners.size(), h);
787       if (MB_SUCCESS != rval)
788         return MB_FAILURE;
789 
790       facets.insert(h);
791     }
792 
793     // Add vertices and facets to surface set
794     rval = mdbImpl->add_entities(ci->second, &verts[0], verts.size());
795     if (MB_SUCCESS != rval)
796       return MB_FAILURE;
797     rval = mdbImpl->add_entities(ci->second, facets);
798     if (MB_SUCCESS != rval)
799       return MB_FAILURE;
800   }
801 
802   return MB_SUCCESS;
803 }
804 
805 // Copy geometry into mesh database
load_file(const char * cgm_file_name,const EntityHandle * file_set,const FileOptions & opts,const ReaderIface::SubsetList * subset_list,const Tag *)806 ErrorCode ReadCGM::load_file(const char *cgm_file_name,
807                              const EntityHandle* file_set,
808                              const FileOptions& opts,
809                              const ReaderIface::SubsetList* subset_list,
810                              const Tag* /*file_id_tag*/)
811 {
812   // Blocks_to_load and num_blocks are ignored.
813   ErrorCode rval;
814 
815   if (subset_list) {
816     MB_SET_ERR(MB_UNSUPPORTED_OPERATION, "Reading subset of files not supported for CGM data");
817   }
818 
819   int norm_tol;
820   double faceting_tol;
821   double len_tol;
822   bool act_att = true;
823   bool verbose_warnings = false;
824   bool fatal_on_curves = false;
825 
826   rval = set_options(opts, norm_tol, faceting_tol, len_tol, act_att, verbose_warnings,fatal_on_curves);
827   if (MB_SUCCESS != rval)
828     return rval;
829 
830   // Always tag with the faceting_tol and geometry absolute resolution
831   // If file_set is defined, use that, otherwise (file_set == NULL) tag the interface
832   EntityHandle set = file_set ? *file_set : 0;
833   rval = mdbImpl->tag_set_data(faceting_tol_tag, &set, 1, &faceting_tol);
834   if (MB_SUCCESS != rval)
835     return rval;
836 
837   rval = mdbImpl->tag_set_data(geometry_resabs_tag, &set, 1, &GEOMETRY_RESABS);
838   if (MB_SUCCESS != rval)
839     return rval;
840 
841   // Initialize CGM
842   InitCGMA::initialize_cgma();
843 
844   // Determine CGM settings and amount of output
845   set_cgm_attributes(act_att, verbose_warnings);
846 
847   CubitStatus s;
848 
849   // Get CGM file type
850   const char* file_type = 0;
851   file_type = get_geom_file_type(cgm_file_name);
852   if (!file_type || !strcmp(file_type , "CUBIT"))
853     return MB_FAILURE;
854 
855   s = CubitCompat_import_solid_model(cgm_file_name, file_type);
856   if (CUBIT_SUCCESS != s) {
857     MB_SET_ERR(MB_FAILURE, cgm_file_name << ": Failed to read file of type \"" << file_type << "\"");
858   }
859 
860   // Create entity sets for all geometric entities
861   std::map<RefEntity*, EntityHandle> entmap[5]; // One for each dim, and one for groups
862 
863   rval = create_entity_sets(entmap);
864   if (rval != MB_SUCCESS)
865     return rval;
866 
867   // Create topology for all geometric entities
868   rval = create_topology(entmap);
869   if (rval != MB_SUCCESS)
870     return rval;
871 
872   // Store CoFace senses
873   rval = store_surface_senses(entmap[2], entmap[3]);
874   if (rval != MB_SUCCESS)
875     return rval;
876 
877   // Store CoEdge senses
878   rval = store_curve_senses(entmap[1], entmap[2]);
879   if (rval != MB_SUCCESS)
880     return rval;
881 
882   // Get group information and store it in the mesh
883   rval = store_groups(entmap);
884   if (rval != MB_SUCCESS)
885     return rval;
886 
887   // Done with volumes and groups
888   entmap[3].clear();
889   entmap[4].clear();
890 
891   // Create geometry for all vertices and replace
892   rval = create_vertices(entmap[0]);
893   if (rval != MB_SUCCESS)
894     return rval;
895 
896   // Create facets for all curves
897   rval = create_curve_facets(entmap[1], entmap[0], norm_tol, faceting_tol, verbose_warnings, fatal_on_curves);
898   if (rval != MB_SUCCESS)
899     return rval;
900 
901   // Create facets for surfaces
902   rval = create_surface_facets(entmap[2], entmap[0], norm_tol, faceting_tol, len_tol);
903   if (rval != MB_SUCCESS)
904     return rval;
905 
906   // print the fail information
907   dump_fail_counts();
908 
909   return MB_SUCCESS;
910 }
911 
912 // return the number of curves that failed to facet
get_failed_curve_count()913 int ReadCGM::get_failed_curve_count()
914 {
915   return failed_curve_count;
916 }
917 
918 // return the number of surfaces that failed to facet
get_failed_surface_count()919 int ReadCGM::get_failed_surface_count()
920 {
921   return failed_surface_count;
922 }
923 
dump_fail_counts()924 void ReadCGM::dump_fail_counts()
925 {
926   std::cout << "***** Faceting Summary Information *****" << std::endl;
927   std::cout << "----- Curve Fail Information -----" << std::endl;
928   std::cout << "There were " << failed_curve_count << " curves that could not be faceted." << std::endl;
929 
930   if(failed_curve_count > 0 )
931     {
932       std::cout << "The curves were ";
933       for ( int i = 0 ; i < failed_curve_count ; i++ )
934 	{
935 	  std::cout << failed_curves[i] << " ";
936 	  if ( (i%10 == 0) & (i > 0) )
937 	    std::cout << std::endl;
938 	}
939     }
940   std::cout << std::endl;
941   std::cout << "----- Facet Fail Information -----" << std::endl;
942   std::cout << "There were " << failed_surface_count << " surfaces that could not be faceted." << std::endl;
943   if(failed_surface_count > 0 )
944     {
945       std::cout << "The surfaces were ";
946       for ( int i = 0 ; i < failed_surface_count ; i++ )
947 	{
948 	  std::cout << failed_surfaces[i] << " ";
949 	  if ( (i%10 == 0) & (i > 0) )
950 	    std::cout << std::endl;
951 	}
952     }
953   std::cout << std::endl;
954   std::cout << "***** End of Faceting Summary Information *****" << std::endl;
955   return;
956 }
957 
get_geom_file_type(const char * name)958 const char* ReadCGM::get_geom_file_type(const char* name)
959 {
960   FILE* file;
961   const char* result = 0;
962 
963   file = fopen(name, "r");
964   if (file) {
965     result = get_geom_fptr_type(file);
966     fclose(file);
967   }
968 
969   return result;
970 }
971 
get_geom_fptr_type(FILE * file)972 const char* ReadCGM::get_geom_fptr_type(FILE* file)
973 {
974   static const char* CUBIT_NAME = GF_CUBIT_FILE_TYPE;
975   static const char*  STEP_NAME = GF_STEP_FILE_TYPE;
976   static const char*  IGES_NAME = GF_IGES_FILE_TYPE;
977   static const char*  BREP_NAME = GF_OCC_BREP_FILE_TYPE;
978   static const char* FACET_NAME = GF_FACET_FILE_TYPE;
979 
980   if (is_cubit_file(file))
981     return CUBIT_NAME;
982   else if (is_step_file(file))
983     return STEP_NAME;
984   else if (is_iges_file(file))
985     return IGES_NAME;
986   else if (is_occ_brep_file(file))
987     return BREP_NAME;
988   else if (is_facet_file(file))
989     return FACET_NAME;
990   else
991     return NULL;
992 }
993 
is_cubit_file(FILE * file)994 int ReadCGM::is_cubit_file(FILE* file)
995 {
996   unsigned char buffer[4];
997   return !fseek(file, 0, SEEK_SET) &&
998          fread(buffer, 4, 1, file) &&
999          !memcmp(buffer, "CUBE", 4);
1000 }
1001 
is_step_file(FILE * file)1002 int ReadCGM::is_step_file(FILE* file)
1003 {
1004   unsigned char buffer[9];
1005   return !fseek(file, 0, SEEK_SET) &&
1006          fread(buffer, 9, 1, file) &&
1007          !memcmp(buffer, "ISO-10303", 9);
1008 }
1009 
is_iges_file(FILE * file)1010 int ReadCGM::is_iges_file(FILE* file)
1011 {
1012   unsigned char buffer[10];
1013   return !fseek(file, 72, SEEK_SET) &&
1014          fread(buffer, 10, 1, file) &&
1015          !memcmp(buffer, "S      1", 8);
1016 }
1017 
is_occ_brep_file(FILE * file)1018 int ReadCGM::is_occ_brep_file(FILE* file)
1019 {
1020   unsigned char buffer[6];
1021   return !fseek(file, 0, SEEK_SET) &&
1022          fread(buffer, 6, 1, file) &&
1023          !memcmp(buffer, "DBRep_", 6);
1024 }
is_facet_file(FILE * file)1025 int ReadCGM::is_facet_file(FILE* file)
1026 {
1027   unsigned char buffer[10];
1028   return !fseek(file, 0, SEEK_SET) &&
1029          fread(buffer, 10, 1, file) &&
1030          !memcmp(buffer, "MESH_BASED", 10);
1031 }
1032 
tokenize(const std::string & str,std::vector<std::string> & tokens,const char * delimiters)1033 void ReadCGM::tokenize(const std::string& str,
1034                        std::vector<std::string>& tokens,
1035                        const char* delimiters)
1036 {
1037   std::string::size_type last = str.find_first_not_of(delimiters, 0);
1038   std::string::size_type pos  = str.find_first_of(delimiters, last);
1039   while (std::string::npos != pos && std::string::npos != last) {
1040     tokens.push_back(str.substr(last, pos - last));
1041     last = str.find_first_not_of(delimiters, pos);
1042     pos  = str.find_first_of(delimiters, last);
1043     if (std::string::npos == pos)
1044       pos = str.size();
1045   }
1046 }
1047 
1048 } // namespace moab
1049