Skip to content

Commit ebc4d4c

Browse files
authored
Fix GOCAD IO plugin (#9445)
2 parents ba0f121 + 3368e3a commit ebc4d4c

6 files changed

Lines changed: 122 additions & 78 deletions

File tree

BGL/include/CGAL/boost/graph/IO/GOCAD.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ class GOCAD_builder
103103
/// \cgalParamType{Boolean}
104104
/// \cgalParamDefault{`false`}
105105
/// \cgalParamNEnd
106+
/// \cgalParamNBegin{read_only_one_object}
107+
/// \cgalParamDescription{if `true` only one GOCAD object will be read in the stream, and the stream will be left ready for the reading of the next GOCAD object.}
108+
/// \cgalParamType{Boolean}
109+
/// \cgalParamDefault{`false`}
110+
/// \cgalParamNEnd
106111
/// \cgalNamedParamsEnd
107112
///
108113
/// \returns `true` if reading was successful and the resulting mesh is valid, `false` otherwise.
@@ -175,6 +180,11 @@ bool read_GOCAD(std::istream& is, Graph& g, const CGAL_NP_CLASS& np = parameters
175180
/// \cgalParamType{Boolean}
176181
/// \cgalParamDefault{`false`}
177182
/// \cgalParamNEnd
183+
/// \cgalParamNBegin{read_only_one_object}
184+
/// \cgalParamDescription{if `true` only one GOCAD object will be read in the stream, and the stream will be left ready for the reading of the next GOCAD object.}
185+
/// \cgalParamType{Boolean}
186+
/// \cgalParamDefault{`false`}
187+
/// \cgalParamNEnd
178188
/// \cgalNamedParamsEnd
179189
///
180190
/// \sa Overloads of this function for specific models of the concept `FaceGraph`.

BGL/include/CGAL/boost/graph/IO/Generic_facegraph_builder.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ class Generic_facegraph_builder
8888

8989
const bool verbose = choose_parameter(get_parameter(np, internal_np::verbose), false);
9090
const bool binary = choose_parameter(get_parameter(np, internal_np::use_binary_mode), true);
91+
const bool read_only_one_object = choose_parameter(get_parameter(np, internal_np::read_only_one_object), false);
9192

9293
bool ok =
9394
static_cast<Derived*>(this)->read(m_is, m_points, m_faces,
@@ -96,7 +97,8 @@ class Generic_facegraph_builder
9697
.vertex_texture_output_iterator(std::back_inserter(vertex_textures))
9798
.face_color_output_iterator(std::back_inserter(face_colors))
9899
.verbose(verbose)
99-
.use_binary_mode(binary));
100+
.use_binary_mode(binary)
101+
.read_only_one_object(read_only_one_object));
100102
if(!ok)
101103
return false;
102104

BGL/test/BGL/test_bgl_read_write.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -710,7 +710,9 @@ void test_bgl_GOCAD(const char* filename)
710710
assert(ok);
711711
assert(num_vertices(fg) != 0 && num_faces(fg) != 0);
712712

713-
is.seekg(0);
713+
is.close();
714+
is.open(filename);
715+
714716
CGAL::clear(fg);
715717
std::pair<std::string, std::string> name_and_color;
716718
ok = CGAL::IO::read_GOCAD(is, name_and_color, fg);

Lab/demo/Lab/Plugins/IO/GOCAD_io_plugin.cpp

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ class CGAL_Lab_gocad_plugin :
3939
};
4040

4141
QString CGAL_Lab_gocad_plugin::nameFilters() const {
42-
return "GOCAD files (*.ts)";
42+
return "GOCAD files (*.ts *.ml)";
43+
4344
}
4445

