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