4546
bool CGAL_Lab_gocad_plugin::canLoad(QFileInfo) const {
@@ -52,53 +53,72 @@ CGAL_Lab_gocad_plugin::load(QFileInfo fileinfo, bool& ok, bool add_to_scene) {
5253

5354
// Open file
5455
std::ifstream in(fileinfo.filePath().toUtf8());
56+
QList<Scene_item*> new_item_list;
5557
if(!in) {
5658
std::cerr << "Error! Cannot open file " << (const char*)fileinfo.filePath().toUtf8() << std::endl;
5759
ok = false;
58-
return QList<Scene_item*>();
60+
return new_item_list;
5961
}
60-
in.close();
6162

6263
CGAL::Timer t;
6364
t.start();
64-
// Try to read GOCAD file in a surface_mesh
65-
Scene_surface_mesh_item* item = new Scene_surface_mesh_item(new SMesh());
66-
if(fileinfo.size() == 0)
65+
66+
SMesh P;
67+
std::pair<std::string,std::string> name_and_color;
68+
while(!in.eof() && CGAL::IO::read_GOCAD(in, name_and_color, P, CGAL::parameters::read_only_one_object(true)))
6769
{
68-
CGAL::Three::Three::warning( tr("The file you are trying to load is empty."));
69-
ok = true;
70+
if (P.is_empty()) continue; // skip non-handled objects
71+
72+
Scene_surface_mesh_item* item = new Scene_surface_mesh_item(new SMesh(std::move(P)));
73+
74+
P = SMesh();
75+
76+
if(name_and_color.first.size() == 0){
77+
item->setName(fileinfo.completeBaseName());
78+
} else {
79+
item->setName(name_and_color.first.c_str());
80+
}
81+
QColor qcolor(name_and_color.second.c_str());
82+
if(qcolor.isValid())
83+
{
84+
item->setColor(qcolor);
85+
}
86+
item->invalidateOpenGLBuffers();
87+
7088
if(add_to_scene)
7189
CGAL::Three::Three::scene()->addItem(item);
72-
return QList<Scene_item*>()<<item;
90+
91+
new_item_list << item;
7392
}
74-
SMesh& P = * const_cast<SMesh*>(item->polyhedron());
7593

76-
std::pair<std::string,std::string> name_and_color;
77-
if(! CGAL::IO::read_GOCAD(in, name_and_color, P))
94+
std::cout << new_item_list.size() << "\n";
95+
96+
if (in.bad())
7897
{
79-
std::cerr << "Error: Invalid polyhedron" << std::endl;
80-
delete item;
81-
ok = false;
82-
return QList<Scene_item*>();
98+
std::cerr << "Error while parsing file" << std::endl;
99+
ok=false;
100+
for(auto item : new_item_list)
101+
delete item;
102+
new_item_list.clear();
103+
return new_item_list;
83104
}
84105

106+
ok = true;
107+
85108
t.stop();
86109
std::cerr << "Reading took " << t.time() << " sec." << std::endl;
87-
if(name_and_color.first.size() == 0){
88-
item->setName(fileinfo.completeBaseName());
89-
} else {
90-
item->setName(name_and_color.first.c_str());
91-
}
92-
QColor qcolor(name_and_color.second.c_str());
93-
if(qcolor.isValid())
110+
111+
if (new_item_list.size()>1)
94112
{
95-
item->setColor(qcolor);
113+
Scene_group_item* group = new Scene_group_item(fileinfo.completeBaseName());
114+
if(add_to_scene)
115+
CGAL::Three::Three::scene()->addItem(group);
116+
for (Scene_item* item : new_item_list)
117+
CGAL::Three::Three::scene()->changeGroup(item, group);
118+
return QList<Scene_item*>()<<group;
96119
}
97-
item->invalidateOpenGLBuffers();
98-
ok = true;
99-
if(add_to_scene)
100-
CGAL::Three::Three::scene()->addItem(item);
101-
return QList<Scene_item*>()<<item;
120+
121+
return new_item_list;
102122
}
103123

104124
bool CGAL_Lab_gocad_plugin::canSave(const CGAL::Three::Scene_item* item)

STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ CGAL_add_named_parameter(face_color_map_t, face_color_map, face_color_map)
6565
CGAL_add_named_parameter(repair_polygon_soup_t, repair_polygon_soup, repair_polygon_soup)
6666
CGAL_add_named_parameter(output_color_t, output_color, output_color)
6767
CGAL_add_named_parameter(stream_precision_t, stream_precision, stream_precision)
68+
CGAL_add_named_parameter(read_only_one_object_t, read_only_one_object, read_only_one_object)
6869

6970
// List of named parameters that we use in the package 'Mesh_3'
7071
CGAL_add_named_parameter(vertex_feature_degree_t, vertex_feature_degree, vertex_feature_degree_map)

Stream_support/include/CGAL/IO/GOCAD.h

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ bool read_GOCAD(std::istream& is,
5353
typedef typename boost::range_value<PolygonRange>::type Poly;
5454

5555
const bool verbose = parameters::choose_parameter(parameters::get_parameter(np, internal_np::verbose), false);
56+
const bool read_only_one_object = parameters::choose_parameter(parameters::get_parameter(np, internal_np::read_only_one_object), false);
57+
5658

5759
if(!is)
5860
{
@@ -63,15 +65,17 @@ bool read_GOCAD(std::istream& is,
6365

6466
set_ascii_mode(is); // GOCAD is ASCII only
6567

66-
int offset = 0;
6768
std::string s;
6869
Point p;
69-
bool vertices_read = false,
70-
end_read = false;
70+
71+
bool vertices_read = false;
72+
std::size_t offset=0;
73+
int l_offset=0;
74+
int nb_gocad=0;
75+
int nb_end=0;
76+
bool end_read=true;
7177

7278
std::string line;
73-
std::size_t nb_gocad=1, //don't read the first one, it is optional anyway.
74-
nb_end=0;
7579
while(std::getline(is, line))
7680
{
7781
if(line.empty())
@@ -81,39 +85,18 @@ bool read_GOCAD(std::istream& is,
8185
if(!(iss >> s))
8286
continue; // can't read anything on the line, whitespace only?
8387

84-
if(s == "TFACE")
85-
{
86-
break;
87-
}
88-
89-
std::string::size_type idx;
90-
if((idx = s.find("name")) != std::string::npos)
88+
if(s == "GOCAD")
9189
{
92-
std::size_t pos = s.find(":")+1;
93-
name_and_color.first = s.substr(pos, s.length());
90+
++nb_gocad;
91+
offset=points.size();
92+
vertices_read = false;
93+
end_read = false;
9494
}
95-
96-
if((idx = s.find("color")) != std::string::npos)
97-
{
98-
std::size_t pos = s.find(":")+1;
99-
name_and_color.second = s.substr(pos, s.length());
100-
}
101-
}
102-
103-
while(std::getline(is, line))
104-
{
105-
if(line.empty())
106-
continue;
107-
108-
std::istringstream iss(line);
109-
if(line.find("GOCAD ") != std::string::npos) //the whitespace matters, it is used to define a gocad type, but not in the coord system keyword, for example.
110-
nb_gocad++;
111-
112-
if((line.find("VRTX") != std::string::npos))
95+
else if(s=="VRTX")
11396
{
11497
int i;
11598
double x, y, z;
116-
if(!(iss >> s >> i >> IO::iformat(x) >> IO::iformat(y) >> IO::iformat(z)))
99+
if(!(iss >> i >> IO::iformat(x) >> IO::iformat(y) >> IO::iformat(z)))
117100
{
118101
if(verbose)
119102
std::cerr << "error while reading vertex." << std::endl;
@@ -123,18 +106,14 @@ bool read_GOCAD(std::istream& is,
123106
if(!vertices_read)
124107
{
125108
vertices_read = true;
126-
offset -= i; // Some files start with index 0 others with 1
109+
l_offset = -i;
127110
}
128111

129112
internal::fill_point(x, y, z, 1., p);
130113
points.push_back(p);
131114
}
132-
else if(line[0] == 'T')
115+
else if(s == "TRGL")
133116
{
134-
iss >> s;
135-
if(s != "TRGL")
136-
continue;
137-
138117
int i,j,k;
139118
if(!(iss >> i >> j >> k))
140119
{
@@ -145,20 +124,40 @@ bool read_GOCAD(std::istream& is,
145124

146125
Poly new_face;
147126
::CGAL::internal::resize(new_face, 3);
148-
new_face[0] = offset + i;
149-
new_face[1] = offset + j;
150-
new_face[2] = offset + k;
127+
new_face[0] = offset + (l_offset + i);
128+
new_face[1] = offset + (l_offset + j);
129+
new_face[2] = offset + (l_offset + k);
151130
polygons.push_back(new_face);
152131
}
153-
else if(line == "END")
132+
else if (s=="END")
154133
{
134+
++nb_end;
155135
end_read=true;
156-
nb_end++;
136+
if (read_only_one_object)
137+
break;
138+
}
139+
else if (s=="HEADER")
140+
{
141+
while(std::getline(is, line))
142+
{
143+
std::string::size_type idx;
144+
if((idx = line.find("name")) != std::string::npos)
145+
{
146+
std::size_t pos = line.find(":")+1;
147+
name_and_color.first = line.substr(pos, line.length());
148+
}
149+
else if((idx = line.find("color")) != std::string::npos)
150+
{
151+
std::size_t pos = line.find(":")+1;
152+
name_and_color.second = line.substr(pos, line.length());
153+
}
154+
else if((idx = line.find("}")) != std::string::npos)
155+
break;
156+
}
157157
}
158158
}
159-
if(is.eof())
160-
is.clear(std::ios::goodbit);
161-
return end_read && nb_gocad == nb_end && !is.bad();
159+
160+
return nb_gocad!=0 && end_read && nb_gocad == nb_end && !is.bad();
162161
}
163162
/// \endcond
164163

@@ -187,6 +186,11 @@ bool read_GOCAD(std::istream& is,
187186
* \cgalParamType{Boolean}
188187
* \cgalParamDefault{`false`}
189188
* \cgalParamNEnd
189+
* \cgalParamNBegin{read_only_one_object}
190+
* \cgalParamDescription{if `true` only one GOCAD object will be read in the stream, and the stream will be left ready for the reading of the next GOCAD object.}
191+
* \cgalParamType{Boolean}
192+
* \cgalParamDefault{`false`}
193+
* \cgalParamNEnd
190194
* \cgalNamedParamsEnd
191195
*
192196
* \returns `true` if the reading was successful, `false` otherwise.
@@ -230,6 +234,11 @@ bool read_GOCAD(std::istream& is,
230234
* \cgalParamType{Boolean}
231235
* \cgalParamDefault{`false`}
232236
* \cgalParamNEnd
237+
* \cgalParamNBegin{read_only_one_object}
238+
* \cgalParamDescription{if `true` only one GOCAD object will be read in the stream, and the stream will be left ready for the reading of the next GOCAD object.}
239+
* \cgalParamType{Boolean}
240+
* \cgalParamDefault{`false`}
241+
* \cgalParamNEnd
233242
* \cgalNamedParamsEnd
234243
*
235244
* \returns `true` if the reading was successful, `false` otherwise.

0 commit comments

Comments
 (0)